-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
infer: Use GADT constraints in maximiseType
Consider the GADT constraints during Inferencing's maximiseType to avoid instantiating type variables that lead to GADT casting inserting unsound casts.
- Loading branch information
Showing
6 changed files
with
66 additions
and
7 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
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,15 @@ | ||
sealed trait Show[-A] | ||
final case class Pure[-B](showB: B => String) extends Show[B] | ||
final case class Many[-C](showL: List[C] => String) extends Show[List[C]] | ||
|
||
object Test: | ||
def meth[X](show: Show[X]): X => String = show match | ||
case Pure(showB) => showB | ||
case Many(showL) => | ||
val res = (xs: List[String]) => xs.head.length.toString | ||
res // error: Found: List[String] => String Required: X => String where: X is a type in method meth with bounds <: List[C$1] | ||
|
||
def main(args: Array[String]): Unit = | ||
val show = Many((is: List[Int]) => (is.head + 1).toString) | ||
val fn = meth(show) | ||
assert(fn(List(42)) == "43") // was: ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String |
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,22 @@ | ||
sealed trait Tree[+A] | ||
final case class Leaf[+B](b: B) extends Tree[B] | ||
final case class Node[+C](l: List[C]) extends Tree[List[C]] | ||
|
||
// The original test case, minimised. | ||
object Test: | ||
def meth[X](tree: Tree[X]): X = tree match | ||
case Leaf(v) => v // ok: Tree[X] vs Leaf[B], PTC: X >: B, max: Leaf[B] => Leaf[X], x: X | ||
case Node(x) => | ||
// tree: Tree[X] vs Node[C] aka Tree[List[C]] | ||
// PTC: X >: List[C] | ||
// max: Node[C] => Node[Any], instantiating C := Any, which makes X >: List[Any] | ||
// adapt: List[String] <: X = OKwithGADTUsed; insert GADT cast asInstanceOf[X] | ||
List("boom") // error: Found: List[String] Required: X where: X is a type in method meth with bounds >: List[C$1] | ||
// after fix: | ||
// max: Node[C] => Node[C$1], instantiating C := C$1, a new symbol, so X >: List[C$1] | ||
// adapt: List[String] <: X = Fail, because String !<: C$1 | ||
|
||
def main(args: Array[String]): Unit = | ||
val tree = Node(List(42)) | ||
val res = meth(tree) | ||
assert(res.head == 42) // was: ClassCastException: class java.lang.String cannot be cast to class java.lang.Integer |
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,14 @@ | ||
sealed trait Tree[+A] | ||
final case class Leaf[+B](b: B) extends Tree[B] | ||
final case class Node[+C](l: List[C]) extends Tree[List[C]] | ||
|
||
// A version of the original test case that is sound so should typecheck. | ||
object Test: | ||
def meth[X](tree: Tree[X]): X = tree match | ||
case Leaf(v) => v // ok: Tree[X] vs Leaf[B], PTC: X >: B, max: Leaf[B] => Leaf[X], x: X <:< X | ||
case Node(x) => x // ok: Tree[X] vs Node[C], PTC: X >: List[C], max: Node[C] => Node[C$1], x: C$1 <:< X, w/ GADT cast | ||
|
||
def main(args: Array[String]): Unit = | ||
val tree = Node(List(42)) | ||
val res = meth(tree) | ||
assert(res.head == 42) // ok |