Skip to content

Commit ad2776c

Browse files
committed
More optimizations
Bring back -- but optimize it for the case where the sets are similar.
1 parent 85f79cb commit ad2776c

File tree

2 files changed

+95
-51
lines changed

2 files changed

+95
-51
lines changed

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

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

414414
val ownedVars = state.ownedVars
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)
456-
}
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)
415+
if ((ownedVars ne locked) && !ownedVars.isEmpty) {
416+
val qualifying = 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)
461458
}
462-
else typr.println(i"no interpolation for nonvariant $tvar in $state")
463-
}
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")
465+
}
466+
}
464467
}
465468
tree
466469
}

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

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,16 @@ abstract class SimpleIdentitySet[+Elem <: AnyRef] {
1515
def exists[E >: Elem <: AnyRef](p: E => Boolean): Boolean
1616
def /: [A, E >: Elem <: AnyRef](z: A)(f: (A, E) => A): A
1717
def toList: List[Elem]
18-
def ++ [E >: Elem <: AnyRef](that: SimpleIdentitySet[E]): SimpleIdentitySet[E] = {
18+
def ++ [E >: Elem <: AnyRef](that: SimpleIdentitySet[E]): SimpleIdentitySet[E] =
1919
if (this.size == 0) that
2020
else if (that.size == 0) this
2121
else concat(that)
22-
}
22+
def -- [E >: Elem <: AnyRef](that: SimpleIdentitySet[E]): SimpleIdentitySet[E] =
23+
if (that.size == 0) this
24+
else
25+
((SimpleIdentitySet.empty: SimpleIdentitySet[E]) /: this) { (s, x) =>
26+
if (that.contains(x)) s else s + x
27+
}
2328
protected def concat[E >: Elem <: AnyRef](that: SimpleIdentitySet[E]): SimpleIdentitySet[E] =
2429
((this: SimpleIdentitySet[E]) /: that)(_ + _)
2530
override def toString: String = toList.mkString("(", ", ", ")")
@@ -143,7 +148,7 @@ object SimpleIdentitySet {
143148
foreach(buf += _)
144149
buf.toList
145150
}
146-
override def concat [E >: Elem <: AnyRef](that: SimpleIdentitySet[E]): SimpleIdentitySet[E] =
151+
override def concat[E >: Elem <: AnyRef](that: SimpleIdentitySet[E]): SimpleIdentitySet[E] =
147152
that match {
148153
case that: SetN[_] =>
149154
var toAdd: mutable.ArrayBuffer[AnyRef] = null
@@ -171,5 +176,41 @@ object SimpleIdentitySet {
171176
}
172177
case _ => super.concat(that)
173178
}
179+
override def -- [E >: Elem <: AnyRef](that: SimpleIdentitySet[E]): SimpleIdentitySet[E] =
180+
that match {
181+
case that: SetN[_] =>
182+
// both sets are large, optimize assuming they are similar
183+
// by starting from empty set and adding elements
184+
var toAdd: mutable.ArrayBuffer[AnyRef] = null
185+
val thisSize = this.size
186+
val thatSize = that.size
187+
val thatElems = that.xs
188+
var i = 0
189+
var searchStart = 0
190+
while (i < thisSize) {
191+
val elem = this.xs(i)
192+
var j = searchStart // search thatElems in round robin fashion, starting one after latest hit
193+
var missing = false
194+
while (!missing && elem != thatElems(j)) {
195+
j = (j + 1) % thatSize
196+
missing = j == searchStart
197+
}
198+
if (missing) {
199+
if (toAdd == null) toAdd = new mutable.ArrayBuffer
200+
toAdd += elem
201+
}
202+
else searchStart = (j + 1) % thatSize
203+
i += 1
204+
}
205+
if (toAdd == null) empty
206+
else toAdd.size match {
207+
case 1 => new Set1[E](toAdd(0))
208+
case 2 => new Set2[E](toAdd(0), toAdd(1))
209+
case 3 => new Set3[E](toAdd(0), toAdd(1), toAdd(2))
210+
case _ => new SetN[E](toAdd.toArray)
211+
}
212+
case _ => // this set is large, that set is small: reduce from above using `-`
213+
((this: SimpleIdentitySet[E]) /: that)(_ - _)
214+
}
174215
}
175216
}

0 commit comments

Comments
 (0)