From dab41556a9c9852cff2e6ad88d8647061ed6eb03 Mon Sep 17 00:00:00 2001 From: Hisham Muhammad Date: Fri, 3 Jan 2025 11:25:59 -0300 Subject: [PATCH] continue allowing plain `local` nominal aliases as types See #891 and test cases for description. --- spec/lang/declaration/local_spec.lua | 72 ++++++++++++++++++++++++++++ tl.lua | 16 ++++--- tl.tl | 17 ++++--- 3 files changed, 93 insertions(+), 12 deletions(-) diff --git a/spec/lang/declaration/local_spec.lua b/spec/lang/declaration/local_spec.lua index 737ce646..35eb1629 100644 --- a/spec/lang/declaration/local_spec.lua +++ b/spec/lang/declaration/local_spec.lua @@ -399,4 +399,76 @@ describe("local", function() ]], { { y = 5, x = 36, msg = "number of types exceeds number of variables" }, })) + + -- behaviors to be deprecated, once we can implement + -- proper detection and warnings. + describe("behavior to deprecate", function() + it("plain `local` aliasing of enums works (regression test for #891)", util.check([[ + local enum MyEnum1 + "A" + "B" + end + + -- this should require `local type`... + local MyEnum2 = MyEnum1 + + local record MyRecord + x: MyEnum2 + end + + local x: MyRecord = {x = "A"} + assert(x) + + local function f(): string, string + return "hello", "world" + end + + local x, y: integer, string, string = 1, "" + + local z, w = 0, f() + + z, w = 0, f() + ]])) + it("plain `local` aliasing of records works (regression test for #891)", util.check([[ + local record MyRecord1 end + + local MyRecord2 = MyRecord1 + + local record MyRecord + x: MyRecord2 + end + + local x: MyRecord = {x = {}} + assert(x) + ]])) + + it("plain `local` aliasing of records works across `require` (regression test for #891)", function() + util.mock_io(finally, { + ["foo.tl"] = [[ + local enum MyEnum + "A" + "B" + end + + return { MyEnum = MyEnum } + ]], + ["bar.tl"] = [[ + local foo = require "foo" + + local MyEnum = foo.MyEnum + + local record MyRecord + x: MyEnum + end + + local x: MyRecord = {x = "A"} + assert(x) + ]], + }) + local result, err = tl.process("bar.tl", assert(tl.init_env())) + assert.same(nil, err) + assert.same({}, result.syntax_errors) + assert.same({}, result.type_errors) + end) + end) end) diff --git a/tl.lua b/tl.lua index f5e95630..460b1408 100644 --- a/tl.lua +++ b/tl.lua @@ -7467,6 +7467,9 @@ do end for i = 2, #names do typ = unwrap_for_find_type(typ) + if typ == nil then + return nil + end local fields = typ.fields and typ.fields if not fields then @@ -7474,12 +7477,13 @@ do end typ = fields[names[i]] - if typ and typ.typename == "nominal" then - typ = typ.found - end - if typ == nil then - return nil - end + end + + if typ and typ.typename == "nominal" then + typ = typ.found + end + if typ == nil then + return nil end if typ.typename == "typedecl" then diff --git a/tl.tl b/tl.tl index 793da860..2856144a 100644 --- a/tl.tl +++ b/tl.tl @@ -7467,6 +7467,9 @@ do end for i = 2, #names do typ = unwrap_for_find_type(typ) + if typ == nil then + return nil + end local fields = typ is RecordLikeType and typ.fields if not fields then @@ -7474,12 +7477,14 @@ do end typ = fields[names[i]] - if typ and typ is NominalType then - typ = typ.found - end - if typ == nil then - return nil - end + end + + -- FIXME doing this at the and lets all nominals be used as types (see #891) + if typ and typ is NominalType then + typ = typ.found + end + if typ == nil then + return nil end if typ is TypeDeclType then