check_repl ["id": "TYPE_GUARDS", "name": "Type identity, narrowing, and recovery across submissions", "steps": [
["let \$foo: any = 1024", "quiet", ""],
["echo (\$foo.type == Integer) \$foo.type", "output", "true Integer"],
["fn show(\$foo: any): String { match \$foo.type { Integer => { let \$n: Integer = \$foo; \"int\" } Float => { let \$n: Float = \$foo; \"float\" } _ => { \"other\" } } }", "quiet", ""],
["echo (show \$foo) (show 1.0) (show \"s\")", "output", "int float other"],
["fn wrong(\$foo: any) { if \$foo.type == Integer && \$foo == 1024 { let \$s: String = \$foo } }", "error", "Expected String, got Integer"],
["echo (show \$foo)", "output", "int"],
["type Count = Integer; let \$count: Count = 7; let \$old_type = \$count.type", "quiet", ""],
["echo (\$count.type == Count) (\$count.type == Integer) (\$old_type.type == Type)", "output", "true false true"],
["type Count = Float; let \$new: Count = 7", "quiet", ""],
["echo (\$count.type == Count) (\$new.type == Count) (\$old_type == \$count.type)", "output", "false true true"],
["let \$old = fn (\$v: any) { \$v.type == Count }", "quiet", ""],
["type Count = String", "quiet", ""],
["echo (\$old \$new) (\$new.type == Count)", "output", "true false"],
["let \$t: Type = Integer; let \$types: [Type] = [Integer, Float]", "quiet", ""],
["echo (\$t == \$foo.type) \$types[0]", "output", "true Integer"],
["\$t = \"Integer\"", "error", "Expected Type"],
["echo (\$t == \$foo.type)", "output", "true"],
["\$foo.type = String", "error", "read-only"],
["echo (\$foo.type == Integer)", "output", "true"],
["\$foo = \"text\"", "quiet", ""],
["echo (show \$foo) (\$foo.type == String)", "output", "other true"],
["fn f(\$v: Integer | String): String { if \$v.type == Integer { \"int\" } else { \$v } }", "quiet", ""],
["echo (f 7) (f \"text\")", "output", "int text"],
["fn bad(\$v: Integer | String): Integer { match \$v.type { Integer => { 0 } _ => { \$v } } }", "error", "Expected Integer, got String"],
["echo (f \"ok\")", "output", "ok"],
["struct Item { n: Integer }; let \$item: any = Item(n: 1)", "quiet", ""],
["fn bad(\$v: any) { if \$v.type == Item && \$v.absent == 1 { () } }", "error", "Cannot access field 'absent' on Item"],
["if \$item.type == Item { echo \$item.n }", "output", "1"],
["type Count = Integer; fn broken(\$v: any) { if \$v.type == Integer { let \$s: String = \$v } }", "error", "Expected String, got Integer"],
["let \$c: Count = \"still string\"", "quiet", ""],
["echo String(\$c)", "output", "still string"],
["let \$keys: [Type: String] = [Integer: \"int\", Float: \"float\"]", "quiet", ""],
["echo \$keys[(7).type] \$keys[(1.0).type]", "output", "int float"],
["let \$missing: Type", "error", "requires an initializer"],
["echo recovered", "output", "recovered"],
["let \$foo: any = 7; let \$read = fn () { if \$foo.type == Integer { let \$n: Integer = \$foo; \$n } else { 0 } }", "quiet", ""],
["echo (\$read)", "output", "7"],
["\$foo = \"s\"", "quiet", ""],
["echo (\$read)", "output", "0"],
["struct A { a: Integer }; struct B { b: String }; let \$state: any = A(a: 1); fn change(): Boolean { \$state = B(b: \"new\"); true }", "quiet", ""],
["if \$state.type == A && (change) { echo \$state.b }", "output", "new"],
], "exit": 0]