Overconstrained GADT bounds in presence of bad bounds
See original GitHub issueCompiler version
3.0.0-RC1 (Scastie)
Minimized code
@main def test: Unit = {
trait S[A]
trait Inv[A]
class P[X] extends S[Inv[X] & Inv[String]]
def patmat[A, Y](s: S[Inv[A] & Y]): A = s match {
case p: P[x] =>
"Hello"
}
val got: Int = patmat[Int, Inv[String]](new P) // ClassCastException: String cannot be cast to Integer
}
Output
Click to expand
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at scala.runtime.BoxesRunTime.unboxToInt(BoxesRunTime.java:99)
at main$package$.test(main.scala:11)
at test.main(main.scala:1)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sbt.Run.invokeMain(Run.scala:115)
at sbt.Run.execute$1(Run.scala:79)
at sbt.Run.$anonfun$runWithLoader$4(Run.scala:92)
at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
at sbt.util.InterfaceUtil$$anon$1.get(InterfaceUtil.scala:10)
at sbt.TrapExit$App.run(TrapExit.scala:257)
at java.lang.Thread.run(Thread.java:748)
Expectation
The code should be rejected, but it is unclear what part is problematic:
- The instantiation of
new P
due to introducing the bad boundsS[Inv[Int] & Inv[String]]
- The class declaration of P with the
extends S[Inv[X] & Inv[String]]
clause, which may lead to bad bounds ifX != String
- Deducing that
x = A = String
I think that the problem comes from 1 (and not necessarily from 3). I believe, however, that this is not sufficient, as it seems that bad bounds can still be crafted.
Translating the above into pDOT shows that we can allow 3. if we require a witness value for Inv[A] & Y
. Then, the above would not cause a ClassCastException
since providing a value for Inv[Int] & Inv[String]
is not possible.
Issue Analytics
- State:
- Created 3 years ago
- Comments:19 (19 by maintainers)
Top Results From Across the Web
Generalization Bounds in the Presence of Outliers: a Median ...
Roughly, we want K > 2nO to ensure that blocks without outliers are in majority. However, if K is too large MoM tends...
Read more >Constrained Nonlinear Optimization Algorithms - MathWorks
In this method an active set, A ¯ k , is maintained that is an estimate of the active constraints (i.e., those that...
Read more >Channel coding: non-asymptotic fundamental limits
Knowledge of the behavior of the fundamental limits in the non-asymptotic ... Moreover, the bound (2.45) also holds in the presence of noiseless...
Read more >RESIDUAL AND BACKWARD ERROR BOUNDS IN MINIMUM ...
The present paper proves the- oretical results motivated by the abovementioned finite precision behavior of MGS. GMRES but assumes exact arithmetic in all...
Read more >Upper Limits on the Epoch of Reionization 21 cm Power ...
(2022) present a validation of the Phase I analysis and power spectrum pipeline, using data simulations with realistic sky, instrument, and ...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
I’m reopening this. @LPTK correctly observed that we’re still unsound. The correct solution seems to be to check whether we’re in GADT constraint inference mode before (approximately) branching on
&
.The culprit is clearly 3. In Scala/pDOT, you can’t escape type members with members that themselves end up having bad bounds (as you say, bad bounds can still be crafted). So we have to live with bad bounds.
In the pattern match, we know
Inv[x] & Inv[String] =:= Inv[A] & Y
. It is utterly wrong to decompose that constraint intoInv[x] =:= Inv[A]
andInv[String] =:= Y
, which is what Dotty seems to be doing. The latter implies the former, so it’s okay for approximating type inference, but the former does not imply the latter.In DOT-like terms, we have
Inv[x | String .. x & String] =:= Inv[A] & Y
. So we do haveInv[x | String .. x & String] <: Inv[A]
and thusA <: x | String
andx & String <: A
. We also haveInv[A] & Y <: Inv[x | String .. x & String]
, from which we can’t deduce anything (think thatY
could be bottom). None of these impliesString <: A
, which is needed to make the pattern match type check.