-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Avoid subtyping incompleteness in Typing_solver.bind_to_lower_bound b…
…y detecting when freshen_inside_ty does nothing Summary: NOTE: I found this when working on a class refinement refactor. The refactor involves creating tyvars with lower bounds where the lower bounds are types involves intersections and unions. The refactor triggered false errors in WWW that this diff aims to fix. I have reproduced the crux of the issue via union and intersection type hints. In `bind_to_lower_bound`, if `freshen_inside_ty` doesn't actually freshen anything, we end up doing a `T <: T` subtype check which (a) doesn't have any effect on the environment and (b) can sometimes fail due to incompleteness issues despite it being always true. (see added test for incompleteness example) One option would be to use `ty_equal` if the subtype check fails (see alternative D68981350), but this diff instead changes `freshen_inside_ty` to return an option—`None` when nothing was freshened and the output would have been the same as the input. Now, in`bind_to_lower_bound` when `freshen_inside_ty` returns None, we skip the subtyping step. --- In the test case: ``` (A & ((B & C) | D)) <: (A & ((B & C) | D)) ``` is broken down into: ``` (A & ((B & C) | D)) < A &&& (A & ((B & C) | D)) < ((B & C) | D) ``` The latter of these propositions fails because [this heuristic](https://fburl.com/code/r88xune0) sees the RHS union contains an intersection and splits the RHS union instead of the LHS intersection Reviewed By: dlreeves Differential Revision: D69210301 fbshipit-source-id: 539c2ce1e05b695daa3f62ea8778d05fc494b62c
- Loading branch information
1 parent
03fa6f0
commit a37f19d
Showing
3 changed files
with
118 additions
and
58 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 29 additions & 0 deletions
29
...ck/test/typecheck/detect_trivial_freshen_to_skip_incomplete_subtyping_of_lower_bounds.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<?hh | ||
|
||
<<file: __EnableUnstableFeatures('union_intersection_type_hints')>> | ||
|
||
final class MyContainer<T> { | ||
public function put(T $x): void {} | ||
public function get(): T { | ||
throw new Exception(); | ||
} | ||
} | ||
|
||
interface IHasMeth { | ||
public function meth(): int; | ||
} | ||
|
||
interface A extends IHasMeth {} | ||
interface B extends IHasMeth {} | ||
interface C extends IHasMeth {} | ||
interface D extends IHasMeth {} | ||
|
||
// (A & ((B & C) | D)) is special because in our current subtyping logic | ||
// (A & ((B & C) | D)) <: (A & ((B & C) | D)) fails due to incompleteness | ||
function myfoo((A & ((B & C) | D)) $x): void { | ||
$c = new MyContainer(); | ||
$c->put($x); | ||
$y = $c->get(); | ||
// $y : tyvar w/ lower bound: A & ((B & C) | D) | ||
$y->meth(); // forces solve | ||
} |
1 change: 1 addition & 0 deletions
1
...est/typecheck/detect_trivial_freshen_to_skip_incomplete_subtyping_of_lower_bounds.php.exp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
No errors |