Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A or B result is always inferred as A when A and B are records #712

Open
Aire-One opened this issue Oct 25, 2023 · 1 comment
Open

A or B result is always inferred as A when A and B are records #712

Aire-One opened this issue Oct 25, 2023 · 1 comment
Labels
semantics Unexpected or unsound behaviors

Comments

@Aire-One
Copy link

Aire-One commented Oct 25, 2023

Hello 👋

I think this issue is older, but with the recent nominal changes in record types, I have played a bit in my code base and stepped on that weird behavior. We can summarize the problem with the following code example :

https://teal-playground.netlify.app/?c=bG9jYWwgcmVjb3JkIEEKICAgZm9vOiBzdHJpbmcKZW5kCgpsb2NhbCByZWNvcmQgQgogICBiYXI6IHN0cmluZwplbmQKCmxvY2FsIGE6IEEKbG9jYWwgYjogQgoKbG9jYWwgcjEgPSBhIG9yIGIKcHJpbnQocjEuZm9vKQpwcmludChyMS5iYXIpCgpsb2NhbCByMiA9IGIgb3IgYQpwcmludChyMi5mb28pCnByaW50KHIyLmJhcik%3D

The issue still happens with #711
https://711--teal-playground-preview.netlify.app/?c=bG9jYWwgcmVjb3JkIEEKICAgZm9vOiBzdHJpbmcKZW5kCgpsb2NhbCByZWNvcmQgQgogICBiYXI6IHN0cmluZwplbmQKCmxvY2FsIGE6IEEKbG9jYWwgYjogQgoKbG9jYWwgcjEgPSBhIG9yIGIKcHJpbnQocjEuZm9vKQpwcmludChyMS5iYXIpCgpsb2NhbCByMiA9IGIgb3IgYQpwcmludChyMi5mb28pCnByaW50KHIyLmJhcik%3D

local record A
   foo: string
end

local record B
   bar: string
end

local a: A
local b: B

local r1 = a or b
print(r1.foo)
print(r1.bar) -- invalid key 'bar' in record 'r1' of type A

local r2 = b or a
print(r2.foo) -- invalid key 'foo' in record 'r2' of type B
print(r2.bar)

Notes :

In this example, we could say that Teal is smart and a or b is a a because the variable is supposed to be trusty since it's declared before, but :

  • In my code base, a and b are actually dictionaries of, respectively, { string : A } and { string : B }, and r is actually something like local r = a[target] or b[target] or default. So Teal really shouldn't take the wild guess r is a A.
  • All types in Teal are potentially nil, so there is no way to be sure a or b results in a since it's potentially nil which is a falsy value

I think r should be typed either, as a union of A and B (which is currently not allowed by Teal), or as the intersection of A and B (which is also something Teal doesn't allow). So I'm afraid I have found a worms' can 😅

@hishamhm hishamhm added the semantics Unexpected or unsound behaviors label Oct 25, 2023
@hishamhm
Copy link
Member

Hi! You do have a point. At least with the current behavior you do get an compile-time error when you try to use the value "inconsistently"...

It took me a bit to understand why this code was being accepted in the first place, but turns out that this works because the sets of fields in these records are disjoint (in plain English, because there are no incompatible fields among them). This is a rule that's in place to allow more lax parameter passing, in the absence of record subtyping: it's in practice a pretty lax form of structural checking.

I'll keep this issue open since this is one of the things I'm looking at, as I'm working on support for interfaces, which will bring proper record subtyping (yes, this is happening!)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
semantics Unexpected or unsound behaviors
Projects
None yet
Development

No branches or pull requests

2 participants