mutable decl syntax change
This commit is contained in:
@@ -5952,7 +5952,7 @@ infer_statements :: proc(
|
||||
#partial switch statement.kind {
|
||||
case .Declaration:
|
||||
if statement.expr == ast.INVALID_EXPR {
|
||||
// Value block (`x :: { ... yield v }` / `x T = { ... }`): register the
|
||||
// Value block (`x :: { ... yield v }` / `x T := { ... }`): register the
|
||||
// binding (its declared type when annotated, else left open) and walk
|
||||
// the block body. The build pass resolves the yielded value's type
|
||||
// independently — value blocks don't join the demand fixpoint.
|
||||
@@ -6026,7 +6026,7 @@ infer_statements :: proc(
|
||||
continue
|
||||
}
|
||||
expected_assignment := types.INVALID
|
||||
if statement.target != ast.INVALID_EXPR {
|
||||
if statement.target != ast.INVALID_EXPR && !symbol.is_valid(statement.name) {
|
||||
expected_assignment = infer_expr(checker, statement.target, locals^[:], pkg, file, demanded, local_types)
|
||||
target_expr := checker.ast_module.exprs[statement.target]
|
||||
if target_expr.kind == .Name && !symbol.is_valid(target_expr.qualifier) {
|
||||
@@ -6055,7 +6055,7 @@ infer_statements :: proc(
|
||||
// type onto open-constant operands and poison their family. Operands of an
|
||||
// arithmetic RHS resolve from their own authoritative uses.
|
||||
rhs_is_arith := is_arith_kind(checker.ast_module.exprs[statement.expr].kind)
|
||||
if statement.target != ast.INVALID_EXPR {
|
||||
if statement.target != ast.INVALID_EXPR && !symbol.is_valid(statement.name) {
|
||||
target_type := expected_assignment
|
||||
target_expr := checker.ast_module.exprs[statement.target]
|
||||
if target_expr.kind == .Name && !symbol.is_valid(target_expr.qualifier) {
|
||||
@@ -10922,7 +10922,7 @@ build_block :: proc(
|
||||
}
|
||||
switch statement.kind {
|
||||
case .Declaration:
|
||||
// A value block (`x :: { ... yield v }` / `x T = { ... }`): the parser
|
||||
// A value block (`x :: { ... yield v }` / `x T := { ... }`): the parser
|
||||
// leaves `expr` invalid and stashes the block in `body`. Build it, then
|
||||
// declare the local from the yielded value (its type for an untyped `::`).
|
||||
if statement.expr == ast.INVALID_EXPR {
|
||||
@@ -11123,7 +11123,7 @@ build_block :: proc(
|
||||
ctx.problematic^ = ctx.problematic^ || checker.module.exprs[value].kind == .Invalid
|
||||
}
|
||||
case .Assignment:
|
||||
if statement.target != ast.INVALID_EXPR {
|
||||
if statement.target != ast.INVALID_EXPR && !symbol.is_valid(statement.name) {
|
||||
target_expr := build_expr(
|
||||
checker, statement.target, ctx.locals^[:], ctx.global_reads, ctx.calls,
|
||||
types.INVALID, ctx.pkg, ctx.file,
|
||||
@@ -14349,18 +14349,6 @@ build_globals :: proc(checker: ^Checker) {
|
||||
)
|
||||
expr = invalid_hir_expr(checker, global.span, diagnostic)
|
||||
}
|
||||
if !global.immutable {
|
||||
if !types.is_valid(global.type) {
|
||||
diagnostic = source.addf(
|
||||
checker.diagnostics,
|
||||
global.span,
|
||||
"mutable global '%s' requires a type annotation",
|
||||
symbol_text(checker, global.name),
|
||||
)
|
||||
global_type = types.I64
|
||||
expr = invalid_hir_expr(checker, global.span, diagnostic, global_type)
|
||||
}
|
||||
}
|
||||
static_value, is_static := static_integer_value(&checker.module, expr)
|
||||
is_static = is_static && diagnostic == source.INVALID_DIAGNOSTIC && global.immutable
|
||||
_ = hir.global_id(len(checker.module.globals))
|
||||
|
||||
@@ -133,9 +133,16 @@ lex :: proc(
|
||||
case ':':
|
||||
start := cursor
|
||||
cursor += 1
|
||||
if cursor < len(bytes) && bytes[cursor] == ':' {
|
||||
cursor += 1
|
||||
append_token(&stream, source_file, .Colon_Colon, start, cursor)
|
||||
if cursor < len(bytes) {
|
||||
if bytes[cursor] == ':' {
|
||||
cursor += 1
|
||||
append_token(&stream, source_file, .Colon_Colon, start, cursor)
|
||||
} else if bytes[cursor] == '=' {
|
||||
cursor += 1
|
||||
append_token(&stream, source_file, .Colon_Equal, start, cursor)
|
||||
} else {
|
||||
append_token(&stream, source_file, .Colon, start, cursor)
|
||||
}
|
||||
} else {
|
||||
append_token(&stream, source_file, .Colon, start, cursor)
|
||||
}
|
||||
|
||||
@@ -1868,15 +1868,35 @@ parse_statement :: proc(parser: ^Parser) -> ast.Stmt_Id {
|
||||
had_type = true
|
||||
}
|
||||
operator := current(parser)
|
||||
if operator.kind == .Colon_Colon || operator.kind == .Equal {
|
||||
if had_type && operator.kind == .Equal {
|
||||
diagnostic := source.add(
|
||||
parser.diagnostics,
|
||||
operator.span,
|
||||
"mutable declarations use ':=' instead of '='",
|
||||
)
|
||||
for current(parser).kind != .Newline &&
|
||||
current(parser).kind != .Right_Brace &&
|
||||
current(parser).kind != .Eof {
|
||||
advance(parser)
|
||||
}
|
||||
id := ast.stmt_id(len(parser.module.statements))
|
||||
append(&parser.module.statements, ast.Stmt{
|
||||
kind=.Invalid,
|
||||
span=span_from(name.span, operator.span),
|
||||
expr=ast.INVALID_EXPR,
|
||||
diagnostic=diagnostic,
|
||||
})
|
||||
return id
|
||||
}
|
||||
is_sink := name.kind == .Underscore && operator.kind == .Equal
|
||||
if operator.kind == .Colon_Colon || operator.kind == .Colon_Equal || is_sink {
|
||||
advance(parser)
|
||||
skip_newlines(parser)
|
||||
kind := ast.Stmt_Kind.Assignment
|
||||
immutable := false
|
||||
if operator.kind == .Colon_Colon || had_type {
|
||||
kind = .Declaration
|
||||
immutable = operator.kind == .Colon_Colon
|
||||
kind := ast.Stmt_Kind.Declaration
|
||||
if is_sink {
|
||||
kind = .Assignment
|
||||
}
|
||||
immutable := operator.kind == .Colon_Colon
|
||||
// A labeled value block (`x :: blk: { … yield :blk v }`): the label lets a
|
||||
// `yield :blk` exit the block past a nested `if`. Block-init body + label.
|
||||
if current(parser).kind == .Identifier && peek(parser).kind == .Colon {
|
||||
@@ -1954,6 +1974,11 @@ parse_statement :: proc(parser: ^Parser) -> ast.Stmt_Id {
|
||||
}
|
||||
|
||||
expr := parse_expression(parser)
|
||||
assignment_name := symbol.INVALID
|
||||
target_expr := parser.module.exprs[expr]
|
||||
if target_expr.kind == .Name && !symbol.is_valid(target_expr.qualifier) {
|
||||
assignment_name = target_expr.name
|
||||
}
|
||||
if _, ok := allow(parser, .Equal); ok {
|
||||
skip_newlines(parser)
|
||||
// A labeled value block assigned to a complex target (`a[i] = blk: { … }`).
|
||||
@@ -1964,6 +1989,7 @@ parse_statement :: proc(parser: ^Parser) -> ast.Stmt_Id {
|
||||
append(&parser.module.statements, ast.Stmt{
|
||||
kind=.Assignment,
|
||||
span=span_from(parser.module.exprs[expr].span, previous(parser).span),
|
||||
name=assignment_name,
|
||||
target=expr,
|
||||
label=label,
|
||||
expr=ast.INVALID_EXPR,
|
||||
@@ -1980,6 +2006,7 @@ parse_statement :: proc(parser: ^Parser) -> ast.Stmt_Id {
|
||||
append(&parser.module.statements, ast.Stmt{
|
||||
kind=.Assignment,
|
||||
span=span_from(parser.module.exprs[expr].span, brace.span),
|
||||
name=assignment_name,
|
||||
target=expr,
|
||||
expr=ast.INVALID_EXPR,
|
||||
body=body,
|
||||
@@ -1995,6 +2022,7 @@ parse_statement :: proc(parser: ^Parser) -> ast.Stmt_Id {
|
||||
append(&parser.module.statements, ast.Stmt{
|
||||
kind=.Assignment,
|
||||
span=span_from(parser.module.exprs[expr].span, previous(parser).span),
|
||||
name=assignment_name,
|
||||
target=expr,
|
||||
value_control_flow=true,
|
||||
expr=ast.INVALID_EXPR,
|
||||
@@ -2008,6 +2036,7 @@ parse_statement :: proc(parser: ^Parser) -> ast.Stmt_Id {
|
||||
append(&parser.module.statements, ast.Stmt{
|
||||
kind=.Assignment,
|
||||
span=span_from(parser.module.exprs[expr].span, parser.module.exprs[value].span),
|
||||
name=assignment_name,
|
||||
target=expr,
|
||||
expr=value,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
@@ -3312,8 +3341,16 @@ parse_top_level :: proc(parser: ^Parser) {
|
||||
type_syntax = parse_type(parser)
|
||||
}
|
||||
operator := current(parser)
|
||||
if operator.kind != .Colon_Colon && operator.kind != .Equal {
|
||||
source.add(parser.diagnostics, operator.span, "expected '::' or '=' after top-level name")
|
||||
if operator.kind == .Equal {
|
||||
source.add(parser.diagnostics, operator.span, "mutable declarations use ':=' instead of '='")
|
||||
for current(parser).kind != .Newline && current(parser).kind != .Eof {
|
||||
advance(parser)
|
||||
}
|
||||
_ = finish_statement(parser)
|
||||
return
|
||||
}
|
||||
if operator.kind != .Colon_Colon && operator.kind != .Colon_Equal {
|
||||
source.add(parser.diagnostics, operator.span, "expected '::' or ':=' after top-level name")
|
||||
_ = finish_statement(parser)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ append_runner :: proc(
|
||||
fmt.sbprintf(&builder, "%s.%s() catch |_| ", alias, symbol.resolve(symbols, test.name))
|
||||
strings.write_string(&builder, "{\n\t\treturn .expectation_failed\n\t}\n}\n\n")
|
||||
}
|
||||
strings.write_string(&builder, "main func() i32 {\n\tfailed i32 = 0\n")
|
||||
strings.write_string(&builder, "main func() i32 {\n\tfailed i32 := 0\n")
|
||||
for entry, index in tests {
|
||||
test_id := entry.function
|
||||
test := module.functions[test_id]
|
||||
|
||||
@@ -16,6 +16,7 @@ Kind :: enum u8 {
|
||||
Underscore,
|
||||
Colon,
|
||||
Colon_Colon,
|
||||
Colon_Equal,
|
||||
Equal,
|
||||
Equal_Equal,
|
||||
Bang,
|
||||
|
||||
Reference in New Issue
Block a user