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

Interesting quirk, should be aware of #27

Open
getify opened this issue Feb 21, 2019 · 3 comments
Open

Interesting quirk, should be aware of #27

getify opened this issue Feb 21, 2019 · 3 comments
Labels
cool-example Something very interesting to look at

Comments

@getify
Copy link
Owner

getify commented Feb 21, 2019

There's nothing to do for this issue... I just want to document this quirk somewhere.

var x;
foo(x);
x = 3;
foo(x);
function foo(a = number) {}

Think carefully about this code. What do you expect to happen? Any errors?

This code requires a second pass, because of the foo(..) hoisting. On the first pass, x is initially implied as undef, then it's re-implied as number. So... on the second pass, would we expect the first foo(x) to throw an error or not?

I claim: yes it should throw an error. Even though x becomes number later in the code, at the moment we first see foo(x), it's still undef. On that second pass, we know foo(..) expects a number, so we should get an error about argument type mismatch.

Likewise, for the second foo(x)... since that one comes after a = 3, by that moment (even on the first pass), we know that foo(x) is trying to pass a number. So... since that's valid, no error should be thrown for that line.

The output (currently) is:

(pass 1) ------------------------
Implying x as inferred-type 'undef', at line 1, column 4
Re-implying x to inferred-type 'number', at line 3, column 0
Implying foo as inferred-type 'func', at line 5, column 0
Implying a as tagged-type 'number', at line 5, column 13
Function 'foo' signature: {"type":"func","params":[{"tagged":"number"}],"hasRestParam":false,"return":{"default":true,"inferred":"undef"}}, at line 5, column 0
(pass 2) ------------------------
Argument type mismatch: expected type 'number', but found type 'undef', at line 2, column 4
Function 'foo' signature: {"type":"func","params":[{"tagged":"number"}],"hasRestParam":false,"return":{"default":true,"inferred":"undef"}}, at line 5, column 0
@mraak
Copy link
Collaborator

mraak commented Feb 21, 2019

Definitely yes, should throw an error for first foo(x) and not for second. Just because the function is declared later in the code, it is declared with a certain signature that developer added with a purpose to be respected. The fact we're doing multi passes and that function is hoisted should not play a role, it is just a technical detail.

I actually think this is a very good example in how typl differs from other static type checkers and is suited to JS style.

@getify
Copy link
Owner Author

getify commented Feb 21, 2019

:)

@getify
Copy link
Owner Author

getify commented Feb 21, 2019

BTW, the reason why the second pass matters here is, if I wasn't careful to preserve this behavior, on the second pass x would just always be a number, and therefore neither of the function calls would report an error.

The way this works is, if an identifier is determined to be undef (on any pass), that is actually stored for that node. Subsequent passes do not update node types that are already assigned (even if undef), but they can update an unknown.

So, in the first pass, the x node in foo(x) is set to undef because at that moment, it hasn't been assigned any other type (and it's local to that scope, not a param). Then the x = 3 forces an update to the scope binding for x, setting it to number.

On the second pass, even though the scope binding for x is now number, the x in foo(x) is still undef from the first pass.

That's basically how Typl uses the lexical ordering to infer different types (specifically undef vs any other type) throughout the lifetime of that scope.

@mraak mraak added the cool-example Something very interesting to look at label Feb 23, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cool-example Something very interesting to look at
Projects
None yet
Development

No branches or pull requests

2 participants