teal-language / tl

The compiler for Teal, a typed dialect of Lua
MIT License
2.12k stars 107 forks source link

Quoted string key in a record emits errors when the value is another record #665

Closed smiling-marx closed 1 year ago

smiling-marx commented 1 year ago

Hi, thank you for maintaining this project!

I've encountered an issue with typing a record and I can't tell if I'm doing it wrong or if this is just not supported. Can you please help me figure it out?

Expectations

Put the following code in a .d.tl file:

global record my_api_1
  ["unstable::stuff"]: number -- this works
end

global record my_api_2
  ["unstable::stuff"]: record -- this does not work
    foo: number
  end
end

I expected that to work. I want to provide type declarations for a table with such keys.

Actual behavior

VS Code gives me a red squiggle saying syntax error on the very last end.

I've tried the following alternatives:

global record my_api_2
  record ["unstable::stuff"] -- syntax error, expected identifier
    foo: number
  end
end

global record my_api_2
  record "unstable::stuff" -- syntax error, expected identifier
    foo: number
  end
end

global record my_api_2
  record unstable::stuff -- syntax error, expected identifier
    foo: number
  end
end

Environment

A folder with a single .d.tl file with the contents as above. The folder is opened in VS Code 1.78.2 with extension pdesaulniers.vscode-teal v0.8.3. tl.exe from release v1.15.2 is available via PATH and is sitting in the whole folder from the release. I'm on Windows 11 Pro.

smiling-marx commented 1 year ago

I've just found a workaround:

local record unstable_stuff
  foo: number
end

global record my_api
  ["unstable::stuff"]: unstable_stuff
end

It's more verbose but I can live with it if this is the intended solution.

hishamhm commented 1 year ago

@smiling-marx The alternatives you tried above don't work because in Teal, records are always nominal, not structural. So, your workaround is indeed the intended solution: to declare a field of a record type, that record type needs a name.

Record types can be nested, so this is also a possible solution:

global record MyApi
   local record UnstableStuff
      foo: number
   end

   ["unstable::stuff"]: UnstableStuff
end