-
Notifications
You must be signed in to change notification settings - Fork 35
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
Use Local Type Inference approach to typecheck polymorphic calls #564
Commits on Apr 19, 2024
-
Allow subst_ty/2 to take empty substitutions
The function allows it, only the spec didn't.
Configuration menu - View commit details
-
Copy full SHA for 16ad12e - Browse repository at this point
Copy the full SHA 16ad12eView commit details
Commits on Apr 22, 2024
-
Merge intersection function types using inner unions
Consider a function spec: -spec negate(bool()) -> bool(); (integer()) -> integer(). Sometimes, we want to make a single function type out of these two clauses. Using an outer union like fun((bool()) -> bool()) | fun((integer()) -> integer()) leads to a loss of precision, because this type says that we either have a function that can take a bool, or we have a function that can take an integer (and we do not know which case it is). This means that we cannot apply a function of this type to anything unless we assert type or something like that. But we know for sure that it can take both, bools and integers! Therefore, using an inner union like fun((bool() | integer()) -> bool() | integer()) seems better to me as this way we know that it can take both. Of course, an ideal solution would be to use intersection types like fun((bool()) -> bool()) & fun((integer()) -> integer()), but Erlang doesn't have them in its syntax and so don't we in Gradualizer.
Configuration menu - View commit details
-
Copy full SHA for e9a0afa - Browse repository at this point
Copy the full SHA e9a0afaView commit details
Commits on Apr 29, 2024
-
Document a known problem related to union function types
Union function types (`fun_ty_union`) do not seem to work. These simple examples should be perfectly valid. I think it throws that error because `expect_fun_type/3` inputs a list of function types (i.e., a clause), containing only a single element (the union of two function types). This leads to expecting an intersection function type later on (which is wrong). Note that these union function types aren't that much useful in practice as when you want to call them, all your argument types must be subtypes of parameter types of all the possible function types. That is, when you have a function of the type fun((integer()) -> integer()) | fun((atom()) -> atom()) then you can only call it with `none()` as we don't know whether the function will accept integers or bools and no other type is a subtype of `integer()` and `atom()`.
Configuration menu - View commit details
-
Copy full SHA for e51f914 - Browse repository at this point
Copy the full SHA e51f914View commit details -
Configuration menu - View commit details
-
Copy full SHA for 8d70850 - Browse repository at this point
Copy the full SHA 8d70850View commit details
Commits on May 26, 2024
-
Use Local Type Inference approach to typecheck polymorphic calls
We use the Local Type Argument Synthesis algorithm from https://www.cis.upenn.edu/~bcpierce/papers/lti-toplas.pdf (a bit extended for our use case). This replaces the global constraint generation and constraint solver. It should result in a much more precise type error messages (pinpointing the exact location, not just the function) and more streamlined code (refactor will be made in a subsequent commit). For more details, see the original paper or https://github.com/josefs/Gradualizer/wiki/Polymorphism#typechecking-polymorphic-calls
Configuration menu - View commit details
-
Copy full SHA for b8cfa76 - Browse repository at this point
Copy the full SHA b8cfa76View commit details -
Make rigid vars also from type vars in function constraints
The following type spec from gradualizer_db uses a type variables (K) as a bound for another type variable (Key): -spec add_entries_to_map([{Key, Value}], #{K => V}) -> #{K => V} when Key :: K, Value :: V. Until now, we converted all Ks and Vs to rigid vars, but then Key and Value got replaced to plain vars K and S in solve_bounds/2. We must therefore convert the type variables to rigid type variables *after* the call to solve_bounds/2, which is what this commit does.
Configuration menu - View commit details
-
Copy full SHA for 3210bce - Browse repository at this point
Copy the full SHA 3210bceView commit details -
Remove constraints from where they are not needed
Flexible type variables may now appear only when typechecking a polymorphic call, in which case they are only in the type of that polymorphic function. No other expression may of be a type that contains a flexible type variable. Constraints are thus needed only in the subtype_with_constraints/3 function that gets called only from type_check_poly_call/4. This means that nothing but the subtyping functions and the type_check_poly_call/4 function needs to deal with constraints. Therefore, I am removing constraints from all the other places. I believe this is a great simplification of the code. It also trivially solves all the TODOs like "Don't drop the constraints". In such a huge refactoring, Gradualizer has proved to be an invaluable help. Via self-gradualization, it discovered numerous errors that I didn't notice. Hopefully, there are no undetected errors left. All tests are passing, the self-gradualization does not crash and 100_000 proptests have also passed.
Configuration menu - View commit details
-
Copy full SHA for 6b6eddf - Browse repository at this point
Copy the full SHA 6b6eddfView commit details -
Configuration menu - View commit details
-
Copy full SHA for 35ab4fe - Browse repository at this point
Copy the full SHA 35ab4feView commit details -
Fix type inference of
try ... of
expressionsAnd also remove the assert_type uses that were needed because of this error.
Configuration menu - View commit details
-
Copy full SHA for b10b5fb - Browse repository at this point
Copy the full SHA b10b5fbView commit details -
any_type/4: return constraints if exactly one supertype matches
This quite a trivial change enables us to typecheck polymorphic functions like -spec generic_hd([A,...] | {A, any()}) -> A. or functions from Elixir's Enum module that use protocol polymorphism in addition to the parametric polymorphism: -spec enum_map([A] | map(), fun ((A) -> B)) -> [B]. which is really handy for Gradient and other Elixir frontends! Support for intersection polymorphic functions like -spec generic_hd([A,...]) -> A; ({A, any()}) -> A. is of course still missing. But at least some of these can now be typechecked when using a spec with the unions.
Configuration menu - View commit details
-
Copy full SHA for 4af8b2e - Browse repository at this point
Copy the full SHA 4af8b2eView commit details -
Make type variables only atoms again
Since now we do not generate type variables, they don't need to be strings anymore.
Configuration menu - View commit details
-
Copy full SHA for 7d45b1b - Browse repository at this point
Copy the full SHA 7d45b1bView commit details -
Configuration menu - View commit details
-
Copy full SHA for 31caf2d - Browse repository at this point
Copy the full SHA 31caf2dView commit details -
Remove the remark on missing subtype polymorpism support
It is already there since December 2022 (unless "subtype polymorphism" means bounded quantification).
Configuration menu - View commit details
-
Copy full SHA for a912cef - Browse repository at this point
Copy the full SHA a912cefView commit details -
Configuration menu - View commit details
-
Copy full SHA for 66bd8b5 - Browse repository at this point
Copy the full SHA 66bd8b5View commit details -
Remove hyphens from flag descriptions
They probably originate from the `fmt_location` description that uses hyphens to list possible values.
Configuration menu - View commit details
-
Copy full SHA for cad1047 - Browse repository at this point
Copy the full SHA cad1047View commit details -
Update CLI synopsis in the README
Removes the hyphens and add `--solve_constraints` flag.
Configuration menu - View commit details
-
Copy full SHA for 8efca04 - Browse repository at this point
Copy the full SHA 8efca04View commit details -
Use lists:usort/1 instead of lists:uniq/1 on OTP < 25
lists:uniq/1 was introduced in OTP 25.
Configuration menu - View commit details
-
Copy full SHA for aac8000 - Browse repository at this point
Copy the full SHA aac8000View commit details