diagnostics upgrade
This commit is contained in:
@@ -1486,7 +1486,7 @@ validate_declaration_aliases :: proc(state: ^State) {
|
||||
|
||||
import_id := find_type_import(state.module, alias.file, alias.qualifier)
|
||||
if import_id == ast.INVALID_IMPORT {
|
||||
alias.diagnostic = source.addf(state.diagnostics, alias.span, "unknown package alias '%s'", symbol.resolve(state.symbols, alias.qualifier))
|
||||
alias.diagnostic = source.addf(state.diagnostics, alias.span, "unknown symbol '%s'", symbol.resolve(state.symbols, alias.qualifier))
|
||||
alias.valid = false
|
||||
continue
|
||||
}
|
||||
@@ -1613,6 +1613,81 @@ canonical_type :: proc(
|
||||
return resolved
|
||||
}
|
||||
|
||||
diagnose_qualified_type_uses :: proc(state: ^State) {
|
||||
module := state.module
|
||||
for &type_use in module.type_uses {
|
||||
item, ok := types.node(&module.type_store, type_use.type)
|
||||
if !ok || item.qualifier == 0 || item.kind != .Named {
|
||||
continue
|
||||
}
|
||||
qualifier := symbol.Id(item.qualifier)
|
||||
name := symbol.Id(item.name)
|
||||
import_id := find_type_import(module, type_use.file, qualifier)
|
||||
if import_id == ast.INVALID_IMPORT {
|
||||
type_use.diagnostic = source.addf(
|
||||
state.diagnostics,
|
||||
type_use.span,
|
||||
"unknown symbol '%s'",
|
||||
symbol.resolve(state.symbols, qualifier),
|
||||
)
|
||||
source.set_primary_label(state.diagnostics, type_use.diagnostic, "unknown symbol")
|
||||
continue
|
||||
}
|
||||
import_item := module.imports[import_id]
|
||||
if !import_item.valid || import_item.target == ast.INVALID_PACKAGE ||
|
||||
int(import_item.target) >= len(module.packages) || !module.packages[import_item.target].available {
|
||||
type_use.diagnostic = source.addf(
|
||||
state.diagnostics,
|
||||
type_use.span,
|
||||
"unavailable imported package '%s'",
|
||||
symbol.resolve(state.symbols, qualifier),
|
||||
)
|
||||
continue
|
||||
}
|
||||
if !types.is_valid(types.find_named(&module.type_store, u32(import_item.target), u32(name))) {
|
||||
type_use.diagnostic = source.addf(
|
||||
state.diagnostics,
|
||||
type_use.span,
|
||||
"package '%s' has no member '%s'",
|
||||
symbol.resolve(state.symbols, qualifier),
|
||||
symbol.resolve(state.symbols, name),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type_resolution_diagnostic :: proc(module: ^ast.Module, value: types.Type, file: ast.File_Id, depth := 0) -> source.Diagnostic_Id {
|
||||
if depth > 64 {
|
||||
return source.INVALID_DIAGNOSTIC
|
||||
}
|
||||
for type_use in module.type_uses {
|
||||
if type_use.file == file && type_use.type == value && type_use.diagnostic != source.INVALID_DIAGNOSTIC {
|
||||
return type_use.diagnostic
|
||||
}
|
||||
}
|
||||
item, ok := types.node(&module.type_store, value)
|
||||
if !ok {
|
||||
return source.INVALID_DIAGNOSTIC
|
||||
}
|
||||
if diagnostic := type_resolution_diagnostic(module, item.child, file, depth+1);
|
||||
diagnostic != source.INVALID_DIAGNOSTIC {
|
||||
return diagnostic
|
||||
}
|
||||
if diagnostic := type_resolution_diagnostic(module, item.extra, file, depth+1);
|
||||
diagnostic != source.INVALID_DIAGNOSTIC {
|
||||
return diagnostic
|
||||
}
|
||||
if item.kind == .Function {
|
||||
for param in types.params_for(&module.type_store, value) {
|
||||
if diagnostic := type_resolution_diagnostic(module, param.type, file, depth+1);
|
||||
diagnostic != source.INVALID_DIAGNOSTIC {
|
||||
return diagnostic
|
||||
}
|
||||
}
|
||||
}
|
||||
return source.INVALID_DIAGNOSTIC
|
||||
}
|
||||
|
||||
canonicalize_types :: proc(module: ^ast.Module, allocator: mem.Allocator) {
|
||||
original_count := len(module.type_store.nodes)
|
||||
mapping := make([]types.Type, original_count, allocator)
|
||||
@@ -1620,6 +1695,19 @@ canonicalize_types :: proc(module: ^ast.Module, allocator: mem.Allocator) {
|
||||
defer delete(mapping, allocator)
|
||||
defer delete(visiting, allocator)
|
||||
for &function in module.functions {
|
||||
for param in function.params {
|
||||
if diagnostic := type_resolution_diagnostic(module, param.type, function.file);
|
||||
diagnostic != source.INVALID_DIAGNOSTIC && function.diagnostic == source.INVALID_DIAGNOSTIC {
|
||||
function.diagnostic = diagnostic
|
||||
}
|
||||
}
|
||||
signature_results := [2]types.Type{function.result, function.error}
|
||||
for value in signature_results {
|
||||
if diagnostic := type_resolution_diagnostic(module, value, function.file);
|
||||
diagnostic != source.INVALID_DIAGNOSTIC && function.diagnostic == source.INVALID_DIAGNOSTIC {
|
||||
function.diagnostic = diagnostic
|
||||
}
|
||||
}
|
||||
for ¶m in function.params {
|
||||
param.type = canonical_type(module, param.type, mapping, visiting)
|
||||
}
|
||||
@@ -1627,9 +1715,17 @@ canonicalize_types :: proc(module: ^ast.Module, allocator: mem.Allocator) {
|
||||
function.error = canonical_type(module, function.error, mapping, visiting)
|
||||
}
|
||||
for &global in module.globals {
|
||||
if diagnostic := type_resolution_diagnostic(module, global.type, global.file);
|
||||
diagnostic != source.INVALID_DIAGNOSTIC && global.diagnostic == source.INVALID_DIAGNOSTIC {
|
||||
global.diagnostic = diagnostic
|
||||
}
|
||||
global.type = canonical_type(module, global.type, mapping, visiting)
|
||||
}
|
||||
for &statement in module.statements {
|
||||
if diagnostic := type_resolution_diagnostic(module, statement.type, ast.File_Id(statement.span.file));
|
||||
diagnostic != source.INVALID_DIAGNOSTIC && statement.diagnostic == source.INVALID_DIAGNOSTIC {
|
||||
statement.diagnostic = diagnostic
|
||||
}
|
||||
statement.type = canonical_type(module, statement.type, mapping, visiting)
|
||||
}
|
||||
for &field in module.type_fields {
|
||||
@@ -1687,6 +1783,7 @@ load :: proc(
|
||||
}
|
||||
validate_imports(&state)
|
||||
validate_declaration_aliases(&state)
|
||||
diagnose_qualified_type_uses(&state)
|
||||
canonicalize_types(&module, allocator)
|
||||
return module, !state.root_failed
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user