diff --git a/spec/declaration/record_spec.lua b/spec/declaration/record_spec.lua index 3c58abed7..2f021a95f 100644 --- a/spec/declaration/record_spec.lua +++ b/spec/declaration/record_spec.lua @@ -702,7 +702,7 @@ for i, name in ipairs({"records", "arrayrecords"}) do end function Foo.new(): Foo - return setmetatable({}, Foo) -- typing of arguments is being very permissive here, may change in the future and require a cast + return setmetatable({}, Foo as metatable) end local foo = Foo.new() diff --git a/tl.lua b/tl.lua index 747e8e137..97e2bee52 100644 --- a/tl.lua +++ b/tl.lua @@ -1418,7 +1418,7 @@ end local function new_node(tokens, i, kind) local t = tokens[i] - return { y = t.y, x = t.x, tk = t.tk, kind = kind or t.kind } + return { y = t.y, x = t.x, tk = t.tk, kind = kind or (t.kind) } end local function a_type(t) @@ -7077,17 +7077,13 @@ tl.type_check = function(ast, opts) end return false, terr(t1, "cannot match against any alternatives of the polymorphic type") elseif t1.typename == "nominal" and t2.typename == "nominal" then - local same, err = are_same_nominals(t1, t2) - if same then - return true - end local t1r = resolve_tuple_and_nominal(t1) local t2r = resolve_tuple_and_nominal(t2) - if is_record_type(t1r) and is_record_type(t2r) then - return same, err - else + if t1r.typename == "union" or t2r.typename == "union" then return is_a(t1r, t2r, for_equality) end + + return are_same_nominals(t1, t2) elseif t1.typename == "enum" and t2.typename == "string" then local ok if for_equality then @@ -9088,7 +9084,7 @@ tl.type_check = function(ast, opts) local infertype = infertypes[i] local rt = resolve_tuple_and_nominal(t) - if rt.typename ~= "enum" and not same_type(t, infertype) then + if rt.typename ~= "enum" and (t.typename ~= "nominal" or rt.typename == "union") and not same_type(t, infertype) then add_var(where, var.tk, infer_at(where, infertype), "const", "narrowed_declaration") end end @@ -10064,6 +10060,14 @@ tl.type_check = function(ast, opts) end end + if orig_a.typename == "nominal" and orig_b.typename == "nominal" and not meta_on_operator then + if is_a(orig_a, orig_b) then + node.type = resolve_tuple(orig_a) + else + node_error(node, "cannot use operator '" .. node.op.op:gsub("%%", "%%%%") .. "' for distinct nominal types %s and %s", resolve_tuple(orig_a), resolve_tuple(orig_b)) + end + end + if types_op == numeric_binop or node.op.op == ".." then node.known = FACT_TRUTHY end diff --git a/tl.tl b/tl.tl index 730712d24..6b8b0005b 100644 --- a/tl.tl +++ b/tl.tl @@ -1418,7 +1418,7 @@ end local function new_node(tokens: {Token}, i: integer, kind: NodeKind): Node local t = tokens[i] - return { y = t.y, x = t.x, tk = t.tk, kind = kind or t.kind } + return { y = t.y, x = t.x, tk = t.tk, kind = kind or (t.kind as NodeKind) } end local function a_type(t: Type): Type @@ -7077,17 +7077,13 @@ tl.type_check = function(ast: Node, opts: TypeCheckOptions): Result, string end return false, terr(t1, "cannot match against any alternatives of the polymorphic type") elseif t1.typename == "nominal" and t2.typename == "nominal" then - local same, err = are_same_nominals(t1, t2) - if same then - return true - end local t1r = resolve_tuple_and_nominal(t1) local t2r = resolve_tuple_and_nominal(t2) - if is_record_type(t1r) and is_record_type(t2r) then - return same, err - else + if t1r.typename == "union" or t2r.typename == "union" then return is_a(t1r, t2r, for_equality) end + + return are_same_nominals(t1, t2) elseif t1.typename == "enum" and t2.typename == "string" then local ok: boolean if for_equality then @@ -9088,7 +9084,7 @@ tl.type_check = function(ast: Node, opts: TypeCheckOptions): Result, string local infertype = infertypes[i] local rt = resolve_tuple_and_nominal(t) - if rt.typename ~= "enum" and not same_type(t, infertype) then + if rt.typename ~= "enum" and (t.typename ~= "nominal" or rt.typename == "union") and not same_type(t, infertype) then add_var(where, var.tk, infer_at(where, infertype), "const", "narrowed_declaration") end end @@ -10064,6 +10060,14 @@ tl.type_check = function(ast: Node, opts: TypeCheckOptions): Result, string end end + if orig_a.typename == "nominal" and orig_b.typename == "nominal" and not meta_on_operator then + if is_a(orig_a, orig_b) then + node.type = resolve_tuple(orig_a) + else + node_error(node, "cannot use operator '" .. node.op.op:gsub("%%", "%%%%") .. "' for distinct nominal types %s and %s", resolve_tuple(orig_a), resolve_tuple(orig_b)) + end + end + if types_op == numeric_binop or node.op.op == ".." then node.known = FACT_TRUTHY end