Skip to content

Commit

Permalink
Put level checking under a config flag
Browse files Browse the repository at this point in the history
Off by default
  • Loading branch information
odersky committed May 31, 2022
1 parent 78dbc59 commit 2317859
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 3 deletions.
6 changes: 6 additions & 0 deletions compiler/src/dotty/tools/dotc/config/Config.scala
Original file line number Diff line number Diff line change
Expand Up @@ -226,4 +226,10 @@ object Config {
* reduces the number of allocated denotations by ~50%.
*/
inline val reuseSymDenotations = true

/** If true, check levels of type variables and create fresh ones as needed.
* This is necessary for soundness (see 3ab18a9), but also causes several
* regressions that should be fixed before turning this on.
*/
inline val checkLevels = false
}
7 changes: 4 additions & 3 deletions compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,10 @@ trait ConstraintHandling {

/** Is `level` <= `maxLevel` or legal in the current context? */
def levelOK(level: Int, maxLevel: Int)(using Context): Boolean =
level <= maxLevel ||
ctx.isAfterTyper || !ctx.typerState.isCommittable || // Leaks in these cases shouldn't break soundness
level == Int.MaxValue // See `nestingLevel` above.
level <= maxLevel
|| ctx.isAfterTyper || !ctx.typerState.isCommittable // Leaks in these cases shouldn't break soundness
|| level == Int.MaxValue // See `nestingLevel` above.
|| !Config.checkLevels

/** If `param` is nested deeper than `maxLevel`, try to instantiate it to a
* fresh type variable of level `maxLevel` and return the new variable.
Expand Down
6 changes: 6 additions & 0 deletions tests/pos/i14494.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
object ImplNotFound:
def main(args: Array[String]): Unit =
val res: Seq[String | Int] = (??? : Seq[Int]).collect {
case 1 => Seq("")
case 2 => Seq(1)
}.flatten
17 changes: 17 additions & 0 deletions tests/pos/i15178.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// This should be a neg test once level checking is re-enabled.

trait E[F[_]] {
type T
val value: F[T]
}

object E {
def apply[F[_], T1](value1: F[T1]) = new E[F] {
type T = T1
val value = value1
}
}

val a: Option[E[Ordering]] = Option(E(Ordering[Int]))
val _ = a.map(it => E(it.value)) // there should be an error here

14 changes: 14 additions & 0 deletions tests/pos/i15184.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
def test() = {
func(_ => Box(Seq.empty[String]) )
}

def func[R0](to0: Unit => R0): Unit = ???

trait JsonFormat[T]
object JsonFormat{
implicit def immSeqFormat: JsonFormat[Seq[String]] = ???

implicit def iterableFormat: JsonFormat[Iterable[String]] = ???
}

case class Box[A1: JsonFormat](elem: A1)
25 changes: 25 additions & 0 deletions tests/pos/i15216.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
sealed abstract class Free[S[_], A] {
final def map[B](f: A => B): Free[S, B] = ???
final def flatMap[B](f: A => Free[S, B]): Free[S, B] = new Free[S, B] {}
}

trait Parameter[T]
def namedDouble(name: String): Free[Parameter, Double] = ???

type Double2 = (Double, Double)
type Double3 = (Double, Double, Double)
val spec: Free[Parameter, Either[Double3, Double2]] = for {
result <-
if (???) {
for {
x <- namedDouble("X")
y <- namedDouble("Y")
z <- namedDouble("Z")
} yield Left((x, y, z))
} else {
for {
x <- namedDouble("X")
y <- namedDouble("Y")
} yield Right((x, y))
}
} yield result

0 comments on commit 2317859

Please sign in to comment.