file-local / package-local decls

This commit is contained in:
2026-08-09 17:01:05 +02:00
parent a7a32894f3
commit 8785912b73
15 changed files with 369 additions and 152 deletions
+66 -30
View File
@@ -139,17 +139,19 @@ Build_Ctx :: struct {
}
Function_Index_Entry :: struct {
scope: ast.Package_Id,
hidden: bool,
name: symbol.Id,
id: ast.Function_Id,
scope: ast.Package_Id,
file: ast.File_Id,
visibility: types.Visibility,
name: symbol.Id,
id: ast.Function_Id,
}
Global_Index_Entry :: struct {
scope: ast.Package_Id,
hidden: bool,
name: symbol.Id,
id: ast.Global_Id,
scope: ast.Package_Id,
file: ast.File_Id,
visibility: types.Visibility,
name: symbol.Id,
id: ast.Global_Id,
}
Import_Index_Entry :: struct {
@@ -1537,12 +1539,17 @@ find_function_symbol :: proc(index: []Function_Index_Entry, scope: ast.Package_I
visible := ast.INVALID_FUNCTION
for low < len(index) && index[low].scope == scope && index[low].name == name {
entry := index[low]
if entry.hidden {
switch entry.visibility {
case .Public:
visible = entry.id
case .Package:
if file != ast.INVALID_FILE {
visible = entry.id
}
case .File:
if entry.file == file {
return entry.id
}
} else {
visible = entry.id
}
low += 1
}
@@ -1564,12 +1571,17 @@ find_global_symbol :: proc(index: []Global_Index_Entry, scope: ast.Package_Id, n
visible := ast.INVALID_GLOBAL
for low < len(index) && index[low].scope == scope && index[low].name == name {
entry := index[low]
if entry.hidden {
switch entry.visibility {
case .Public:
visible = entry.id
case .Package:
if file != ast.INVALID_FILE {
visible = entry.id
}
case .File:
if entry.file == file {
return entry.id
}
} else {
visible = entry.id
}
low += 1
}
@@ -1612,12 +1624,12 @@ build_symbol_indexes :: proc(checker: ^Checker) {
if function.generated {
continue
}
checker.function_index[function_index] = Function_Index_Entry{scope=function.pkg, hidden=function.package_hidden, name=function.name, id=ast.function_id(id)}
checker.function_index[function_index] = Function_Index_Entry{scope=function.pkg, file=function.file, visibility=function.visibility, name=function.name, id=ast.function_id(id)}
function_index += 1
}
for alias in checker.ast_module.aliases {
if alias.valid && alias.kind == .Function {
checker.function_index[function_index] = Function_Index_Entry{scope=alias.pkg, hidden=alias.package_hidden, name=alias.name, id=ast.Function_Id(alias.target)}
checker.function_index[function_index] = Function_Index_Entry{scope=alias.pkg, file=alias.file, visibility=alias.visibility, name=alias.name, id=ast.Function_Id(alias.target)}
function_index += 1
}
}
@@ -1631,12 +1643,12 @@ build_symbol_indexes :: proc(checker: ^Checker) {
}
checker.global_index = make([]Global_Index_Entry, global_count, checker.allocator)
for global, id in checker.ast_module.globals {
checker.global_index[id] = Global_Index_Entry{scope=global.pkg, hidden=global.package_hidden, name=global.name, id=ast.global_id(id)}
checker.global_index[id] = Global_Index_Entry{scope=global.pkg, file=global.file, visibility=global.visibility, name=global.name, id=ast.global_id(id)}
}
global_index := len(checker.ast_module.globals)
for alias in checker.ast_module.aliases {
if alias.valid && alias.kind == .Global {
checker.global_index[global_index] = Global_Index_Entry{scope=alias.pkg, hidden=alias.package_hidden, name=alias.name, id=ast.Global_Id(alias.target)}
checker.global_index[global_index] = Global_Index_Entry{scope=alias.pkg, file=alias.file, visibility=alias.visibility, name=alias.name, id=ast.Global_Id(alias.target)}
global_index += 1
}
}
@@ -1737,7 +1749,7 @@ configure_entry_point :: proc(checker: ^Checker) {
type_from_syntax(checker, function.result, function.pkg, function.file),
&checker.module.types,
)
if function.package_hidden && function.has_body && !function.c_abi && !function.infer_error &&
if function.visibility == .Package && function.has_body && !function.c_abi && !function.infer_error &&
len(function.params) == 0 && !types.is_valid(function.error) && types.equal(result, io_type) {
provider = ast.function_id(function_id)
}
@@ -1774,9 +1786,25 @@ declared_type_named :: proc(checker: ^Checker, pkg: ast.Package_Id, name: symbol
}
type_declaration_conflicts :: proc(checker: ^Checker, pkg: ast.Package_Id, name: symbol.Id) -> bool {
declaration_scopes_overlap :: proc(
left_visibility: types.Visibility,
left_file: ast.File_Id,
right_visibility: types.Visibility,
right_file: ast.File_Id,
) -> bool {
return left_visibility != .File || right_visibility != .File || left_file == right_file
}
type_declaration_conflicts :: proc(
checker: ^Checker,
pkg: ast.Package_Id,
name: symbol.Id,
visibility: types.Visibility,
file: ast.File_Id,
) -> bool {
for item in checker.module.types.nodes {
if item.declared && item.pkg == u32(pkg) && item.name == u32(name) {
if item.declared && item.pkg == u32(pkg) && item.name == u32(name) &&
declaration_scopes_overlap(visibility, file, item.visibility, ast.File_Id(item.file)) {
return true
}
}
@@ -3996,11 +4024,11 @@ validate_declarations :: proc(checker: ^Checker) {
function.span,
"inferred error channels are not allowed on 'c_func'",
)
} else if !function.package_hidden && !root_main {
} else if function.visibility == .Public && !root_main {
checker.template_diagnostics[function_id] = source.add(
checker.diagnostics,
function.span,
"inferred error channels are only allowed on hidden functions and root main",
"inferred error channels are only allowed on local functions and root main",
)
}
}
@@ -13971,8 +13999,13 @@ build_function :: proc(checker: ^Checker, id: Spec_Id) {
symbol_text(checker, function.name),
)
}
checker.specs[id].result = types.I64
spec.result = types.I64
recovery_result := types.fallible_success(spec.result, &checker.module.types) if function.infer_error else types.INVALID
if !types.is_void(recovery_result) && !types.is_noreturn(recovery_result) &&
!is_runtime_type(checker, recovery_result) {
recovery_result = types.I64
}
checker.specs[id].result = recovery_result
spec.result = recovery_result
}
for arg in spec.args {
if !is_runtime_type(checker, arg) {
@@ -14810,26 +14843,29 @@ check :: proc(
continue
}
for previous in ast_module.functions[:index] {
if !previous.generated && previous.pkg == function.pkg && previous.name == function.name {
if !previous.generated && previous.pkg == function.pkg && previous.name == function.name &&
declaration_scopes_overlap(previous.visibility, previous.file, function.visibility, function.file) {
source.addf(diagnostics, function.span, "duplicate function '%s'", symbol_text(&checker, function.name))
}
}
for global in ast_module.globals {
if global.pkg == function.pkg && global.name == function.name {
if global.pkg == function.pkg && global.name == function.name &&
declaration_scopes_overlap(global.visibility, global.file, function.visibility, function.file) {
source.addf(diagnostics, function.span, "package declaration '%s' conflicts with a global", symbol_text(&checker, function.name))
}
}
if type_declaration_conflicts(&checker, function.pkg, function.name) {
if type_declaration_conflicts(&checker, function.pkg, function.name, function.visibility, function.file) {
source.addf(diagnostics, function.span, "function '%s' shadows visible type", symbol_text(&checker, function.name))
}
}
for global, index in ast_module.globals {
for previous in ast_module.globals[:index] {
if previous.pkg == global.pkg && previous.name == global.name {
if previous.pkg == global.pkg && previous.name == global.name &&
declaration_scopes_overlap(previous.visibility, previous.file, global.visibility, global.file) {
source.addf(diagnostics, global.span, "duplicate global '%s'", symbol_text(&checker, global.name))
}
}
if type_declaration_conflicts(&checker, global.pkg, global.name) {
if type_declaration_conflicts(&checker, global.pkg, global.name, global.visibility, global.file) {
source.addf(diagnostics, global.span, "global '%s' shadows visible type", symbol_text(&checker, global.name))
}
}