You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Under certain conditions involving parameter unification, the GADT bounds will not get fully propagated.
In the following example, we have three type parameters X, A and B, with bound A: >: X <: X and B: <: Int.
In the snippet, we first add the ordering B <: A, then the ordering A <: B.
When we add the ordering A <: B, the upper bound <: Int should be propagated to X, since we have X <: A <: B <: Int.
However, that is not the case. The bound is not propagated in the GADT solver, and we have to explicitly cast X to A to make use of the bound X <: Int.
deftest[X, A>:X<:X, B<:Int] = {
enumExpr[+T]:caseTagA() extendsExpr[A]
caseTagB() extendsExpr[B]
importExpr._deffoo(e1: Expr[A], e2: Expr[B]) = e1 match {
caseTagB() =>// add GADT constr: B <: A
e2 match {
caseTagA() =>// add GADT constr: A <: B// should propagate bound X (<: A <: B) <: Int for X.valt0:X=???valt1:Int= t0 // errorvalt2:Int=t0 : A// cast explicitly, workscase _ =>
}
case _ =>
}
}
The problem happens during the unification of type parameters. When adding the constraint A <: B, the constraint handler checks that B <: A already holds, and it will unify A into B.
Ideally, the handler should propagate the upper bound of B (<: Int) to the parameters known to be the subtype of A (X in our case). To do this, the handler will first query all parameters less than A (except for those already known to be less than B, to avoid propgating bounds repeatedly) with the exclusiveLower function, then propagate the upper bounds of B to these parameters.
The problem is that, in the current implementation, we call exclusiveLower(A, B) after we call addLess(A, B). addLess(A, B) will order all lower parameters to be lower than B, which means that the result of exclusiveLower(A, B) will be List(B) instead of List(X, B).
To fix the problem we could call exclusiveLower before we call addLess.
Output
[info] running (fork) dotty.tools.dotc.Main-classpath /Users/linyxus/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.8/scala-library-2.13.8.jar:/Users/linyxus/Workspace/dotty/library/../out/bootstrap/scala3-library-bootstrapped/scala-3.1.3-RC1-bin-SNAPSHOT-nonbootstrapped/scala3-library_3-3.1.3-RC1-bin-SNAPSHOT.jar -color:never issues/gadt-unify.scala
-- [E007] TypeMismatchError: issues/gadt-unify.scala:15:24--------------------------------------------------------------------------------------------------------------------------------------------------------15|valt1:Int= t0 // error|^^|Found: (t0 : X)
|Required:Int||where: X is a typein method test which is an alias of B|| longer explanation available when compiling with`-explain`1 error found
[error] Nonzero exit code returned from runner: 1
[error] (scala3-compiler /Compile/ runMain) Nonzero exit code returned from runner: 1
[error] Totaltime: 2 s, completed Mar21, 2022, 4:56:21PM
Expectation
The 15th line should also work, without casting explicitly.
The text was updated successfully, but these errors were encountered:
Linyxus
changed the title
GADT upper bounds are not propagated during unification
GADT upper bounds are not properly propagated during unification
Mar 21, 2022
Compiler version
3.1.2-RC2
Minimized code
Under certain conditions involving parameter unification, the GADT bounds will not get fully propagated.
In the following example, we have three type parameters
X
,A
andB
, with boundA: >: X <: X
andB: <: Int
.In the snippet, we first add the ordering
B <: A
, then the orderingA <: B
.When we add the ordering
A <: B
, the upper bound<: Int
should be propagated toX
, since we haveX <: A <: B <: Int
.However, that is not the case. The bound is not propagated in the GADT solver, and we have to explicitly cast
X
toA
to make use of the boundX <: Int
.The problem happens during the unification of type parameters. When adding the constraint
A <: B
, the constraint handler checks thatB <: A
already holds, and it will unifyA
intoB
.Ideally, the handler should propagate the upper bound of
B
(<: Int
) to the parameters known to be the subtype ofA
(X
in our case). To do this, the handler will first query all parameters less thanA
(except for those already known to be less thanB
, to avoid propgating bounds repeatedly) with theexclusiveLower
function, then propagate the upper bounds ofB
to these parameters.The problem is that, in the current implementation, we call
exclusiveLower(A, B)
after we calladdLess(A, B)
.addLess(A, B)
will order all lower parameters to be lower thanB
, which means that the result ofexclusiveLower(A, B)
will beList(B)
instead ofList(X, B)
.To fix the problem we could call
exclusiveLower
before we calladdLess
.Output
Expectation
The 15th line should also work, without casting explicitly.
The text was updated successfully, but these errors were encountered: