From 6117c8c2e023cfe9828d972fa91d985e0bda9e8b Mon Sep 17 00:00:00 2001 From: Hisham Muhammad Date: Fri, 20 Sep 2024 23:59:49 -0300 Subject: [PATCH] types: reports record functions in record field list Also, strip typedecls from type report, and represent records in the "str" field by their declared name. Thanks @pdesaulniers for the report! --- spec/api/get_types_spec.lua | 28 ++++++++++++++++++++++++++++ tl.lua | 15 +++++++++++++-- tl.tl | 15 +++++++++++++-- 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/spec/api/get_types_spec.lua b/spec/api/get_types_spec.lua index a36b5373e..d2aea26d1 100644 --- a/spec/api/get_types_spec.lua +++ b/spec/api/get_types_spec.lua @@ -33,4 +33,32 @@ describe("tl.get_types", function() local type_at_y_x = tr.by_pos[""][y][x] assert(tr.types[type_at_y_x].str == "function(string)") end) + + it("reports record functions in record field list", function() + local env = tl.init_env() + env.report_types = true + local result = assert(tl.check_string([[ + local record Point + x: number + y: number + end + + function Point:init(x: number, y: number) + self.x = x + self.y = y + end + ]], env)) + + local tr, trenv = tl.get_types(result) + local y = 1 + local x = 10 + local type_at_y_x = tr.by_pos[""][y][x] + assert(tr.types[type_at_y_x].str == "Point") + local fields = {} + for k, _ in pairs(tr.types[type_at_y_x].fields) do + table.insert(fields, k) + end + table.sort(fields) + assert.same(fields, {"init", "x", "y"}) + end) end) diff --git a/tl.lua b/tl.lua index f082dae71..8e9f08059 100644 --- a/tl.lua +++ b/tl.lua @@ -5860,7 +5860,7 @@ function TypeReporter:get_typenum(t) end if rt.typename == "typedecl" then - rt = rt.def + return self:get_typenum(rt.def) end local ti = { @@ -5916,6 +5916,13 @@ function TypeReporter:get_typenum(t) return n end +function TypeReporter:add_field(rtype, fname, ftype) + local n = self:get_typenum(rtype) + local ti = self.tr.types[n] + assert(ti.fields) + ti.fields[fname] = self:get_typenum(ftype) +end + @@ -6758,7 +6765,7 @@ local function show_type_base(t, short, seen) elseif t.typename == "enum" then return t.declname or "enum" elseif t.fields then - return short and t.typename or t.typename .. show_fields(t, show) + return short and (t.declname or t.typename) or t.typename .. show_fields(t, show) elseif t.typename == "function" then local out = { "function" } if t.typeargs then @@ -11981,6 +11988,10 @@ self:expand_type(node, values, elements) }) if self.feat_lax or rtype == open_t then rtype.fields[node.name.tk] = fn_type table.insert(rtype.field_order, node.name.tk) + + if self.collector then + self.env.reporter:add_field(rtype, node.name.tk, fn_type) + end else self.errs:add(node, "cannot add undeclared function '" .. node.name.tk .. "' outside of the scope where '" .. owner_name .. "' was originally declared") return diff --git a/tl.tl b/tl.tl index 1b3b28fd7..580e213fb 100644 --- a/tl.tl +++ b/tl.tl @@ -5860,7 +5860,7 @@ function TypeReporter:get_typenum(t: Type): integer end if rt is TypeDeclType then - rt = rt.def + return self:get_typenum(rt.def) end local ti: TypeInfo = { @@ -5916,6 +5916,13 @@ function TypeReporter:get_typenum(t: Type): integer return n end +function TypeReporter:add_field(rtype: RecordLikeType, fname: string, ftype: Type) + local n = self:get_typenum(rtype) + local ti = self.tr.types[n] + assert(ti.fields) + ti.fields[fname] = self:get_typenum(ftype) +end + local record TypeCollector record Symbol x: integer @@ -6758,7 +6765,7 @@ local function show_type_base(t: Type, short: boolean, seen: {Type:string}): str elseif t is EnumType then return t.declname or "enum" elseif t is RecordLikeType then - return short and t.typename or t.typename .. show_fields(t, show) + return short and (t.declname or t.typename) or t.typename .. show_fields(t, show) elseif t is FunctionType then local out: {string} = {"function"} if t.typeargs then @@ -11981,6 +11988,10 @@ do if self.feat_lax or rtype == open_t then rtype.fields[node.name.tk] = fn_type table.insert(rtype.field_order, node.name.tk) + + if self.collector then + self.env.reporter:add_field(rtype, node.name.tk, fn_type) + end else self.errs:add(node, "cannot add undeclared function '" .. node.name.tk .. "' outside of the scope where '" .. owner_name .. "' was originally declared") return