package-private visibility
This commit is contained in:
+1
-1
@@ -15,7 +15,7 @@ roadmap and milestone history.
|
|||||||
- file-local relative imports, import aliases, and qualified member access
|
- file-local relative imports, import aliases, and qualified member access
|
||||||
- transparent declaration aliases with `Name :: alias package.Member`; functions/type factories,
|
- transparent declaration aliases with `Name :: alias package.Member`; functions/type factories,
|
||||||
named types, and globals retain their original declaration or storage identity
|
named types, and globals retain their original declaration or storage identity
|
||||||
- `hide` makes any named top-level declaration file-local; declarations are public by default,
|
- `hide` makes any named top-level declaration package-local; declarations are public by default,
|
||||||
leading underscores are ordinary identifier characters, and imports are always file-local
|
leading underscores are ordinary identifier characters, and imports are always file-local
|
||||||
- relative `.h` imports as synthetic C header package namespaces
|
- relative `.h` imports as synthetic C header package namespaces
|
||||||
- native `name test { ... }` declarations with fallible-void results inferred from `testing.Error`
|
- native `name test { ... }` declarations with fallible-void results inferred from `testing.Error`
|
||||||
|
|||||||
@@ -207,8 +207,9 @@ value :: math.sum(other_math.value, 1)
|
|||||||
```
|
```
|
||||||
|
|
||||||
Top-level declarations are public by default. Prefix a declaration with `hide`
|
Top-level declarations are public by default. Prefix a declaration with `hide`
|
||||||
to keep it local to its source file; leading underscores have no visibility
|
to keep it local to its package; sibling files can use it, but importing packages
|
||||||
meaning. Imports are always file-local and cannot be hidden or re-exported:
|
cannot. Leading underscores have no visibility meaning. Imports are always file-local
|
||||||
|
and cannot be hidden or re-exported:
|
||||||
|
|
||||||
```bro
|
```bro
|
||||||
hide helper func() i32 { return 42 }
|
hide helper func() i32 { return 42 }
|
||||||
|
|||||||
@@ -842,13 +842,13 @@
|
|||||||
- this keeps package lookup shallow and deterministic and avoids overloading import aliases with
|
- this keeps package lookup shallow and deterministic and avoids overloading import aliases with
|
||||||
declaration visibility
|
declaration visibility
|
||||||
|
|
||||||
36.5. explicit `hide` file-local declarations (implemented)
|
36.5. explicit `hide` package-local declarations (implemented)
|
||||||
- `hide name ...` gives any named top-level function, global, native/C record, union, enum,
|
- `hide name ...` gives any named top-level function, global, native/C record, union, enum,
|
||||||
opaque/distinct type, or declaration/type alias the existing file-local semantics
|
opaque/distinct type, or declaration/type alias package-local visibility across sibling files
|
||||||
- declarations remain public by default; a leading underscore is an ordinary identifier and `_`
|
- declarations remain public by default; a leading underscore is an ordinary identifier and `_`
|
||||||
remains the write-only sink
|
remains the write-only sink
|
||||||
- hidden native and C declarations with the same name may coexist in separate files, while public
|
- hidden declarations occupy the package namespace, collide with sibling declarations of the
|
||||||
collisions are still diagnosed
|
same name, and remain absent from imported package namespaces
|
||||||
- `hide` is reserved for named top-level declarations and is rejected on imports, locals,
|
- `hide` is reserved for named top-level declarations and is rejected on imports, locals,
|
||||||
parameters, fields, and anonymous declarations
|
parameters, fields, and anonymous declarations
|
||||||
|
|
||||||
|
|||||||
@@ -243,7 +243,7 @@ Function :: struct {
|
|||||||
generated: bool,
|
generated: bool,
|
||||||
analysis_root: bool,
|
analysis_root: bool,
|
||||||
test: bool,
|
test: bool,
|
||||||
file_hidden: bool,
|
package_hidden: bool,
|
||||||
has_body: bool,
|
has_body: bool,
|
||||||
variadic: bool,
|
variadic: bool,
|
||||||
params: []Param,
|
params: []Param,
|
||||||
@@ -265,7 +265,7 @@ Global :: struct {
|
|||||||
immutable: bool,
|
immutable: bool,
|
||||||
external: bool,
|
external: bool,
|
||||||
writable: bool,
|
writable: bool,
|
||||||
file_hidden: bool,
|
package_hidden: bool,
|
||||||
expr: Expr_Id,
|
expr: Expr_Id,
|
||||||
diagnostic: source.Diagnostic_Id,
|
diagnostic: source.Diagnostic_Id,
|
||||||
}
|
}
|
||||||
@@ -313,7 +313,7 @@ Declaration_Alias :: struct {
|
|||||||
target_pkg: Package_Id,
|
target_pkg: Package_Id,
|
||||||
target: u32,
|
target: u32,
|
||||||
kind: Declaration_Alias_Kind,
|
kind: Declaration_Alias_Kind,
|
||||||
file_hidden: bool,
|
package_hidden: bool,
|
||||||
valid: bool,
|
valid: bool,
|
||||||
diagnostic: source.Diagnostic_Id,
|
diagnostic: source.Diagnostic_Id,
|
||||||
}
|
}
|
||||||
|
|||||||
+129
-54
@@ -139,7 +139,6 @@ Build_Ctx :: struct {
|
|||||||
|
|
||||||
Function_Index_Entry :: struct {
|
Function_Index_Entry :: struct {
|
||||||
scope: ast.Package_Id,
|
scope: ast.Package_Id,
|
||||||
file: ast.File_Id,
|
|
||||||
hidden: bool,
|
hidden: bool,
|
||||||
name: symbol.Id,
|
name: symbol.Id,
|
||||||
id: ast.Function_Id,
|
id: ast.Function_Id,
|
||||||
@@ -147,7 +146,6 @@ Function_Index_Entry :: struct {
|
|||||||
|
|
||||||
Global_Index_Entry :: struct {
|
Global_Index_Entry :: struct {
|
||||||
scope: ast.Package_Id,
|
scope: ast.Package_Id,
|
||||||
file: ast.File_Id,
|
|
||||||
hidden: bool,
|
hidden: bool,
|
||||||
name: symbol.Id,
|
name: symbol.Id,
|
||||||
id: ast.Global_Id,
|
id: ast.Global_Id,
|
||||||
@@ -1508,7 +1506,7 @@ find_function_symbol :: proc(index: []Function_Index_Entry, scope: ast.Package_I
|
|||||||
for low < len(index) && index[low].scope == scope && index[low].name == name {
|
for low < len(index) && index[low].scope == scope && index[low].name == name {
|
||||||
entry := index[low]
|
entry := index[low]
|
||||||
if entry.hidden {
|
if entry.hidden {
|
||||||
if entry.file == file {
|
if file != ast.INVALID_FILE {
|
||||||
return entry.id
|
return entry.id
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1535,7 +1533,7 @@ find_global_symbol :: proc(index: []Global_Index_Entry, scope: ast.Package_Id, n
|
|||||||
for low < len(index) && index[low].scope == scope && index[low].name == name {
|
for low < len(index) && index[low].scope == scope && index[low].name == name {
|
||||||
entry := index[low]
|
entry := index[low]
|
||||||
if entry.hidden {
|
if entry.hidden {
|
||||||
if entry.file == file {
|
if file != ast.INVALID_FILE {
|
||||||
return entry.id
|
return entry.id
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1582,12 +1580,12 @@ build_symbol_indexes :: proc(checker: ^Checker) {
|
|||||||
if function.generated {
|
if function.generated {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
checker.function_index[function_index] = Function_Index_Entry{scope=function.pkg, file=function.file, hidden=function.file_hidden, name=function.name, id=ast.function_id(id)}
|
checker.function_index[function_index] = Function_Index_Entry{scope=function.pkg, hidden=function.package_hidden, name=function.name, id=ast.function_id(id)}
|
||||||
function_index += 1
|
function_index += 1
|
||||||
}
|
}
|
||||||
for alias in checker.ast_module.aliases {
|
for alias in checker.ast_module.aliases {
|
||||||
if alias.valid && alias.kind == .Function {
|
if alias.valid && alias.kind == .Function {
|
||||||
checker.function_index[function_index] = Function_Index_Entry{scope=alias.pkg, file=alias.file, hidden=alias.file_hidden, name=alias.name, id=ast.Function_Id(alias.target)}
|
checker.function_index[function_index] = Function_Index_Entry{scope=alias.pkg, hidden=alias.package_hidden, name=alias.name, id=ast.Function_Id(alias.target)}
|
||||||
function_index += 1
|
function_index += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1601,12 +1599,12 @@ build_symbol_indexes :: proc(checker: ^Checker) {
|
|||||||
}
|
}
|
||||||
checker.global_index = make([]Global_Index_Entry, global_count, checker.allocator)
|
checker.global_index = make([]Global_Index_Entry, global_count, checker.allocator)
|
||||||
for global, id in checker.ast_module.globals {
|
for global, id in checker.ast_module.globals {
|
||||||
checker.global_index[id] = Global_Index_Entry{scope=global.pkg, file=global.file, hidden=global.file_hidden, name=global.name, id=ast.global_id(id)}
|
checker.global_index[id] = Global_Index_Entry{scope=global.pkg, hidden=global.package_hidden, name=global.name, id=ast.global_id(id)}
|
||||||
}
|
}
|
||||||
global_index := len(checker.ast_module.globals)
|
global_index := len(checker.ast_module.globals)
|
||||||
for alias in checker.ast_module.aliases {
|
for alias in checker.ast_module.aliases {
|
||||||
if alias.valid && alias.kind == .Global {
|
if alias.valid && alias.kind == .Global {
|
||||||
checker.global_index[global_index] = Global_Index_Entry{scope=alias.pkg, file=alias.file, hidden=alias.file_hidden, name=alias.name, id=ast.Global_Id(alias.target)}
|
checker.global_index[global_index] = Global_Index_Entry{scope=alias.pkg, hidden=alias.package_hidden, name=alias.name, id=ast.Global_Id(alias.target)}
|
||||||
global_index += 1
|
global_index += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1707,7 +1705,7 @@ configure_entry_point :: proc(checker: ^Checker) {
|
|||||||
type_from_syntax(checker, function.result, function.pkg, function.file),
|
type_from_syntax(checker, function.result, function.pkg, function.file),
|
||||||
&checker.module.types,
|
&checker.module.types,
|
||||||
)
|
)
|
||||||
if function.file_hidden && function.has_body && !function.c_abi && len(function.params) == 0 &&
|
if function.package_hidden && function.has_body && !function.c_abi && len(function.params) == 0 &&
|
||||||
!types.is_valid(function.error) && types.equal(result, io_type) {
|
!types.is_valid(function.error) && types.equal(result, io_type) {
|
||||||
provider = ast.function_id(function_id)
|
provider = ast.function_id(function_id)
|
||||||
}
|
}
|
||||||
@@ -1743,14 +1741,10 @@ declared_type_named :: proc(checker: ^Checker, pkg: ast.Package_Id, name: symbol
|
|||||||
return ok && item.declared
|
return ok && item.declared
|
||||||
}
|
}
|
||||||
|
|
||||||
declarations_conflict :: proc(left_file: ast.File_Id, left_hidden: bool, right_file: ast.File_Id, right_hidden: bool) -> bool {
|
|
||||||
return left_file == right_file if left_hidden && right_hidden else true
|
|
||||||
}
|
|
||||||
|
|
||||||
type_declaration_conflicts :: proc(checker: ^Checker, pkg: ast.Package_Id, name: symbol.Id, file: ast.File_Id, hidden: bool) -> bool {
|
type_declaration_conflicts :: proc(checker: ^Checker, pkg: ast.Package_Id, name: symbol.Id) -> bool {
|
||||||
for item in checker.module.types.nodes {
|
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) {
|
||||||
declarations_conflict(file, hidden, ast.File_Id(item.file), item.file_hidden) {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2386,6 +2380,28 @@ call_argument_mapping :: proc(
|
|||||||
return selected, .Explicit if identity else .Inferred, comptime_param_count(function^), ""
|
return selected, .Explicit if identity else .Inferred, comptime_param_count(function^), ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inferred_comptime_value_equal :: proc(checker: ^Checker, left, right: Comptime_Value) -> bool {
|
||||||
|
if left.kind != right.kind {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if left.kind == .Type {
|
||||||
|
return types.equal(
|
||||||
|
types.resolve_alias(left.type, &checker.module.types),
|
||||||
|
types.resolve_alias(right.type, &checker.module.types),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if !types.equal(left.type, right.type) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if left.kind == .Static {
|
||||||
|
return left.fingerprint == right.fingerprint && left.key == right.key
|
||||||
|
}
|
||||||
|
if left.kind == .String {
|
||||||
|
return left.text == right.text
|
||||||
|
}
|
||||||
|
return left.value == right.value
|
||||||
|
}
|
||||||
|
|
||||||
bind_inferred_comptime :: proc(
|
bind_inferred_comptime :: proc(
|
||||||
checker: ^Checker,
|
checker: ^Checker,
|
||||||
function: ast.Function,
|
function: ast.Function,
|
||||||
@@ -2409,16 +2425,7 @@ bind_inferred_comptime :: proc(
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
existing := values[index]
|
existing := values[index]
|
||||||
matches := existing.kind == value.kind
|
matches := inferred_comptime_value_equal(checker, existing, value)
|
||||||
if matches {
|
|
||||||
if existing.kind == .Type {
|
|
||||||
matches = types.equal(types.resolve_alias(existing.type, &checker.module.types), types.resolve_alias(value.type, &checker.module.types))
|
|
||||||
} else if existing.kind == .Static {
|
|
||||||
matches = existing.fingerprint == value.fingerprint && existing.key == value.key && types.equal(existing.type, value.type)
|
|
||||||
} else {
|
|
||||||
matches = existing.value == value.value && types.equal(existing.type, value.type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !matches && diagnose {
|
if !matches && diagnose {
|
||||||
left := type_label(checker, existing.type) if existing.kind == .Type else fmt.aprintf("<comptime value>", allocator=checker.allocator) if existing.kind == .Static else fmt.aprintf("%d", existing.value, allocator=checker.allocator)
|
left := type_label(checker, existing.type) if existing.kind == .Type else fmt.aprintf("<comptime value>", allocator=checker.allocator) if existing.kind == .Static else fmt.aprintf("%d", existing.value, allocator=checker.allocator)
|
||||||
right := type_label(checker, value.type) if value.kind == .Type else fmt.aprintf("<comptime value>", allocator=checker.allocator) if value.kind == .Static else fmt.aprintf("%d", value.value, allocator=checker.allocator)
|
right := type_label(checker, value.type) if value.kind == .Type else fmt.aprintf("<comptime value>", allocator=checker.allocator) if value.kind == .Static else fmt.aprintf("%d", value.value, allocator=checker.allocator)
|
||||||
@@ -2514,6 +2521,33 @@ type_pattern_mentions_comptime :: proc(
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type_pattern_contains_type_call :: proc(checker: ^Checker, pattern: types.Type, depth := 0) -> bool {
|
||||||
|
if depth > 64 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
item, ok := types.node(&checker.module.types, pattern)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if item.kind == .Type_Call {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if types.is_valid(item.child) && type_pattern_contains_type_call(checker, item.child, depth+1) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if types.is_valid(item.extra) && type_pattern_contains_type_call(checker, item.extra, depth+1) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if item.kind == .Function {
|
||||||
|
for field in types.params_for(&checker.module.types, pattern) {
|
||||||
|
if type_pattern_contains_type_call(checker, field.type, depth+1) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
match_inferred_type_pattern :: proc(
|
match_inferred_type_pattern :: proc(
|
||||||
checker: ^Checker,
|
checker: ^Checker,
|
||||||
function: ast.Function,
|
function: ast.Function,
|
||||||
@@ -2563,22 +2597,52 @@ match_inferred_type_pattern :: proc(
|
|||||||
template := find_template(checker, expr.name, target_pkg, expr_lookup_file(expr, function.file))
|
template := find_template(checker, expr.name, target_pkg, expr_lookup_file(expr, function.file))
|
||||||
origin: Type_Factory_Origin
|
origin: Type_Factory_Origin
|
||||||
found := false
|
found := false
|
||||||
|
ambiguous := false
|
||||||
for candidate in checker.type_factory_origins {
|
for candidate in checker.type_factory_origins {
|
||||||
if candidate.template == template && types.equal(candidate.result, actual_type) {
|
if candidate.template != template || !types.equal(candidate.result, actual_type) ||
|
||||||
origin = candidate
|
len(expr.args) != len(candidate.values) {
|
||||||
found = true
|
continue
|
||||||
|
}
|
||||||
|
compatible := true
|
||||||
|
for arg_id, index in expr.args {
|
||||||
|
if arg_id == ast.INVALID_EXPR || int(arg_id) >= len(checker.ast_module.exprs) {
|
||||||
|
compatible = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
arg := checker.ast_module.exprs[arg_id]
|
||||||
|
if arg.kind == .Name && !symbol.is_valid(arg.qualifier) {
|
||||||
|
if binding_index, is_binding := comptime_binding_index(function, prefix, arg.name);
|
||||||
|
is_binding && bound[binding_index] &&
|
||||||
|
!inferred_comptime_value_equal(checker, values[binding_index], candidate.values[index]) {
|
||||||
|
compatible = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found || len(expr.args) != len(origin.values) {
|
}
|
||||||
|
if !compatible {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
origin = candidate
|
||||||
|
found = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for arg_id, index in expr.args {
|
||||||
|
arg := checker.ast_module.exprs[arg_id]
|
||||||
|
if arg.kind == .Name && !symbol.is_valid(arg.qualifier) {
|
||||||
|
if _, is_binding := comptime_binding_index(function, prefix, arg.name);
|
||||||
|
is_binding && !inferred_comptime_value_equal(checker, origin.values[index], candidate.values[index]) {
|
||||||
|
ambiguous = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found || ambiguous {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
matched := true
|
matched := true
|
||||||
for arg_id, index in expr.args {
|
for arg_id, index in expr.args {
|
||||||
if arg_id == ast.INVALID_EXPR || int(arg_id) >= len(checker.ast_module.exprs) {
|
|
||||||
matched = false
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
arg := checker.ast_module.exprs[arg_id]
|
arg := checker.ast_module.exprs[arg_id]
|
||||||
if arg.kind == .Name && !symbol.is_valid(arg.qualifier) {
|
if arg.kind == .Name && !symbol.is_valid(arg.qualifier) {
|
||||||
if _, is_binding := comptime_binding_index(function, prefix, arg.name); is_binding {
|
if _, is_binding := comptime_binding_index(function, prefix, arg.name); is_binding {
|
||||||
@@ -2893,11 +2957,21 @@ infer_call_comptime_values :: proc(
|
|||||||
for value_bound in bound {
|
for value_bound in bound {
|
||||||
all_bound = all_bound && value_bound
|
all_bound = all_bound && value_bound
|
||||||
}
|
}
|
||||||
// Concrete arguments bind first. Numeric constants, string literals, and `null`
|
// Factory provenance is authoritative when unique, so try it before direct
|
||||||
// are contextual and therefore only contribute after stronger evidence has had a
|
// arguments. Strong and then weak direct evidence can disambiguate a factory
|
||||||
// chance to bind the parameter type.
|
// result; retry factory patterns once after both evidence passes.
|
||||||
weak_passes := [2]bool{false, true}
|
Evidence_Pass :: struct {
|
||||||
for weak in weak_passes {
|
type_call: bool,
|
||||||
|
weak: bool,
|
||||||
|
final: bool,
|
||||||
|
}
|
||||||
|
evidence_passes := [?]Evidence_Pass{
|
||||||
|
{type_call=true},
|
||||||
|
{final=true},
|
||||||
|
{weak=true, final=true},
|
||||||
|
{type_call=true, final=true},
|
||||||
|
}
|
||||||
|
for pass in evidence_passes {
|
||||||
for arg_id, source_index in args {
|
for arg_id, source_index in args {
|
||||||
param_index := call_param_index(mapping, source_index)
|
param_index := call_param_index(mapping, source_index)
|
||||||
if param_index >= len(function.params) || param_index >= len(actual_args) {
|
if param_index >= len(function.params) || param_index >= len(actual_args) {
|
||||||
@@ -2910,7 +2984,11 @@ infer_call_comptime_values :: proc(
|
|||||||
is_null := arg_expr.kind == .Null
|
is_null := arg_expr.kind == .Null
|
||||||
is_weak := is_numeric_constant_expr(checker, arg_id) ||
|
is_weak := is_numeric_constant_expr(checker, arg_id) ||
|
||||||
arg_expr.kind == .String || is_null
|
arg_expr.kind == .String || is_null
|
||||||
if is_weak != weak {
|
contains_type_call := type_pattern_contains_type_call(
|
||||||
|
checker, function.params[param_index].type,
|
||||||
|
)
|
||||||
|
if contains_type_call != pass.type_call ||
|
||||||
|
!pass.type_call && is_weak != pass.weak {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !type_pattern_mentions_comptime(checker, function, prefix, function.params[param_index].type) {
|
if !type_pattern_mentions_comptime(checker, function, prefix, function.params[param_index].type) {
|
||||||
@@ -2923,7 +3001,7 @@ infer_call_comptime_values :: proc(
|
|||||||
if all_bound && arg_expr.kind == .Struct_Literal && !arg_expr.tuple && !symbol.is_valid(arg_expr.name) {
|
if all_bound && arg_expr.kind == .Struct_Literal && !arg_expr.tuple && !symbol.is_valid(arg_expr.name) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if weak {
|
if pass.weak {
|
||||||
if item, ok := types.node(&checker.module.types, function.params[param_index].type); ok &&
|
if item, ok := types.node(&checker.module.types, function.params[param_index].type); ok &&
|
||||||
item.qualifier == 0 && item.name != 0 {
|
item.qualifier == 0 && item.name != 0 {
|
||||||
if binding_index, is_binding := comptime_binding_index(function, prefix, symbol.Id(item.name));
|
if binding_index, is_binding := comptime_binding_index(function, prefix, symbol.Id(item.name));
|
||||||
@@ -2945,11 +3023,14 @@ infer_call_comptime_values :: proc(
|
|||||||
actual_args[param_index] = contextual
|
actual_args[param_index] = contextual
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
matched = match_inferred_type_pattern(
|
pass_matched := match_inferred_type_pattern(
|
||||||
checker, function, prefix, function.params[param_index].type,
|
checker, function, prefix, function.params[param_index].type,
|
||||||
actual, values, bound,
|
actual, values, bound,
|
||||||
checker.ast_module.exprs[arg_id].span, diagnose,
|
checker.ast_module.exprs[arg_id].span, diagnose && pass.final,
|
||||||
) && matched
|
)
|
||||||
|
if pass.final {
|
||||||
|
matched = pass_matched && matched
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ordinal = 0
|
ordinal = 0
|
||||||
@@ -10063,9 +10144,6 @@ make_link_name :: proc(checker: ^Checker, id: Spec_Id) -> string {
|
|||||||
defer strings.builder_destroy(&builder)
|
defer strings.builder_destroy(&builder)
|
||||||
strings.write_string(&builder, "bro_c__" if function.c_abi else "bro__")
|
strings.write_string(&builder, "bro_c__" if function.c_abi else "bro__")
|
||||||
fmt.sbprintf(&builder, "p%d__", function.pkg)
|
fmt.sbprintf(&builder, "p%d__", function.pkg)
|
||||||
if function.file_hidden {
|
|
||||||
fmt.sbprintf(&builder, "f%d__", function.file)
|
|
||||||
}
|
|
||||||
strings.write_string(&builder, symbol_text(checker, function.name))
|
strings.write_string(&builder, symbol_text(checker, function.name))
|
||||||
for arg in spec.args {
|
for arg in spec.args {
|
||||||
strings.write_string(&builder, "__")
|
strings.write_string(&builder, "__")
|
||||||
@@ -14381,29 +14459,26 @@ check :: proc(
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for previous in ast_module.functions[:index] {
|
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 {
|
||||||
declarations_conflict(function.file, function.file_hidden, previous.file, previous.file_hidden) {
|
|
||||||
source.addf(diagnostics, function.span, "duplicate function '%s'", symbol_text(&checker, function.name))
|
source.addf(diagnostics, function.span, "duplicate function '%s'", symbol_text(&checker, function.name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for global in ast_module.globals {
|
for global in ast_module.globals {
|
||||||
if global.pkg == function.pkg && global.name == function.name &&
|
if global.pkg == function.pkg && global.name == function.name {
|
||||||
declarations_conflict(function.file, function.file_hidden, global.file, global.file_hidden) {
|
|
||||||
source.addf(diagnostics, function.span, "package declaration '%s' conflicts with a global", symbol_text(&checker, function.name))
|
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, function.file, function.file_hidden) {
|
if type_declaration_conflicts(&checker, function.pkg, function.name) {
|
||||||
source.addf(diagnostics, function.span, "function '%s' shadows visible type", symbol_text(&checker, function.name))
|
source.addf(diagnostics, function.span, "function '%s' shadows visible type", symbol_text(&checker, function.name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for global, index in ast_module.globals {
|
for global, index in ast_module.globals {
|
||||||
for previous in ast_module.globals[:index] {
|
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 {
|
||||||
declarations_conflict(global.file, global.file_hidden, previous.file, previous.file_hidden) {
|
|
||||||
source.addf(diagnostics, global.span, "duplicate global '%s'", symbol_text(&checker, global.name))
|
source.addf(diagnostics, global.span, "duplicate global '%s'", symbol_text(&checker, global.name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if type_declaration_conflicts(&checker, global.pkg, global.name, global.file, global.file_hidden) {
|
if type_declaration_conflicts(&checker, global.pkg, global.name) {
|
||||||
source.addf(diagnostics, global.span, "global '%s' shadows visible type", symbol_text(&checker, global.name))
|
source.addf(diagnostics, global.span, "global '%s' shadows visible type", symbol_text(&checker, global.name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-25
@@ -1251,12 +1251,12 @@ load_package :: proc(
|
|||||||
|
|
||||||
declaration_conflicts :: proc(module: ^ast.Module, pkg: ast.Package_Id, file: ast.File_Id, name: symbol.Id) -> bool {
|
declaration_conflicts :: proc(module: ^ast.Module, pkg: ast.Package_Id, file: ast.File_Id, name: symbol.Id) -> bool {
|
||||||
for function in module.functions {
|
for function in module.functions {
|
||||||
if function.pkg == pkg && function.name == name && (!function.file_hidden || function.file == file) {
|
if function.pkg == pkg && function.name == name {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for global in module.globals {
|
for global in module.globals {
|
||||||
if global.pkg == pkg && global.name == name && (!global.file_hidden || global.file == file) {
|
if global.pkg == pkg && global.name == name {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1327,8 +1327,7 @@ find_visible_enum_global :: proc(
|
|||||||
public_only := false,
|
public_only := false,
|
||||||
) -> ast.Global_Id {
|
) -> ast.Global_Id {
|
||||||
for global, index in module.globals {
|
for global, index in module.globals {
|
||||||
if global.pkg == pkg && global.name == name &&
|
if global.pkg == pkg && global.name == name && (!global.package_hidden || !public_only) {
|
||||||
(!global.file_hidden || !public_only && global.file == file) {
|
|
||||||
return ast.global_id(index)
|
return ast.global_id(index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1449,26 +1448,20 @@ resolve_enum_values :: proc(state: ^State) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
alias_declarations_conflict :: proc(left_file: ast.File_Id, left_hidden: bool, right_file: ast.File_Id, right_hidden: bool) -> bool {
|
|
||||||
return left_file == right_file if left_hidden && right_hidden else true
|
|
||||||
}
|
|
||||||
|
|
||||||
alias_conflicts_with_declaration :: proc(module: ^ast.Module, alias: ast.Declaration_Alias) -> bool {
|
alias_conflicts_with_declaration :: proc(module: ^ast.Module, alias: ast.Declaration_Alias) -> bool {
|
||||||
for function in module.functions {
|
for function in module.functions {
|
||||||
if function.pkg == alias.pkg && function.name == alias.name &&
|
if function.pkg == alias.pkg && function.name == alias.name {
|
||||||
alias_declarations_conflict(alias.file, alias.file_hidden, function.file, function.file_hidden) {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for global in module.globals {
|
for global in module.globals {
|
||||||
if global.pkg == alias.pkg && global.name == alias.name &&
|
if global.pkg == alias.pkg && global.name == alias.name {
|
||||||
alias_declarations_conflict(alias.file, alias.file_hidden, global.file, global.file_hidden) {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for item in module.type_store.nodes {
|
for item in module.type_store.nodes {
|
||||||
if item.declared && item.pkg == u32(alias.pkg) && item.name == u32(alias.name) &&
|
if item.declared && item.pkg == u32(alias.pkg) && item.name == u32(alias.name) {
|
||||||
alias_declarations_conflict(alias.file, alias.file_hidden, ast.File_Id(item.file), item.file_hidden) {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1480,7 +1473,7 @@ direct_alias_target :: proc(module: ^ast.Module, pkg: ast.Package_Id, name: symb
|
|||||||
target: u32
|
target: u32
|
||||||
kinds := 0
|
kinds := 0
|
||||||
for function, index in module.functions {
|
for function, index in module.functions {
|
||||||
if function.pkg == pkg && function.name == name && !function.generated && !function.file_hidden {
|
if function.pkg == pkg && function.name == name && !function.generated && !function.package_hidden {
|
||||||
kind = .Function
|
kind = .Function
|
||||||
target = u32(ast.function_id(index))
|
target = u32(ast.function_id(index))
|
||||||
kinds += 1
|
kinds += 1
|
||||||
@@ -1488,7 +1481,7 @@ direct_alias_target :: proc(module: ^ast.Module, pkg: ast.Package_Id, name: symb
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for global, index in module.globals {
|
for global, index in module.globals {
|
||||||
if global.pkg == pkg && global.name == name && !global.file_hidden {
|
if global.pkg == pkg && global.name == name && !global.package_hidden {
|
||||||
kind = .Global
|
kind = .Global
|
||||||
target = u32(ast.global_id(index))
|
target = u32(ast.global_id(index))
|
||||||
kinds += 1
|
kinds += 1
|
||||||
@@ -1507,22 +1500,22 @@ direct_alias_target :: proc(module: ^ast.Module, pkg: ast.Package_Id, name: symb
|
|||||||
|
|
||||||
hidden_alias_target_exists :: proc(module: ^ast.Module, pkg: ast.Package_Id, name: symbol.Id) -> bool {
|
hidden_alias_target_exists :: proc(module: ^ast.Module, pkg: ast.Package_Id, name: symbol.Id) -> bool {
|
||||||
for function in module.functions {
|
for function in module.functions {
|
||||||
if function.pkg == pkg && function.name == name && function.file_hidden {
|
if function.pkg == pkg && function.name == name && function.package_hidden {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for global in module.globals {
|
for global in module.globals {
|
||||||
if global.pkg == pkg && global.name == name && global.file_hidden {
|
if global.pkg == pkg && global.name == name && global.package_hidden {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for item in module.type_store.nodes {
|
for item in module.type_store.nodes {
|
||||||
if item.declared && item.pkg == u32(pkg) && item.name == u32(name) && item.file_hidden {
|
if item.declared && item.pkg == u32(pkg) && item.name == u32(name) && item.package_hidden {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for alias in module.aliases {
|
for alias in module.aliases {
|
||||||
if alias.valid && alias.pkg == pkg && alias.name == name && alias.file_hidden {
|
if alias.valid && alias.pkg == pkg && alias.name == name && alias.package_hidden {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1531,7 +1524,7 @@ hidden_alias_target_exists :: proc(module: ^ast.Module, pkg: ast.Package_Id, nam
|
|||||||
|
|
||||||
find_public_alias :: proc(module: ^ast.Module, pkg: ast.Package_Id, name: symbol.Id) -> int {
|
find_public_alias :: proc(module: ^ast.Module, pkg: ast.Package_Id, name: symbol.Id) -> int {
|
||||||
for alias, index in module.aliases {
|
for alias, index in module.aliases {
|
||||||
if alias.valid && alias.pkg == pkg && alias.name == name && !alias.file_hidden {
|
if alias.valid && alias.pkg == pkg && alias.name == name && !alias.package_hidden {
|
||||||
return index
|
return index
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1592,7 +1585,7 @@ resolve_declaration_alias :: proc(state: ^State, index: int, states: []u8) -> bo
|
|||||||
alias.diagnostic = source.addf(
|
alias.diagnostic = source.addf(
|
||||||
state.diagnostics,
|
state.diagnostics,
|
||||||
alias.span,
|
alias.span,
|
||||||
"package member '%s.%s' is file-hidden",
|
"package member '%s.%s' is package-hidden",
|
||||||
symbol.resolve(state.symbols, alias.qualifier),
|
symbol.resolve(state.symbols, alias.qualifier),
|
||||||
symbol.resolve(state.symbols, alias.member),
|
symbol.resolve(state.symbols, alias.member),
|
||||||
)
|
)
|
||||||
@@ -1618,8 +1611,7 @@ validate_declaration_aliases :: proc(state: ^State) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for previous in state.module.aliases[:index] {
|
for previous in state.module.aliases[:index] {
|
||||||
if previous.pkg == alias.pkg && previous.name == alias.name &&
|
if previous.pkg == alias.pkg && previous.name == alias.name {
|
||||||
alias_declarations_conflict(alias.file, alias.file_hidden, previous.file, previous.file_hidden) {
|
|
||||||
alias.diagnostic = source.addf(state.diagnostics, alias.span, "duplicate declaration alias '%s'", name)
|
alias.diagnostic = source.addf(state.diagnostics, alias.span, "duplicate declaration alias '%s'", name)
|
||||||
alias.valid = false
|
alias.valid = false
|
||||||
break
|
break
|
||||||
@@ -1669,9 +1661,9 @@ validate_declaration_aliases :: proc(state: ^State) {
|
|||||||
u32(alias.pkg),
|
u32(alias.pkg),
|
||||||
u32(alias.name),
|
u32(alias.name),
|
||||||
file=u32(alias.file),
|
file=u32(alias.file),
|
||||||
file_hidden=alias.file_hidden,
|
package_hidden=alias.package_hidden,
|
||||||
)
|
)
|
||||||
if !types.define_alias(&state.module.type_store, id, types.Type(alias.target)) {
|
if !types.define_alias(&state.module.type_store, id, types.Type(alias.target), alias.package_hidden) {
|
||||||
alias.diagnostic = source.addf(state.diagnostics, alias.span, "duplicate type declaration '%s'", symbol.resolve(state.symbols, alias.name))
|
alias.diagnostic = source.addf(state.diagnostics, alias.span, "duplicate type declaration '%s'", symbol.resolve(state.symbols, alias.name))
|
||||||
alias.valid = false
|
alias.valid = false
|
||||||
}
|
}
|
||||||
|
|||||||
+37
-37
@@ -41,7 +41,7 @@ token_text :: proc(parser: ^Parser, tok: token.Token) -> string {
|
|||||||
return parser.source_file.text[int(tok.span.start):int(tok.span.end)]
|
return parser.source_file.text[int(tok.span.start):int(tok.span.end)]
|
||||||
}
|
}
|
||||||
|
|
||||||
file_hidden_name :: proc(parser: ^Parser, name: symbol.Id) -> bool {
|
package_hidden_name :: proc(parser: ^Parser, name: symbol.Id) -> bool {
|
||||||
for hidden in parser.hidden_names {
|
for hidden in parser.hidden_names {
|
||||||
if hidden == name {
|
if hidden == name {
|
||||||
return true
|
return true
|
||||||
@@ -435,7 +435,7 @@ parse_type_atom :: proc(parser: ^Parser) -> ast.Type_Syntax {
|
|||||||
u32(name.symbol),
|
u32(name.symbol),
|
||||||
u32(qualifier),
|
u32(qualifier),
|
||||||
u32(parser.file),
|
u32(parser.file),
|
||||||
!symbol.is_valid(qualifier) && file_hidden_name(parser, name.symbol),
|
!symbol.is_valid(qualifier) && package_hidden_name(parser, name.symbol),
|
||||||
)
|
)
|
||||||
if token_text(parser, name) == "struct_type" &&
|
if token_text(parser, name) == "struct_type" &&
|
||||||
current(parser).kind == .Bang && peek(parser).kind == .Left_Paren {
|
current(parser).kind == .Bang && peek(parser).kind == .Left_Paren {
|
||||||
@@ -2559,7 +2559,7 @@ parse_while :: proc(parser: ^Parser) -> ast.Stmt_Id {
|
|||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_function :: proc(parser: ^Parser, name: token.Token, c_abi, file_hidden: bool) {
|
parse_function :: proc(parser: ^Parser, name: token.Token, c_abi, package_hidden: bool) {
|
||||||
advance(parser)
|
advance(parser)
|
||||||
if _, ok := allow(parser, .Left_Paren); !ok {
|
if _, ok := allow(parser, .Left_Paren); !ok {
|
||||||
source.add(parser.diagnostics, current(parser).span, "expected '(' after 'func'")
|
source.add(parser.diagnostics, current(parser).span, "expected '(' after 'func'")
|
||||||
@@ -2590,7 +2590,7 @@ parse_function :: proc(parser: ^Parser, name: token.Token, c_abi, file_hidden: b
|
|||||||
pkg=parser.pkg,
|
pkg=parser.pkg,
|
||||||
file=parser.file,
|
file=parser.file,
|
||||||
c_abi=c_abi,
|
c_abi=c_abi,
|
||||||
file_hidden=file_hidden,
|
package_hidden=package_hidden,
|
||||||
has_body=false,
|
has_body=false,
|
||||||
variadic=variadic,
|
variadic=variadic,
|
||||||
params=params,
|
params=params,
|
||||||
@@ -2609,7 +2609,7 @@ parse_function :: proc(parser: ^Parser, name: token.Token, c_abi, file_hidden: b
|
|||||||
pkg=parser.pkg,
|
pkg=parser.pkg,
|
||||||
file=parser.file,
|
file=parser.file,
|
||||||
c_abi=c_abi,
|
c_abi=c_abi,
|
||||||
file_hidden=file_hidden,
|
package_hidden=package_hidden,
|
||||||
has_body=true,
|
has_body=true,
|
||||||
variadic=variadic,
|
variadic=variadic,
|
||||||
params=params,
|
params=params,
|
||||||
@@ -2795,9 +2795,9 @@ parse_inline_union_type :: proc(parser: ^Parser) -> types.Type {
|
|||||||
return types.union_anonymous(&parser.module.type_store, fields[:], tag)
|
return types.union_anonymous(&parser.module.type_store, fields[:], tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_struct :: proc(parser: ^Parser, name: token.Token, c_layout, file_hidden: bool, is_union := false) {
|
parse_struct :: proc(parser: ^Parser, name: token.Token, c_layout, package_hidden: bool, is_union := false) {
|
||||||
start := advance(parser)
|
start := advance(parser)
|
||||||
id := types.named(&parser.module.type_store, u32(parser.pkg), u32(name.symbol), file=u32(parser.file), file_hidden=file_hidden)
|
id := types.named(&parser.module.type_store, u32(parser.pkg), u32(name.symbol), file=u32(parser.file), package_hidden=package_hidden)
|
||||||
// A tagged union spells its discriminant in parens: `union(Enum)` reuses an existing
|
// A tagged union spells its discriminant in parens: `union(Enum)` reuses an existing
|
||||||
// enum; `union(enum)` synthesizes one from the variant names after the body is parsed.
|
// enum; `union(enum)` synthesizes one from the variant names after the body is parsed.
|
||||||
tag := types.INVALID
|
tag := types.INVALID
|
||||||
@@ -2831,7 +2831,7 @@ parse_struct :: proc(parser: ^Parser, name: token.Token, c_layout, file_hidden:
|
|||||||
"native union declarations require a body" if is_union else "native struct declarations require a body",
|
"native union declarations require a body" if is_union else "native struct declarations require a body",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if !types.define_record(&parser.module.type_store, id, nil, c_layout, true, is_union, tag=tag, declared_tag=declared_tag) {
|
if !types.define_record(&parser.module.type_store, id, nil, c_layout, true, is_union, tag=tag, declared_tag=declared_tag, package_hidden=package_hidden) {
|
||||||
source.addf(parser.diagnostics, name.span, "duplicate type declaration '%s'", token_text(parser, name))
|
source.addf(parser.diagnostics, name.span, "duplicate type declaration '%s'", token_text(parser, name))
|
||||||
}
|
}
|
||||||
if !ended_by_newline {
|
if !ended_by_newline {
|
||||||
@@ -2868,7 +2868,7 @@ parse_struct :: proc(parser: ^Parser, name: token.Token, c_layout, file_hidden:
|
|||||||
if is_union && (inferred_tag || types.is_valid(declared_tag)) {
|
if is_union && (inferred_tag || types.is_valid(declared_tag)) {
|
||||||
tag = synthesize_union_tag(parser, fields[:])
|
tag = synthesize_union_tag(parser, fields[:])
|
||||||
}
|
}
|
||||||
if !types.define_record(&parser.module.type_store, id, fields[:], c_layout, false, is_union, tag=tag, declared_tag=declared_tag, tuple=tuple) {
|
if !types.define_record(&parser.module.type_store, id, fields[:], c_layout, false, is_union, tag=tag, declared_tag=declared_tag, tuple=tuple, package_hidden=package_hidden) {
|
||||||
source.addf(parser.diagnostics, name.span, "duplicate type declaration '%s'", token_text(parser, name))
|
source.addf(parser.diagnostics, name.span, "duplicate type declaration '%s'", token_text(parser, name))
|
||||||
} else if !c_layout && !is_union && !tuple {
|
} else if !c_layout && !is_union && !tuple {
|
||||||
for value, index in defaults {
|
for value, index in defaults {
|
||||||
@@ -2887,10 +2887,10 @@ parse_struct :: proc(parser: ^Parser, name: token.Token, c_layout, file_hidden:
|
|||||||
_ = finish_statement(parser)
|
_ = finish_statement(parser)
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_opaque :: proc(parser: ^Parser, name: token.Token, file_hidden: bool) {
|
parse_opaque :: proc(parser: ^Parser, name: token.Token, package_hidden: bool) {
|
||||||
start := advance(parser)
|
start := advance(parser)
|
||||||
id := types.named(&parser.module.type_store, u32(parser.pkg), u32(name.symbol), file=u32(parser.file), file_hidden=file_hidden)
|
id := types.named(&parser.module.type_store, u32(parser.pkg), u32(name.symbol), file=u32(parser.file), package_hidden=package_hidden)
|
||||||
if !types.define_record(&parser.module.type_store, id, nil, false, true, false) {
|
if !types.define_record(&parser.module.type_store, id, nil, false, true, false, package_hidden=package_hidden) {
|
||||||
source.addf(parser.diagnostics, name.span, "duplicate type declaration '%s'", token_text(parser, name))
|
source.addf(parser.diagnostics, name.span, "duplicate type declaration '%s'", token_text(parser, name))
|
||||||
}
|
}
|
||||||
if current(parser).kind == .Left_Brace {
|
if current(parser).kind == .Left_Brace {
|
||||||
@@ -2915,11 +2915,11 @@ synthesize_union_tag :: proc(parser: ^Parser, fields: []types.Field) -> types.Ty
|
|||||||
return types.enum_anonymous(&parser.module.type_store, members, types.U16)
|
return types.enum_anonymous(&parser.module.type_store, members, types.U16)
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_distinct :: proc(parser: ^Parser, name: token.Token, file_hidden: bool) {
|
parse_distinct :: proc(parser: ^Parser, name: token.Token, package_hidden: bool) {
|
||||||
start := advance(parser)
|
start := advance(parser)
|
||||||
child := parse_type(parser)
|
child := parse_type(parser)
|
||||||
id := types.named(&parser.module.type_store, u32(parser.pkg), u32(name.symbol), file=u32(parser.file), file_hidden=file_hidden)
|
id := types.named(&parser.module.type_store, u32(parser.pkg), u32(name.symbol), file=u32(parser.file), package_hidden=package_hidden)
|
||||||
if !types.define_distinct(&parser.module.type_store, id, child) {
|
if !types.define_distinct(&parser.module.type_store, id, child, package_hidden) {
|
||||||
source.addf(parser.diagnostics, name.span, "duplicate type declaration '%s'", token_text(parser, name))
|
source.addf(parser.diagnostics, name.span, "duplicate type declaration '%s'", token_text(parser, name))
|
||||||
}
|
}
|
||||||
if !types.is_valid(child) {
|
if !types.is_valid(child) {
|
||||||
@@ -2928,7 +2928,7 @@ parse_distinct :: proc(parser: ^Parser, name: token.Token, file_hidden: bool) {
|
|||||||
_ = finish_statement(parser)
|
_ = finish_statement(parser)
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_alias :: proc(parser: ^Parser, name: token.Token, file_hidden: bool) {
|
parse_alias :: proc(parser: ^Parser, name: token.Token, package_hidden: bool) {
|
||||||
start := advance(parser)
|
start := advance(parser)
|
||||||
saved := parser.cursor
|
saved := parser.cursor
|
||||||
if current(parser).kind == .Identifier && peek(parser).kind == .Dot {
|
if current(parser).kind == .Identifier && peek(parser).kind == .Dot {
|
||||||
@@ -2945,7 +2945,7 @@ parse_alias :: proc(parser: ^Parser, name: token.Token, file_hidden: bool) {
|
|||||||
pkg=parser.pkg,
|
pkg=parser.pkg,
|
||||||
file=parser.file,
|
file=parser.file,
|
||||||
target_pkg=ast.INVALID_PACKAGE,
|
target_pkg=ast.INVALID_PACKAGE,
|
||||||
file_hidden=file_hidden,
|
package_hidden=package_hidden,
|
||||||
valid=true,
|
valid=true,
|
||||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||||
})
|
})
|
||||||
@@ -2956,8 +2956,8 @@ parse_alias :: proc(parser: ^Parser, name: token.Token, file_hidden: bool) {
|
|||||||
}
|
}
|
||||||
parser.cursor = saved
|
parser.cursor = saved
|
||||||
child := parse_type(parser)
|
child := parse_type(parser)
|
||||||
id := types.named(&parser.module.type_store, u32(parser.pkg), u32(name.symbol), file=u32(parser.file), file_hidden=file_hidden)
|
id := types.named(&parser.module.type_store, u32(parser.pkg), u32(name.symbol), file=u32(parser.file), package_hidden=package_hidden)
|
||||||
if !types.define_alias(&parser.module.type_store, id, child) {
|
if !types.define_alias(&parser.module.type_store, id, child, package_hidden) {
|
||||||
source.addf(parser.diagnostics, name.span, "duplicate type declaration '%s'", token_text(parser, name))
|
source.addf(parser.diagnostics, name.span, "duplicate type declaration '%s'", token_text(parser, name))
|
||||||
}
|
}
|
||||||
if !types.is_valid(child) {
|
if !types.is_valid(child) {
|
||||||
@@ -3100,7 +3100,7 @@ parse_inline_enum_type :: proc(parser: ^Parser) -> types.Type {
|
|||||||
return types.enum_anonymous(&parser.module.type_store, members[:], backing)
|
return types.enum_anonymous(&parser.module.type_store, members[:], backing)
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_enum :: proc(parser: ^Parser, name: token.Token, file_hidden: bool) {
|
parse_enum :: proc(parser: ^Parser, name: token.Token, package_hidden: bool) {
|
||||||
start := advance(parser)
|
start := advance(parser)
|
||||||
explicit_backing := false
|
explicit_backing := false
|
||||||
backing := types.INVALID
|
backing := types.INVALID
|
||||||
@@ -3122,8 +3122,8 @@ parse_enum :: proc(parser: ^Parser, name: token.Token, file_hidden: bool) {
|
|||||||
_ = finish_statement(parser)
|
_ = finish_statement(parser)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
id := types.named(&parser.module.type_store, u32(parser.pkg), u32(name.symbol), file=u32(parser.file), file_hidden=file_hidden)
|
id := types.named(&parser.module.type_store, u32(parser.pkg), u32(name.symbol), file=u32(parser.file), package_hidden=package_hidden)
|
||||||
if !types.define_enum(&parser.module.type_store, id, backing, members[:], explicit_backing) {
|
if !types.define_enum(&parser.module.type_store, id, backing, members[:], explicit_backing, package_hidden) {
|
||||||
source.addf(parser.diagnostics, name.span, "duplicate type declaration '%s'", token_text(parser, name))
|
source.addf(parser.diagnostics, name.span, "duplicate type declaration '%s'", token_text(parser, name))
|
||||||
}
|
}
|
||||||
if explicit_backing && deferred {
|
if explicit_backing && deferred {
|
||||||
@@ -3252,9 +3252,9 @@ parse_test :: proc(parser: ^Parser, name: token.Token) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parse_top_level :: proc(parser: ^Parser) {
|
parse_top_level :: proc(parser: ^Parser) {
|
||||||
hide_token, file_hidden := allow(parser, .Keyword_Hide)
|
hide_token, package_hidden := allow(parser, .Keyword_Hide)
|
||||||
if current(parser).kind == .Keyword_Test && peek(parser).kind == .Keyword_Import {
|
if current(parser).kind == .Keyword_Test && peek(parser).kind == .Keyword_Import {
|
||||||
if file_hidden {
|
if package_hidden {
|
||||||
source.add(parser.diagnostics, hide_token.span, "test imports cannot use 'hide'")
|
source.add(parser.diagnostics, hide_token.span, "test imports cannot use 'hide'")
|
||||||
}
|
}
|
||||||
start := advance(parser)
|
start := advance(parser)
|
||||||
@@ -3263,7 +3263,7 @@ parse_top_level :: proc(parser: ^Parser) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if current(parser).kind == .Keyword_Import {
|
if current(parser).kind == .Keyword_Import {
|
||||||
if file_hidden {
|
if package_hidden {
|
||||||
source.add(parser.diagnostics, hide_token.span, "imports are already file-local and cannot use 'hide'")
|
source.add(parser.diagnostics, hide_token.span, "imports are already file-local and cannot use 'hide'")
|
||||||
}
|
}
|
||||||
start := advance(parser)
|
start := advance(parser)
|
||||||
@@ -3271,7 +3271,7 @@ parse_top_level :: proc(parser: ^Parser) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if current(parser).kind != .Identifier {
|
if current(parser).kind != .Identifier {
|
||||||
message := "expected a declaration name after 'hide'" if file_hidden else "expected a top-level declaration"
|
message := "expected a declaration name after 'hide'" if package_hidden else "expected a top-level declaration"
|
||||||
source.add(parser.diagnostics, current(parser).span, message)
|
source.add(parser.diagnostics, current(parser).span, message)
|
||||||
for current(parser).kind != .Newline && current(parser).kind != .Eof {
|
for current(parser).kind != .Newline && current(parser).kind != .Eof {
|
||||||
advance(parser)
|
advance(parser)
|
||||||
@@ -3281,7 +3281,7 @@ parse_top_level :: proc(parser: ^Parser) {
|
|||||||
}
|
}
|
||||||
name := advance(parser)
|
name := advance(parser)
|
||||||
if current(parser).kind == .Keyword_Test {
|
if current(parser).kind == .Keyword_Test {
|
||||||
if file_hidden {
|
if package_hidden {
|
||||||
source.add(parser.diagnostics, hide_token.span, "test declarations cannot use 'hide'")
|
source.add(parser.diagnostics, hide_token.span, "test declarations cannot use 'hide'")
|
||||||
}
|
}
|
||||||
parse_test(parser, name)
|
parse_test(parser, name)
|
||||||
@@ -3292,7 +3292,7 @@ parse_top_level :: proc(parser: ^Parser) {
|
|||||||
advance(parser)
|
advance(parser)
|
||||||
skip_newlines(parser)
|
skip_newlines(parser)
|
||||||
if current(parser).kind == .Keyword_Import {
|
if current(parser).kind == .Keyword_Import {
|
||||||
if file_hidden {
|
if package_hidden {
|
||||||
source.add(parser.diagnostics, hide_token.span, "imports are already file-local and cannot use 'hide'")
|
source.add(parser.diagnostics, hide_token.span, "imports are already file-local and cannot use 'hide'")
|
||||||
}
|
}
|
||||||
start := advance(parser)
|
start := advance(parser)
|
||||||
@@ -3303,7 +3303,7 @@ parse_top_level :: proc(parser: ^Parser) {
|
|||||||
}
|
}
|
||||||
if current(parser).kind == .Keyword_Func || current(parser).kind == .Keyword_C_Func {
|
if current(parser).kind == .Keyword_Func || current(parser).kind == .Keyword_C_Func {
|
||||||
c_abi := current(parser).kind == .Keyword_C_Func
|
c_abi := current(parser).kind == .Keyword_C_Func
|
||||||
parse_function(parser, name, c_abi, file_hidden)
|
parse_function(parser, name, c_abi, package_hidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
type_syntax := types.INVALID
|
type_syntax := types.INVALID
|
||||||
@@ -3324,32 +3324,32 @@ parse_top_level :: proc(parser: ^Parser) {
|
|||||||
source.add(parser.diagnostics, span_from(name.span, current(parser).span),
|
source.add(parser.diagnostics, span_from(name.span, current(parser).span),
|
||||||
"function declarations do not use '::'; write 'name func(...)' or 'name c_func(...)'")
|
"function declarations do not use '::'; write 'name func(...)' or 'name c_func(...)'")
|
||||||
c_abi := current(parser).kind == .Keyword_C_Func
|
c_abi := current(parser).kind == .Keyword_C_Func
|
||||||
parse_function(parser, name, c_abi, file_hidden)
|
parse_function(parser, name, c_abi, package_hidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if operator.kind == .Colon_Colon &&
|
if operator.kind == .Colon_Colon &&
|
||||||
(current(parser).kind == .Keyword_Struct || current(parser).kind == .Keyword_C_Struct) {
|
(current(parser).kind == .Keyword_Struct || current(parser).kind == .Keyword_C_Struct) {
|
||||||
parse_struct(parser, name, current(parser).kind == .Keyword_C_Struct, file_hidden)
|
parse_struct(parser, name, current(parser).kind == .Keyword_C_Struct, package_hidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if operator.kind == .Colon_Colon && current(parser).kind == .Keyword_Opaque {
|
if operator.kind == .Colon_Colon && current(parser).kind == .Keyword_Opaque {
|
||||||
parse_opaque(parser, name, file_hidden)
|
parse_opaque(parser, name, package_hidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if operator.kind == .Colon_Colon && current(parser).kind == .Keyword_Union {
|
if operator.kind == .Colon_Colon && current(parser).kind == .Keyword_Union {
|
||||||
parse_struct(parser, name, false, file_hidden, is_union=true)
|
parse_struct(parser, name, false, package_hidden, is_union=true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if operator.kind == .Colon_Colon && current(parser).kind == .Keyword_Enum {
|
if operator.kind == .Colon_Colon && current(parser).kind == .Keyword_Enum {
|
||||||
parse_enum(parser, name, file_hidden)
|
parse_enum(parser, name, package_hidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if operator.kind == .Colon_Colon && current(parser).kind == .Keyword_Distinct {
|
if operator.kind == .Colon_Colon && current(parser).kind == .Keyword_Distinct {
|
||||||
parse_distinct(parser, name, file_hidden)
|
parse_distinct(parser, name, package_hidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if operator.kind == .Colon_Colon && current(parser).kind == .Keyword_Alias {
|
if operator.kind == .Colon_Colon && current(parser).kind == .Keyword_Alias {
|
||||||
parse_alias(parser, name, file_hidden)
|
parse_alias(parser, name, package_hidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3360,7 +3360,7 @@ parse_top_level :: proc(parser: ^Parser) {
|
|||||||
name=name.symbol,
|
name=name.symbol,
|
||||||
pkg=parser.pkg,
|
pkg=parser.pkg,
|
||||||
file=parser.file,
|
file=parser.file,
|
||||||
file_hidden=file_hidden,
|
package_hidden=package_hidden,
|
||||||
type=type_syntax,
|
type=type_syntax,
|
||||||
immutable=operator.kind == .Colon_Colon,
|
immutable=operator.kind == .Colon_Colon,
|
||||||
expr=expr,
|
expr=expr,
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ inject_assertion_locations :: proc(
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
location := location_expr(module, sources, symbols, expr.span, expr.qualifier)
|
location := location_expr(module, sources, symbols, expr.span, expr.qualifier)
|
||||||
|
expr = &module.exprs[index]
|
||||||
args := make([]ast.Expr_Id, len(expr.args)+1, module.allocator)
|
args := make([]ast.Expr_Id, len(expr.args)+1, module.allocator)
|
||||||
copy(args, expr.args)
|
copy(args, expr.args)
|
||||||
args[len(expr.args)] = location
|
args[len(expr.args)] = location
|
||||||
|
|||||||
+20
-20
@@ -109,7 +109,7 @@ Node :: struct {
|
|||||||
tuple: bool,
|
tuple: bool,
|
||||||
opaque: bool,
|
opaque: bool,
|
||||||
declared: bool,
|
declared: bool,
|
||||||
file_hidden: bool,
|
package_hidden: bool,
|
||||||
explicit_backing: bool,
|
explicit_backing: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,43 +193,38 @@ intern :: proc(store: ^Store, candidate: Node) -> Type {
|
|||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
named :: proc(store: ^Store, pkg, name: u32, qualifier: u32 = 0, file: u32 = 0xffff_ffff, file_hidden := false) -> Type {
|
named :: proc(store: ^Store, pkg, name: u32, qualifier: u32 = 0, file: u32 = 0xffff_ffff, package_hidden := false) -> Type {
|
||||||
normalized_file := file if qualifier != 0 || file_hidden else u32(0)
|
normalized_file := file if qualifier != 0 else u32(0)
|
||||||
for existing, index in store.nodes {
|
for existing, index in store.nodes {
|
||||||
visibility_matches := existing.file_hidden == file_hidden &&
|
|
||||||
(!file_hidden || existing.file == normalized_file)
|
|
||||||
if (existing.kind == .Named || existing.kind == .Alias || existing.kind == .Distinct ||
|
if (existing.kind == .Named || existing.kind == .Alias || existing.kind == .Distinct ||
|
||||||
existing.kind == .Enum || existing.kind == .Struct || existing.kind == .Union) &&
|
existing.kind == .Enum || existing.kind == .Struct || existing.kind == .Union) &&
|
||||||
existing.pkg == pkg && existing.name == name && existing.qualifier == qualifier &&
|
existing.pkg == pkg && existing.name == name && existing.qualifier == qualifier &&
|
||||||
(visibility_matches || qualifier == 0 && existing.file_hidden != file_hidden) {
|
(qualifier == 0 || existing.file == normalized_file) {
|
||||||
return DYNAMIC_START+Type(index)
|
return DYNAMIC_START+Type(index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return intern(store, Node{kind=.Named, pkg=pkg, name=name, qualifier=qualifier, file=normalized_file, file_hidden=file_hidden})
|
return intern(store, Node{
|
||||||
|
kind=.Named,
|
||||||
|
pkg=pkg,
|
||||||
|
name=name,
|
||||||
|
qualifier=qualifier,
|
||||||
|
file=normalized_file,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
find_named :: proc(store: ^Store, pkg, name: u32, qualifier: u32 = 0, file: u32 = 0xffff_ffff) -> Type {
|
find_named :: proc(store: ^Store, pkg, name: u32, qualifier: u32 = 0, file: u32 = 0xffff_ffff) -> Type {
|
||||||
if file != 0xffff_ffff {
|
|
||||||
for existing, index in store.nodes {
|
for existing, index in store.nodes {
|
||||||
if (existing.kind == .Named || existing.kind == .Alias || existing.kind == .Distinct ||
|
if (existing.kind == .Named || existing.kind == .Alias || existing.kind == .Distinct ||
|
||||||
existing.kind == .Enum || existing.kind == .Struct || existing.kind == .Union) &&
|
existing.kind == .Enum || existing.kind == .Struct || existing.kind == .Union) &&
|
||||||
existing.pkg == pkg && existing.name == name && existing.qualifier == qualifier &&
|
existing.pkg == pkg && existing.name == name && existing.qualifier == qualifier &&
|
||||||
existing.file_hidden && existing.file == file {
|
(!existing.package_hidden || file != 0xffff_ffff) {
|
||||||
return DYNAMIC_START+Type(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for existing, index in store.nodes {
|
|
||||||
if (existing.kind == .Named || existing.kind == .Alias || existing.kind == .Distinct ||
|
|
||||||
existing.kind == .Enum || existing.kind == .Struct || existing.kind == .Union) &&
|
|
||||||
existing.pkg == pkg && existing.name == name && existing.qualifier == qualifier && !existing.file_hidden {
|
|
||||||
return DYNAMIC_START+Type(index)
|
return DYNAMIC_START+Type(index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return INVALID
|
return INVALID
|
||||||
}
|
}
|
||||||
|
|
||||||
define_alias :: proc(store: ^Store, id, child: Type) -> bool {
|
define_alias :: proc(store: ^Store, id, child: Type, package_hidden := false) -> bool {
|
||||||
existing, ok := node(store, id)
|
existing, ok := node(store, id)
|
||||||
if !ok || existing.kind != .Named || existing.declared {
|
if !ok || existing.kind != .Named || existing.declared {
|
||||||
return false
|
return false
|
||||||
@@ -237,11 +232,12 @@ define_alias :: proc(store: ^Store, id, child: Type) -> bool {
|
|||||||
index := int(id-DYNAMIC_START)
|
index := int(id-DYNAMIC_START)
|
||||||
store.nodes[index].kind = .Alias
|
store.nodes[index].kind = .Alias
|
||||||
store.nodes[index].child = child
|
store.nodes[index].child = child
|
||||||
|
store.nodes[index].package_hidden = package_hidden
|
||||||
store.nodes[index].declared = true
|
store.nodes[index].declared = true
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
define_distinct :: proc(store: ^Store, id, child: Type) -> bool {
|
define_distinct :: proc(store: ^Store, id, child: Type, package_hidden := false) -> bool {
|
||||||
existing, ok := node(store, id)
|
existing, ok := node(store, id)
|
||||||
if !ok || existing.kind != .Named || existing.declared {
|
if !ok || existing.kind != .Named || existing.declared {
|
||||||
return false
|
return false
|
||||||
@@ -249,11 +245,12 @@ define_distinct :: proc(store: ^Store, id, child: Type) -> bool {
|
|||||||
index := int(id-DYNAMIC_START)
|
index := int(id-DYNAMIC_START)
|
||||||
store.nodes[index].kind = .Distinct
|
store.nodes[index].kind = .Distinct
|
||||||
store.nodes[index].child = child
|
store.nodes[index].child = child
|
||||||
|
store.nodes[index].package_hidden = package_hidden
|
||||||
store.nodes[index].declared = true
|
store.nodes[index].declared = true
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
define_enum :: proc(store: ^Store, id, backing: Type, members: []Enum_Member, explicit_backing: bool) -> bool {
|
define_enum :: proc(store: ^Store, id, backing: Type, members: []Enum_Member, explicit_backing: bool, package_hidden := false) -> bool {
|
||||||
existing, ok := node(store, id)
|
existing, ok := node(store, id)
|
||||||
if !ok || existing.kind != .Named || existing.declared {
|
if !ok || existing.kind != .Named || existing.declared {
|
||||||
return false
|
return false
|
||||||
@@ -264,6 +261,7 @@ define_enum :: proc(store: ^Store, id, backing: Type, members: []Enum_Member, ex
|
|||||||
store.nodes[index].field_start = u32(len(store.enum_members))
|
store.nodes[index].field_start = u32(len(store.enum_members))
|
||||||
store.nodes[index].field_count = u32(len(members))
|
store.nodes[index].field_count = u32(len(members))
|
||||||
store.nodes[index].explicit_backing = explicit_backing
|
store.nodes[index].explicit_backing = explicit_backing
|
||||||
|
store.nodes[index].package_hidden = package_hidden
|
||||||
store.nodes[index].declared = true
|
store.nodes[index].declared = true
|
||||||
append(&store.enum_members, ..members)
|
append(&store.enum_members, ..members)
|
||||||
return true
|
return true
|
||||||
@@ -280,6 +278,7 @@ define_record :: proc(
|
|||||||
tag: Type = INVALID,
|
tag: Type = INVALID,
|
||||||
declared_tag: Type = INVALID,
|
declared_tag: Type = INVALID,
|
||||||
tuple := false,
|
tuple := false,
|
||||||
|
package_hidden := false,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
existing, ok := node(store, id)
|
existing, ok := node(store, id)
|
||||||
if !ok || (existing.kind != .Named && existing.kind != .Struct && existing.kind != .Union) ||
|
if !ok || (existing.kind != .Named && existing.kind != .Struct && existing.kind != .Union) ||
|
||||||
@@ -291,6 +290,7 @@ define_record :: proc(
|
|||||||
store.nodes[index].c_layout = c_layout
|
store.nodes[index].c_layout = c_layout
|
||||||
store.nodes[index].tuple = tuple
|
store.nodes[index].tuple = tuple
|
||||||
store.nodes[index].opaque = opaque
|
store.nodes[index].opaque = opaque
|
||||||
|
store.nodes[index].package_hidden = package_hidden
|
||||||
store.nodes[index].declared = true
|
store.nodes[index].declared = true
|
||||||
store.nodes[index].explicit_size = explicit_size
|
store.nodes[index].explicit_size = explicit_size
|
||||||
store.nodes[index].explicit_alignment = explicit_alignment
|
store.nodes[index].explicit_alignment = explicit_alignment
|
||||||
|
|||||||
+84
-7
@@ -9752,7 +9752,7 @@ hide_is_rejected_outside_named_top_level_declarations :: proc(t: ^testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@(test)
|
@(test)
|
||||||
hide_declarations_are_file_hidden :: proc(t: ^testing.T) {
|
hide_declarations_are_package_hidden :: proc(t: ^testing.T) {
|
||||||
output := "/tmp/brolang-test-hidden-declarations"
|
output := "/tmp/brolang-test-hidden-declarations"
|
||||||
defer _ = os.remove(output)
|
defer _ = os.remove(output)
|
||||||
status := compiler_core.compile_package("examples/packages/hidden_valid/app", output)
|
status := compiler_core.compile_package("examples/packages/hidden_valid/app", output)
|
||||||
@@ -9762,7 +9762,7 @@ hide_declarations_are_file_hidden :: proc(t: ^testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@(test)
|
@(test)
|
||||||
file_hidden_declarations_are_not_package_members :: proc(t: ^testing.T) {
|
package_hidden_declarations_resolve_locally_but_not_through_imports :: proc(t: ^testing.T) {
|
||||||
sources := source.init_store()
|
sources := source.init_store()
|
||||||
defer source.destroy_store(&sources)
|
defer source.destroy_store(&sources)
|
||||||
diagnostics := source.init_store_diagnostics(&sources)
|
diagnostics := source.init_store_diagnostics(&sources)
|
||||||
@@ -9787,9 +9787,9 @@ file_hidden_declarations_are_not_package_members :: proc(t: ^testing.T) {
|
|||||||
found_import = found_import || strings.contains(diagnostic.message, "package 'dep' has no member 'secret'")
|
found_import = found_import || strings.contains(diagnostic.message, "package 'dep' has no member 'secret'")
|
||||||
found_collision = found_collision || strings.contains(diagnostic.message, "duplicate function 'collision'")
|
found_collision = found_collision || strings.contains(diagnostic.message, "duplicate function 'collision'")
|
||||||
}
|
}
|
||||||
testing.expect(t, found_sibling)
|
testing.expect(t, !found_sibling)
|
||||||
testing.expect(t, found_sibling_value)
|
testing.expect(t, !found_sibling_value)
|
||||||
testing.expect(t, found_sibling_type)
|
testing.expect(t, !found_sibling_type)
|
||||||
testing.expect(t, found_import)
|
testing.expect(t, found_import)
|
||||||
testing.expect(t, found_collision)
|
testing.expect(t, found_collision)
|
||||||
}
|
}
|
||||||
@@ -9910,13 +9910,15 @@ RenamedBox :: alias dep.Box
|
|||||||
RenamedPoint :: alias dep.Point
|
RenamedPoint :: alias dep.Point
|
||||||
counter :: alias dep.counter
|
counter :: alias dep.counter
|
||||||
answer :: alias dep.answer
|
answer :: alias dep.answer
|
||||||
hide local_answer_alias :: alias dep.answer
|
|
||||||
local_answer func() i32 { return local_answer_alias() }
|
local_answer func() i32 { return local_answer_alias() }
|
||||||
Scalar :: alias i32
|
Scalar :: alias i32
|
||||||
ScalarChain :: alias Scalar
|
ScalarChain :: alias Scalar
|
||||||
static_scalar Scalar :: Scalar(usize(6))
|
static_scalar Scalar :: Scalar(usize(6))
|
||||||
MaybePoint :: alias ?@dep.Point
|
MaybePoint :: alias ?@dep.Point
|
||||||
Concrete :: alias dep.Box(i32)
|
Concrete :: alias dep.Box(i32)
|
||||||
|
`
|
||||||
|
hidden_text := `dep :: import "../dep"
|
||||||
|
hide local_answer_alias :: alias dep.answer
|
||||||
`
|
`
|
||||||
top_text := `facade :: import "../facade"
|
top_text := `facade :: import "../facade"
|
||||||
Box :: alias facade.RenamedBox
|
Box :: alias facade.RenamedBox
|
||||||
@@ -9946,6 +9948,7 @@ main func() i32 {
|
|||||||
`
|
`
|
||||||
testing.expect(t, os.write_entire_file(dep_dir + "/dep.bro", transmute([]byte)dep_text))
|
testing.expect(t, os.write_entire_file(dep_dir + "/dep.bro", transmute([]byte)dep_text))
|
||||||
testing.expect(t, os.write_entire_file(facade_dir + "/facade.bro", transmute([]byte)facade_text))
|
testing.expect(t, os.write_entire_file(facade_dir + "/facade.bro", transmute([]byte)facade_text))
|
||||||
|
testing.expect(t, os.write_entire_file(facade_dir + "/hidden.bro", transmute([]byte)hidden_text))
|
||||||
testing.expect(t, os.write_entire_file(top_dir + "/top.bro", transmute([]byte)top_text))
|
testing.expect(t, os.write_entire_file(top_dir + "/top.bro", transmute([]byte)top_text))
|
||||||
testing.expect(t, os.write_entire_file(app_dir + "/main.bro", transmute([]byte)app_text))
|
testing.expect(t, os.write_entire_file(app_dir + "/main.bro", transmute([]byte)app_text))
|
||||||
|
|
||||||
@@ -10083,7 +10086,7 @@ main func() void {}
|
|||||||
testing.expect(t, loaded)
|
testing.expect(t, loaded)
|
||||||
wants := []string{
|
wants := []string{
|
||||||
"has no member 'missing'",
|
"has no member 'missing'",
|
||||||
"is file-hidden",
|
"is package-hidden",
|
||||||
"unknown symbol 'nope'",
|
"unknown symbol 'nope'",
|
||||||
"unavailable imported package 'gone'",
|
"unavailable imported package 'gone'",
|
||||||
"package member 'dep.ambiguous' is ambiguous",
|
"package member 'dep.ambiguous' is ambiguous",
|
||||||
@@ -14961,6 +14964,8 @@ enum_field_struct_and_contextual_anonymous_records_compile_and_run :: proc(t: ^t
|
|||||||
text := `meta :: import "@std/meta"
|
text := `meta :: import "@std/meta"
|
||||||
testing :: import "@std/testing"
|
testing :: import "@std/testing"
|
||||||
|
|
||||||
|
OtherTokenKind :: enum { alpha, beta, end }
|
||||||
|
|
||||||
TokenKind :: enum(u8) {
|
TokenKind :: enum(u8) {
|
||||||
ident = 3
|
ident = 3
|
||||||
int = 8
|
int = 8
|
||||||
@@ -15034,6 +15039,8 @@ get func($E, $V type, map @Map(E, V), key E) ?V {
|
|||||||
}
|
}
|
||||||
|
|
||||||
main func() i32 {
|
main func() i32 {
|
||||||
|
other Map(OtherTokenKind, []u8) = init(OtherTokenKind, []u8, {alpha = "other"})
|
||||||
|
if !other.present[0] { return 26 }
|
||||||
_ = ordered
|
_ = ordered
|
||||||
if none != 41 { return 24 }
|
if none != 41 { return 24 }
|
||||||
if !$(static_none == null) or !$(null == static_none) or
|
if !$(static_none == null) or !$(null == static_none) or
|
||||||
@@ -15570,3 +15577,73 @@ main func() void {
|
|||||||
testing.expect(t, found_missing)
|
testing.expect(t, found_missing)
|
||||||
testing.expect(t, found_empty_c)
|
testing.expect(t, found_empty_c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
type_factory_inference_prefers_unique_provenance_before_convertible_direct_evidence :: proc(t: ^testing.T) {
|
||||||
|
directory := "/tmp/brolang-test-factory-provenance-conversion"
|
||||||
|
main_path := "/tmp/brolang-test-factory-provenance-conversion/main.bro"
|
||||||
|
output := "/tmp/brolang-test-factory-provenance-conversion-output"
|
||||||
|
text := `HashBox func($K, $V type, $hash func(value K) usize) type {
|
||||||
|
return struct { value V }
|
||||||
|
}
|
||||||
|
|
||||||
|
string_hash func(value []u8) usize { return value.len }
|
||||||
|
|
||||||
|
StringBox func($V type) type {
|
||||||
|
return HashBox([]u8, V, string_hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
put func(
|
||||||
|
$K, $V type,
|
||||||
|
$hash func(value K) usize,
|
||||||
|
box @mut HashBox(K, V, hash),
|
||||||
|
key K,
|
||||||
|
value V,
|
||||||
|
) void {
|
||||||
|
_ = box
|
||||||
|
_ = key
|
||||||
|
_ = value
|
||||||
|
}
|
||||||
|
|
||||||
|
main func() i32 {
|
||||||
|
box StringBox(u32) = {value = 0}
|
||||||
|
key []mut u8 = undefined
|
||||||
|
put(&box, key, 42)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
`
|
||||||
|
_ = os2.remove_all(directory)
|
||||||
|
defer _ = os2.remove_all(directory)
|
||||||
|
defer _ = os.remove(output)
|
||||||
|
testing.expect(t, os.make_directory(directory) == nil)
|
||||||
|
testing.expect(t, os.write_entire_file(main_path, transmute([]byte)text))
|
||||||
|
testing.expect_value(t, compiler_core.compile_package(
|
||||||
|
directory, output, nil, target.DEFAULT, cimport.Options{}, ".",
|
||||||
|
), 0)
|
||||||
|
state := run_executable(output)
|
||||||
|
testing.expect_value(t, state.exit_code, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
assertion_location_injection_survives_expression_store_growth :: proc(t: ^testing.T) {
|
||||||
|
directory := "/tmp/brolang-test-assertion-location-growth"
|
||||||
|
main_path := "/tmp/brolang-test-assertion-location-growth/main.bro"
|
||||||
|
output := "/tmp/brolang-test-assertion-location-growth-output"
|
||||||
|
builder := strings.builder_make()
|
||||||
|
defer strings.builder_destroy(&builder)
|
||||||
|
strings.write_string(&builder, "testing :: import \"@std/testing\"\n\nmany test {\n")
|
||||||
|
for index in 0..<128 {
|
||||||
|
fmt.sbprintf(&builder, "\ttry testing.expect_equal(%d, %d)\n", index, index)
|
||||||
|
}
|
||||||
|
strings.write_string(&builder, "}\n")
|
||||||
|
_ = os2.remove_all(directory)
|
||||||
|
defer _ = os2.remove_all(directory)
|
||||||
|
defer _ = os.remove(output)
|
||||||
|
testing.expect(t, os.make_directory(directory) == nil)
|
||||||
|
testing.expect(t, os.write_entire_file(main_path, transmute([]byte)strings.to_string(builder)))
|
||||||
|
testing.expect_value(t, compiler_core.compile_package(
|
||||||
|
directory, output, nil, target.DEFAULT, cimport.Options{}, ".", .Test,
|
||||||
|
), 0)
|
||||||
|
state := run_executable(output)
|
||||||
|
testing.expect_value(t, state.exit_code, 0)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,36 +1,5 @@
|
|||||||
import "../dep"
|
import "../dep"
|
||||||
|
|
||||||
hide Thing :: struct {
|
|
||||||
value i32
|
|
||||||
}
|
|
||||||
|
|
||||||
hide Local_Union :: union {
|
|
||||||
value i32
|
|
||||||
}
|
|
||||||
|
|
||||||
hide Local_Enum :: enum {
|
|
||||||
value
|
|
||||||
}
|
|
||||||
|
|
||||||
hide Local_Opaque :: opaque
|
|
||||||
hide Local_Distinct :: distinct i32
|
|
||||||
hide Local_Alias :: alias i32
|
|
||||||
|
|
||||||
hide value :: 2
|
|
||||||
hide mutable_value i32 = 2
|
|
||||||
|
|
||||||
hide helper func() i32 {
|
|
||||||
thing Thing = Thing { value = value }
|
|
||||||
return thing.value
|
|
||||||
}
|
|
||||||
|
|
||||||
hide local_foreign c_func() i32 {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
hide Local_C_Record :: c_struct {
|
|
||||||
value c_int
|
|
||||||
}
|
|
||||||
|
|
||||||
Box :: struct {
|
Box :: struct {
|
||||||
_value i32
|
_value i32
|
||||||
@@ -39,5 +8,6 @@ Box :: struct {
|
|||||||
from_b func(_input i32) i32 {
|
from_b func(_input i32) i32 {
|
||||||
_local Box = Box { _value = _input }
|
_local Box = Box { _value = _input }
|
||||||
record _C_Record = _C_Record { value = 0 }
|
record _C_Record = _C_Record { value = 0 }
|
||||||
return helper() + _local._value + _foreign() + i32(record.value) + dep._visible()
|
thing Thing = Thing { value = value }
|
||||||
|
return helper() + thing.value + _local._value + _foreign() + i32(record.value) + dep._visible()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user