remove undefined global constraint
This commit is contained in:
+1
-1
@@ -9,7 +9,7 @@ roadmap and milestone history.
|
|||||||
|
|
||||||
- newline-terminated statements and `#` comments
|
- newline-terminated statements and `#` comments
|
||||||
- immutable `::` bindings, typed mutable `=` locals/globals, and `_` sinks
|
- immutable `::` bindings, typed mutable `=` locals/globals, and `_` sinks
|
||||||
- immutable package globals, mutable runtime globals, function-local mutable locals, and mutable local declarations initialized with `undefined`
|
- immutable package globals, mutable runtime globals, function-local mutable locals, and mutable declarations initialized with `undefined`
|
||||||
- package-level functions, globals, native type declarations, and `Name :: alias T`
|
- package-level functions, globals, native type declarations, and `Name :: alias T`
|
||||||
- directory packages with merged declarations
|
- directory packages with merged declarations
|
||||||
- file-local relative imports, import aliases, and qualified member access
|
- file-local relative imports, import aliases, and qualified member access
|
||||||
|
|||||||
@@ -177,7 +177,7 @@
|
|||||||
- future direction: generalize toward Zig-style arbitrary pointer-result casts once casts have a broader result-type story
|
- future direction: generalize toward Zig-style arbitrary pointer-result casts once casts have a broader result-type story
|
||||||
|
|
||||||
12. `undefined` as inspired by zig (implemented):
|
12. `undefined` as inspired by zig (implemented):
|
||||||
- allow mutable local declarations with `undefined`
|
- allow mutable local and global declarations with `undefined`
|
||||||
- undefined values are assigned a poison value (0xaa...)
|
- undefined values are assigned a poison value (0xaa...)
|
||||||
- allows for something like:
|
- allows for something like:
|
||||||
```
|
```
|
||||||
@@ -696,6 +696,7 @@
|
|||||||
and inferred array counts may resolve through the existing inference fixpoint, but
|
and inferred array counts may resolve through the existing inference fixpoint, but
|
||||||
the final type must be concrete runtime storage
|
the final type must be concrete runtime storage
|
||||||
- emit source-defined mutable globals as writable globals, not constants
|
- emit source-defined mutable globals as writable globals, not constants
|
||||||
|
- allow `undefined` initializers for runtime storage initialized explicitly by a function
|
||||||
- allow assignment, address-taking, field/index mutation, and pointer passing under
|
- allow assignment, address-taking, field/index mutation, and pointer passing under
|
||||||
the same mutability rules as other writable locations
|
the same mutability rules as other writable locations
|
||||||
- keep mutable globals invalid in comptime evaluation; `$global_var` and writes from
|
- keep mutable globals invalid in comptime evaluation; `$global_var` and writes from
|
||||||
|
|||||||
@@ -7891,7 +7891,7 @@ build_compound_expr :: proc(
|
|||||||
id := source.add(
|
id := source.add(
|
||||||
checker.diagnostics,
|
checker.diagnostics,
|
||||||
expr.span,
|
expr.span,
|
||||||
"'undefined' is only valid as a mutable local declaration initializer",
|
"'undefined' is only valid as a mutable declaration initializer",
|
||||||
)
|
)
|
||||||
return invalid_hir_expr(checker, expr.span, id, expected)
|
return invalid_hir_expr(checker, expr.span, id, expected)
|
||||||
case .Enum_Literal:
|
case .Enum_Literal:
|
||||||
@@ -13686,7 +13686,20 @@ build_globals :: proc(checker: ^Checker) {
|
|||||||
is_runtime_type(checker, checker.global_types[global_index]) {
|
is_runtime_type(checker, checker.global_types[global_index]) {
|
||||||
expected = checker.global_types[global_index]
|
expected = checker.global_types[global_index]
|
||||||
}
|
}
|
||||||
expr := build_expr(checker, global.expr, nil, &dependencies, &calls, expected, global.pkg, global.file)
|
expr := hir.INVALID_EXPR
|
||||||
|
if !global.immutable && is_undefined_expr(checker, global.expr) {
|
||||||
|
expr = add_hir_expr(checker, hir.Expr{
|
||||||
|
kind=.Undefined,
|
||||||
|
span=checker.ast_module.exprs[global.expr].span,
|
||||||
|
type=checker.global_types[global_index],
|
||||||
|
target=hir.INVALID_REF,
|
||||||
|
left=hir.INVALID_EXPR,
|
||||||
|
right=hir.INVALID_EXPR,
|
||||||
|
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
expr = build_expr(checker, global.expr, nil, &dependencies, &calls, expected, global.pkg, global.file)
|
||||||
|
}
|
||||||
global_type := checker.global_types[global_index]
|
global_type := checker.global_types[global_index]
|
||||||
if is_runtime_type(checker, checker.global_types[global_index]) {
|
if is_runtime_type(checker, checker.global_types[global_index]) {
|
||||||
expr = coerce_expr(checker, expr, checker.global_types[global_index], global.span)
|
expr = coerce_expr(checker, expr, checker.global_types[global_index], global.span)
|
||||||
@@ -13713,17 +13726,6 @@ build_globals :: proc(checker: ^Checker) {
|
|||||||
global_type = constraint_recovery_type(checker, declared)
|
global_type = constraint_recovery_type(checker, declared)
|
||||||
expr = invalid_hir_expr(checker, global.span, diagnostic, global_type)
|
expr = invalid_hir_expr(checker, global.span, diagnostic, global_type)
|
||||||
}
|
}
|
||||||
if !global.immutable && is_undefined_expr(checker, global.expr) {
|
|
||||||
diagnostic = source.add(
|
|
||||||
checker.diagnostics,
|
|
||||||
global.span,
|
|
||||||
"'undefined' is only valid as a mutable local declaration initializer",
|
|
||||||
)
|
|
||||||
if !is_runtime_type(checker, global_type) {
|
|
||||||
global_type = types.I64
|
|
||||||
}
|
|
||||||
expr = invalid_hir_expr(checker, global.span, diagnostic, global_type)
|
|
||||||
}
|
|
||||||
if diagnostic == source.INVALID_DIAGNOSTIC && !is_runtime_type(checker, global_type) {
|
if diagnostic == source.INVALID_DIAGNOSTIC && !is_runtime_type(checker, global_type) {
|
||||||
if types.is_comptime_only(global_type, &checker.module.types) ||
|
if types.is_comptime_only(global_type, &checker.module.types) ||
|
||||||
types.is_comptime_only(declared, &checker.module.types) {
|
types.is_comptime_only(declared, &checker.module.types) {
|
||||||
|
|||||||
+11
-6
@@ -9211,6 +9211,7 @@ counter int = 0
|
|||||||
ratio float = 1
|
ratio float = 1
|
||||||
span range = 0..2
|
span range = 0..2
|
||||||
point Point = Point { x = 1 }
|
point Point = Point { x = 1 }
|
||||||
|
unset Point = undefined
|
||||||
values [_]mut i32 = [10, 20]
|
values [_]mut i32 = [10, 20]
|
||||||
main func() void {
|
main func() void {
|
||||||
counter = 1
|
counter = 1
|
||||||
@@ -9239,8 +9240,9 @@ main func() void {
|
|||||||
found_counter := false
|
found_counter := false
|
||||||
found_ratio := false
|
found_ratio := false
|
||||||
found_span := false
|
found_span := false
|
||||||
|
found_unset := false
|
||||||
found_values := false
|
found_values := false
|
||||||
for global in hir_module.globals {
|
for global, global_index in hir_module.globals {
|
||||||
name := symbol.resolve(&symbols, global.name)
|
name := symbol.resolve(&symbols, global.name)
|
||||||
if name == "counter" {
|
if name == "counter" {
|
||||||
found_counter = global.writable && !global.is_static && types.equal(global.type, types.I32)
|
found_counter = global.writable && !global.is_static && types.equal(global.type, types.I32)
|
||||||
@@ -9248,6 +9250,12 @@ main func() void {
|
|||||||
found_ratio = global.writable && !global.is_static && types.equal(global.type, types.F64)
|
found_ratio = global.writable && !global.is_static && types.equal(global.type, types.F64)
|
||||||
} else if name == "span" {
|
} else if name == "span" {
|
||||||
found_span = global.writable && !global.is_static && types.is_range(global.type, &hir_module.types)
|
found_span = global.writable && !global.is_static && types.is_range(global.type, &hir_module.types)
|
||||||
|
} else if name == "unset" {
|
||||||
|
found_unset = global.writable &&
|
||||||
|
!global.is_static &&
|
||||||
|
hir_module.exprs[global.expr].kind == .Undefined &&
|
||||||
|
len(ir_module.globals[global_index].initializer) > 0 &&
|
||||||
|
ir_module.globals[global_index].initializer[0].op == .Poison
|
||||||
} else if name == "values" {
|
} else if name == "values" {
|
||||||
item, ok := types.node(&hir_module.types, global.type)
|
item, ok := types.node(&hir_module.types, global.type)
|
||||||
found_values = global.writable && !global.is_static && ok && item.kind == .Array && item.count == 2
|
found_values = global.writable && !global.is_static && ok && item.kind == .Array && item.count == 2
|
||||||
@@ -9256,6 +9264,7 @@ main func() void {
|
|||||||
testing.expect(t, found_counter)
|
testing.expect(t, found_counter)
|
||||||
testing.expect(t, found_ratio)
|
testing.expect(t, found_ratio)
|
||||||
testing.expect(t, found_span)
|
testing.expect(t, found_span)
|
||||||
|
testing.expect(t, found_unset)
|
||||||
testing.expect(t, found_values)
|
testing.expect(t, found_values)
|
||||||
testing.expect(t, strings.contains(llvm_text, "internal global"))
|
testing.expect(t, strings.contains(llvm_text, "internal global"))
|
||||||
testing.expect(t, !strings.contains(llvm_text, "internal constant i32 0"))
|
testing.expect(t, !strings.contains(llvm_text, "internal constant i32 0"))
|
||||||
@@ -9267,7 +9276,6 @@ mutable_global_diagnostics_and_no_shadowing :: proc(t: ^testing.T) {
|
|||||||
OtherID :: distinct i32
|
OtherID :: distinct i32
|
||||||
ID i32 = 0
|
ID i32 = 0
|
||||||
counter = 0
|
counter = 0
|
||||||
bad i32 = undefined
|
|
||||||
runtime i32 = 1
|
runtime i32 = 1
|
||||||
immutable :: 1
|
immutable :: 1
|
||||||
foo func(foo i32) void {}
|
foo func(foo i32) void {}
|
||||||
@@ -9304,7 +9312,6 @@ main func() void {
|
|||||||
defer hir.destroy_module(&hir_module)
|
defer hir.destroy_module(&hir_module)
|
||||||
|
|
||||||
missing_type := false
|
missing_type := false
|
||||||
undefined_global := false
|
|
||||||
not_comptime := false
|
not_comptime := false
|
||||||
immutable_write := false
|
immutable_write := false
|
||||||
global_type_shadow := false
|
global_type_shadow := false
|
||||||
@@ -9317,7 +9324,6 @@ main func() void {
|
|||||||
value_label_shadow := false
|
value_label_shadow := false
|
||||||
for diagnostic in diagnostics.items {
|
for diagnostic in diagnostics.items {
|
||||||
missing_type = missing_type || strings.contains(diagnostic.message, "mutable global 'counter' requires a type annotation")
|
missing_type = missing_type || strings.contains(diagnostic.message, "mutable global 'counter' requires a type annotation")
|
||||||
undefined_global = undefined_global || strings.contains(diagnostic.message, "'undefined' is only valid as a mutable local declaration initializer")
|
|
||||||
not_comptime = not_comptime || strings.contains(diagnostic.message, "global 'runtime' is not comptime-known")
|
not_comptime = not_comptime || strings.contains(diagnostic.message, "global 'runtime' is not comptime-known")
|
||||||
immutable_write = immutable_write || strings.contains(diagnostic.message, "assignment target is not writable")
|
immutable_write = immutable_write || strings.contains(diagnostic.message, "assignment target is not writable")
|
||||||
global_type_shadow = global_type_shadow || strings.contains(diagnostic.message, "global 'ID' shadows visible type")
|
global_type_shadow = global_type_shadow || strings.contains(diagnostic.message, "global 'ID' shadows visible type")
|
||||||
@@ -9330,7 +9336,6 @@ main func() void {
|
|||||||
value_label_shadow = value_label_shadow || strings.contains(diagnostic.message, "local 'value_label' shadows visible label")
|
value_label_shadow = value_label_shadow || strings.contains(diagnostic.message, "local 'value_label' shadows visible label")
|
||||||
}
|
}
|
||||||
testing.expect(t, missing_type)
|
testing.expect(t, missing_type)
|
||||||
testing.expect(t, undefined_global)
|
|
||||||
testing.expect(t, not_comptime)
|
testing.expect(t, not_comptime)
|
||||||
testing.expect(t, immutable_write)
|
testing.expect(t, immutable_write)
|
||||||
testing.expect(t, global_type_shadow)
|
testing.expect(t, global_type_shadow)
|
||||||
@@ -11914,7 +11919,7 @@ main func() void {
|
|||||||
for diagnostic in diagnostics.items {
|
for diagnostic in diagnostics.items {
|
||||||
immutable_count += 1 if strings.contains(diagnostic.message, "'undefined' requires a mutable local declaration") else 0
|
immutable_count += 1 if strings.contains(diagnostic.message, "'undefined' requires a mutable local declaration") else 0
|
||||||
found_unresolved = found_unresolved || strings.contains(diagnostic.message, "could not infer a concrete type for local 'unresolved'")
|
found_unresolved = found_unresolved || strings.contains(diagnostic.message, "could not infer a concrete type for local 'unresolved'")
|
||||||
found_assignment = found_assignment || strings.contains(diagnostic.message, "'undefined' is only valid as a mutable local declaration initializer")
|
found_assignment = found_assignment || strings.contains(diagnostic.message, "'undefined' is only valid as a mutable declaration initializer")
|
||||||
found_incompatible = found_incompatible || strings.contains(diagnostic.message, "cannot implicitly convert f64 to i8")
|
found_incompatible = found_incompatible || strings.contains(diagnostic.message, "cannot implicitly convert f64 to i8")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user