Permalink
Show file tree
Hide file tree
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Fix non-transitive subtyping with generic parameters and recursion
Summary: Subtyping should be transitive. It's not, as the following test demonstrates: ``` interface I<-Ti> { } class B { } class C extends B implements I<B> { } class D<T as C> { public function fromTtoC(T $x):C { return $x; } public function fromCtoIT(C $c):I<T> { return $c; } public function fromTtoIT(T $x):I<T> { return $x; } } ``` Hack rejects the third method. This is due to the way that we detect cycles involving generic parameters: if during subtype simplification we arrive at a generic parameter that we have already seen, then we assume that subtyping will loop. This isn't sufficient. Consider the case above: under the assumption that `T <: C` we are checking `T <: I<T>`. This leads to the following chain of assertions: `T <: I<T>` => `C <: I<T>` (by assumption) => `I<B> <: I<T>` (by inheritance) => `T <: B` (by contravariance) At this point, we bail, because we've seen `T` before. But we should continue: `C <: B` (by assumption) => `B <: B` (by inheritance) => done. Instead, we now keep in essence a set of visited *goals* i.e. subtype assertions. We do this only for assertions of the form `T <: t` or `t <: T` where `T` is a generic parameter, in order to avoid regressing performance of subtyping. Reviewed By: vsiles Differential Revision: D25909931 fbshipit-source-id: 43047654daa2d521a38e4cefc5a7b48b6ec22520
- Loading branch information
1 parent
f848b33
commit 6542f53
Showing
5 changed files
with
139 additions
and
43 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
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,17 @@ | ||
<?hh | ||
// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. | ||
|
||
interface I<-Ti> { } | ||
class B { } | ||
class C extends B implements I<B> { } | ||
class D<T as C> { | ||
public function fromTtoC(T $x):C { | ||
return $x; | ||
} | ||
public function fromCtoIT(C $c):I<T> { | ||
return $c; | ||
} | ||
public function fromTtoIT(T $x):I<T> { | ||
return $x; | ||
} | ||
} |
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 |
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,12 @@ | ||
<?hh | ||
// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. | ||
|
||
class Cov<+Tc> { } | ||
function foo<T2 as T,T as Cov<T2>>(T $x):Cov<T> { | ||
return $x; | ||
} | ||
|
||
class Contra<-TN> { } | ||
function bar<T as Contra<Contra<T>>>(T $x):Contra<T> { | ||
return $x; | ||
} |
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,6 @@ | ||
File "recursive_bounds.php", line 11, characters 10-11: | ||
Invalid return type (Typing[4110]) | ||
File "recursive_bounds.php", line 10, characters 44-52: | ||
Expected `Contra<T>` | ||
File "recursive_bounds.php", line 10, characters 38-38: | ||
But got `T` |