Skip to content

Commit f72522c

Browse files
committed
Avoid constructing intermediate sets in interpolateTypeVars
1 parent 35e6318 commit f72522c

File tree

2 files changed

+61
-54
lines changed

2 files changed

+61
-54
lines changed

compiler/src/dotty/tools/dotc/typer/Inferencing.scala

Lines changed: 48 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -412,58 +412,55 @@ trait Inferencing { this: Typer =>
412412
// `qualifying`.
413413

414414
val ownedVars = state.ownedVars
415-
if (ownedVars.size > 0) {
416-
val qualifying = if (locked.isEmpty) ownedVars else ownedVars -- locked
417-
if (!qualifying.isEmpty) {
418-
typr.println(i"interpolate $tree: ${tree.tpe.widen} in $state, owned vars = ${state.ownedVars.toList}%, %, previous = ${locked.toList}%, % / ${state.constraint}")
419-
val resultAlreadyConstrained =
420-
tree.isInstanceOf[Apply] || tree.tpe.isInstanceOf[MethodOrPoly]
421-
if (!resultAlreadyConstrained)
422-
constrainResult(tree.symbol, tree.tpe, pt)
423-
// This is needed because it could establish singleton type upper bounds. See i2998.scala.
424-
425-
val tp = tree.tpe.widen
426-
val vs = variances(tp)
427-
428-
// Avoid interpolating variables occurring in tree's type if typerstate has unreported errors.
429-
// Reason: The errors might reflect unsatisfiable constraints. In that
430-
// case interpolating without taking account the constraints risks producing
431-
// nonsensical types that then in turn produce incomprehensible errors.
432-
// An example is in neg/i1240.scala. Without the condition in the next code line
433-
// we get for
434-
//
435-
// val y: List[List[String]] = List(List(1))
436-
//
437-
// i1430.scala:5: error: type mismatch:
438-
// found : Int(1)
439-
// required: Nothing
440-
// val y: List[List[String]] = List(List(1))
441-
// ^
442-
// With the condition, we get the much more sensical:
443-
//
444-
// i1430.scala:5: error: type mismatch:
445-
// found : Int(1)
446-
// required: String
447-
// val y: List[List[String]] = List(List(1))
448-
val hasUnreportedErrors = state.reporter.hasUnreportedErrors
449-
def constraint = state.constraint
450-
for (tvar <- qualifying)
451-
if (!tvar.isInstantiated && state.constraint.contains(tvar)) {
452-
// Needs to be checked again, since previous interpolations could already have
453-
// instantiated `tvar` through unification.
454-
val v = vs(tvar)
455-
if (v == null) {
456-
typr.println(i"interpolate non-occurring $tvar in $state in $tree: $tp, fromBelow = ${tvar.hasLowerBound}, $constraint")
457-
tvar.instantiate(fromBelow = tvar.hasLowerBound)
458-
}
459-
else if (!hasUnreportedErrors)
460-
if (v.intValue != 0) {
461-
typr.println(i"interpolate $tvar in $state in $tree: $tp, fromBelow = ${v.intValue == 1}, $constraint")
462-
tvar.instantiate(fromBelow = v.intValue == 1)
463-
}
464-
else typr.println(i"no interpolation for nonvariant $tvar in $state")
415+
if (ownedVars.size > 0 && (locked.size == 0 || ownedVars.exists(!locked.contains(_)))) {
416+
typr.println(i"interpolate $tree: ${tree.tpe.widen} in $state, owned vars = ${state.ownedVars.toList}%, %, previous = ${locked.toList}%, % / ${state.constraint}")
417+
val resultAlreadyConstrained =
418+
tree.isInstanceOf[Apply] || tree.tpe.isInstanceOf[MethodOrPoly]
419+
if (!resultAlreadyConstrained)
420+
constrainResult(tree.symbol, tree.tpe, pt)
421+
// This is needed because it could establish singleton type upper bounds. See i2998.scala.
422+
423+
val tp = tree.tpe.widen
424+
val vs = variances(tp)
425+
426+
// Avoid interpolating variables occurring in tree's type if typerstate has unreported errors.
427+
// Reason: The errors might reflect unsatisfiable constraints. In that
428+
// case interpolating without taking account the constraints risks producing
429+
// nonsensical types that then in turn produce incomprehensible errors.
430+
// An example is in neg/i1240.scala. Without the condition in the next code line
431+
// we get for
432+
//
433+
// val y: List[List[String]] = List(List(1))
434+
//
435+
// i1430.scala:5: error: type mismatch:
436+
// found : Int(1)
437+
// required: Nothing
438+
// val y: List[List[String]] = List(List(1))
439+
// ^
440+
// With the condition, we get the much more sensical:
441+
//
442+
// i1430.scala:5: error: type mismatch:
443+
// found : Int(1)
444+
// required: String
445+
// val y: List[List[String]] = List(List(1))
446+
val hasUnreportedErrors = state.reporter.hasUnreportedErrors
447+
def constraint = state.constraint
448+
for (tvar <- ownedVars)
449+
if (!locked.contains(tvar) && !tvar.isInstantiated && state.constraint.contains(tvar)) {
450+
// Needs to be checked again, since previous interpolations could already have
451+
// instantiated `tvar` through unification.
452+
val v = vs(tvar)
453+
if (v == null) {
454+
typr.println(i"interpolate non-occurring $tvar in $state in $tree: $tp, fromBelow = ${tvar.hasLowerBound}, $constraint")
455+
tvar.instantiate(fromBelow = tvar.hasLowerBound)
465456
}
466-
}
457+
else if (!hasUnreportedErrors)
458+
if (v.intValue != 0) {
459+
typr.println(i"interpolate $tvar in $state in $tree: $tp, fromBelow = ${v.intValue == 1}, $constraint")
460+
tvar.instantiate(fromBelow = v.intValue == 1)
461+
}
462+
else typr.println(i"no interpolation for nonvariant $tvar in $state")
463+
}
467464
}
468465
tree
469466
}

compiler/src/dotty/tools/dotc/util/SimpleIdentitySet.scala

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,17 @@ import collection.mutable.ListBuffer
77
*/
88
abstract class SimpleIdentitySet[+Elem <: AnyRef] {
99
def size: Int
10-
def isEmpty: Boolean = size == 0
10+
final def isEmpty: Boolean = size == 0
1111
def + [E >: Elem <: AnyRef](x: E): SimpleIdentitySet[E]
1212
def - [E >: Elem <: AnyRef](x: E): SimpleIdentitySet[Elem]
1313
def contains[E >: Elem <: AnyRef](x: E): Boolean
1414
def foreach(f: Elem => Unit): Unit
15+
def exists[E >: Elem <: AnyRef](p: E => Boolean): Boolean
1516
def /: [A, E >: Elem <: AnyRef](z: A)(f: (A, E) => A): A
1617
def toList: List[Elem]
17-
def ++ [E >: Elem <: AnyRef](that: SimpleIdentitySet[E]): SimpleIdentitySet[E] =
18+
final def ++ [E >: Elem <: AnyRef](that: SimpleIdentitySet[E]): SimpleIdentitySet[E] =
1819
((this: SimpleIdentitySet[E]) /: that)(_ + _)
19-
def -- [E >: Elem <: AnyRef](that: SimpleIdentitySet[E]): SimpleIdentitySet[Elem] =
20+
final def -- [E >: Elem <: AnyRef](that: SimpleIdentitySet[E]): SimpleIdentitySet[Elem] =
2021
(this /: that)(_ - _)
2122
override def toString: String = toList.mkString("(", ", ", ")")
2223
}
@@ -30,6 +31,7 @@ object SimpleIdentitySet {
3031
this
3132
def contains[E <: AnyRef](x: E): Boolean = false
3233
def foreach(f: Nothing => Unit): Unit = ()
34+
def exists[E <: AnyRef](p: E => Boolean): Boolean = false
3335
def /: [A, E <: AnyRef](z: A)(f: (A, E) => A): A = z
3436
def toList = Nil
3537
}
@@ -42,6 +44,8 @@ object SimpleIdentitySet {
4244
if (x `eq` x0) empty else this
4345
def contains[E >: Elem <: AnyRef](x: E): Boolean = x `eq` x0
4446
def foreach(f: Elem => Unit): Unit = f(x0.asInstanceOf[Elem])
47+
def exists[E >: Elem <: AnyRef](p: E => Boolean): Boolean =
48+
p(x0.asInstanceOf[E])
4549
def /: [A, E >: Elem <: AnyRef](z: A)(f: (A, E) => A): A =
4650
f(z, x0.asInstanceOf[E])
4751
def toList = x0.asInstanceOf[Elem] :: Nil
@@ -57,6 +61,8 @@ object SimpleIdentitySet {
5761
else this
5862
def contains[E >: Elem <: AnyRef](x: E): Boolean = (x `eq` x0) || (x `eq` x1)
5963
def foreach(f: Elem => Unit): Unit = { f(x0.asInstanceOf[Elem]); f(x1.asInstanceOf[Elem]) }
64+
def exists[E >: Elem <: AnyRef](p: E => Boolean): Boolean =
65+
p(x0.asInstanceOf[E]) || p(x1.asInstanceOf[E])
6066
def /: [A, E >: Elem <: AnyRef](z: A)(f: (A, E) => A): A =
6167
f(f(z, x0.asInstanceOf[E]), x1.asInstanceOf[E])
6268
def toList = x0.asInstanceOf[Elem] :: x1.asInstanceOf[Elem] :: Nil
@@ -83,6 +89,8 @@ object SimpleIdentitySet {
8389
def foreach(f: Elem => Unit): Unit = {
8490
f(x0.asInstanceOf[Elem]); f(x1.asInstanceOf[Elem]); f(x2.asInstanceOf[Elem])
8591
}
92+
def exists[E >: Elem <: AnyRef](p: E => Boolean): Boolean =
93+
p(x0.asInstanceOf[E]) || p(x1.asInstanceOf[E]) || p(x2.asInstanceOf[E])
8694
def /: [A, E >: Elem <: AnyRef](z: A)(f: (A, E) => A): A =
8795
f(f(f(z, x0.asInstanceOf[E]), x1.asInstanceOf[E]), x2.asInstanceOf[E])
8896
def toList = x0.asInstanceOf[Elem] :: x1.asInstanceOf[Elem] :: x2.asInstanceOf[Elem] :: Nil
@@ -123,6 +131,8 @@ object SimpleIdentitySet {
123131
var i = 0
124132
while (i < size) { f(xs(i).asInstanceOf[Elem]); i += 1 }
125133
}
134+
def exists[E >: Elem <: AnyRef](p: E => Boolean): Boolean =
135+
xs.asInstanceOf[Array[E]].exists(p)
126136
def /: [A, E >: Elem <: AnyRef](z: A)(f: (A, E) => A): A =
127137
(z /: xs.asInstanceOf[Array[E]])(f)
128138
def toList: List[Elem] = {

0 commit comments

Comments
 (0)