Skip to content

Commit 67aef97

Browse files
committed
Merge pull request #678 from dotty-staging/fix/#670-orphan-polyparam
Avoid junk produced by Constraint#replace.
2 parents 0fba875 + d973e5d commit 67aef97

File tree

7 files changed

+51
-16
lines changed

7 files changed

+51
-16
lines changed

src/dotty/tools/dotc/config/Config.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ object Config {
3232
*/
3333
final val checkConstraintsPropagated = false
3434

35+
/** Check that constraints of globally committable typer states are closed */
36+
final val checkConstraintsClosed = true
37+
3538
/** Check that no type appearing as the info of a SymDenotation contains
3639
* skolem types.
3740
*/

src/dotty/tools/dotc/core/Constraint.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,4 +146,7 @@ abstract class Constraint extends Showable {
146146

147147
/** Check that no constrained parameter contains itself as a bound */
148148
def checkNonCyclic()(implicit ctx: Context): Unit
149+
150+
/** Check that constraint only refers to PolyParams bound by itself */
151+
def checkClosed()(implicit ctx: Context): Unit
149152
}

src/dotty/tools/dotc/core/OrderingConstraint.scala

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
399399
def removeParam(ps: List[PolyParam]) =
400400
ps.filterNot(p => p.binder.eq(poly) && p.paramNum == idx)
401401

402-
def replaceParam(tp: Type, atPoly: PolyType, atIdx: Int) = tp match {
402+
def replaceParam(tp: Type, atPoly: PolyType, atIdx: Int): Type = tp match {
403403
case bounds @ TypeBounds(lo, hi) =>
404404

405405
def recombine(andor: AndOrType, op: (Type, Boolean) => Type, isUpper: Boolean): Type = {
@@ -424,7 +424,8 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
424424
}
425425

426426
bounds.derivedTypeBounds(replaceIn(lo, isUpper = false), replaceIn(hi, isUpper = true))
427-
case _ => tp
427+
case _ =>
428+
tp.substParam(param, replacement)
428429
}
429430

430431
var current =
@@ -438,8 +439,16 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
438439
}
439440
}
440441

441-
def remove(pt: PolyType)(implicit ctx: Context): This =
442-
newConstraint(boundsMap.remove(pt), lowerMap.remove(pt), upperMap.remove(pt))
442+
def remove(pt: PolyType)(implicit ctx: Context): This = {
443+
def removeFromOrdering(po: ParamOrdering) = {
444+
def removeFromBoundss(key: PolyType, bndss: Array[List[PolyParam]]): Array[List[PolyParam]] = {
445+
val bndss1 = bndss.map(_.filterConserve(_.binder ne pt))
446+
if (bndss.corresponds(bndss1)(_ eq _)) bndss else bndss1
447+
}
448+
po.remove(pt).mapValuesNow(removeFromBoundss)
449+
}
450+
newConstraint(boundsMap.remove(pt), removeFromOrdering(lowerMap), removeFromOrdering(upperMap))
451+
}
443452

444453
def isRemovable(pt: PolyType, removedParam: Int = -1): Boolean = {
445454
val entries = boundsMap(pt)
@@ -491,6 +500,19 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
491500
}
492501
}
493502

503+
override def checkClosed()(implicit ctx: Context): Unit = {
504+
def isFreePolyParam(tp: Type) = tp match {
505+
case PolyParam(binder, _) => !contains(binder)
506+
case _ => false
507+
}
508+
def checkClosedType(tp: Type, where: String) =
509+
if (tp != null)
510+
assert(!tp.existsPart(isFreePolyParam), i"unclosed constraint: $this refers to $tp in $where")
511+
boundsMap.foreachBinding((_, tps) => tps.foreach(checkClosedType(_, "bounds")))
512+
lowerMap.foreachBinding((_, paramss) => paramss.foreach(_.foreach(checkClosedType(_, "lower"))))
513+
upperMap.foreachBinding((_, paramss) => paramss.foreach(_.foreach(checkClosedType(_, "upper"))))
514+
}
515+
494516
private var myUninstVars: mutable.ArrayBuffer[TypeVar] = _
495517

496518
/** The uninstantiated typevars of this constraint */

src/dotty/tools/dotc/core/TyperState.scala

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import util.{SimpleMap, DotClass}
99
import reporting._
1010
import printing.{Showable, Printer}
1111
import printing.Texts._
12+
import config.Config
1213
import collection.mutable
1314

1415
class TyperState(r: Reporter) extends DotClass with Showable {
@@ -19,7 +20,7 @@ class TyperState(r: Reporter) extends DotClass with Showable {
1920
/** The current constraint set */
2021
def constraint: Constraint =
2122
new OrderingConstraint(SimpleMap.Empty, SimpleMap.Empty, SimpleMap.Empty)
22-
def constraint_=(c: Constraint): Unit = {}
23+
def constraint_=(c: Constraint)(implicit ctx: Context): Unit = {}
2324

2425
/** The uninstantiated variables */
2526
def uninstVars = constraint.uninstVars
@@ -85,7 +86,10 @@ extends TyperState(r) {
8586
private var myConstraint: Constraint = previous.constraint
8687

8788
override def constraint = myConstraint
88-
override def constraint_=(c: Constraint) = myConstraint = c
89+
override def constraint_=(c: Constraint)(implicit ctx: Context) = {
90+
if (Config.checkConstraintsClosed && isGlobalCommittable) c.checkClosed()
91+
myConstraint = c
92+
}
8993

9094
private var myEphemeral: Boolean = previous.ephemeral
9195

src/dotty/tools/dotc/core/Types.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2458,6 +2458,9 @@ object Types {
24582458
if (fromBelow && isOrType(inst) && isFullyDefined(inst) && !isOrType(upperBound))
24592459
inst = inst.approximateUnion
24602460

2461+
if (ctx.typerState.isGlobalCommittable)
2462+
assert(!inst.isInstanceOf[PolyParam], i"bad inst $this := $inst, constr = ${ctx.typerState.constraint}")
2463+
24612464
instantiateWith(inst)
24622465
}
24632466

src/dotty/tools/dotc/util/SimpleMap.scala

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ abstract class SimpleMap[K <: AnyRef, +V >: Null <: AnyRef] extends (K => V) {
88
def remove(k: K): SimpleMap[K, V]
99
def updated[V1 >: V <: AnyRef](k: K, v: V1): SimpleMap[K, V1]
1010
def contains(k: K): Boolean = apply(k) != null
11-
def mapValues[V1 >: V <: AnyRef](f: (K, V1) => V1): SimpleMap[K, V1]
11+
def mapValuesNow[V1 >: V <: AnyRef](f: (K, V1) => V1): SimpleMap[K, V1]
1212
def foreachBinding(f: (K, V) => Unit): Unit
1313
def map2[T](f: (K, V) => T): List[T] = {
1414
val buf = new ListBuffer[T]
@@ -32,7 +32,7 @@ object SimpleMap {
3232
def apply(k: AnyRef) = null
3333
def remove(k: AnyRef) = this
3434
def updated[V1 >: Null <: AnyRef](k: AnyRef, v: V1) = new Map1(k, v)
35-
def mapValues[V1 >: Null <: AnyRef](f: (AnyRef, V1) => V1) = this
35+
def mapValuesNow[V1 >: Null <: AnyRef](f: (AnyRef, V1) => V1) = this
3636
def foreachBinding(f: (AnyRef, Null) => Unit) = ()
3737
}
3838

@@ -49,7 +49,7 @@ object SimpleMap {
4949
def updated[V1 >: V <: AnyRef](k: K, v: V1) =
5050
if (k == k1) new Map1(k, v)
5151
else new Map2(k1, v1, k, v)
52-
def mapValues[V1 >: V <: AnyRef](f: (K, V1) => V1) = {
52+
def mapValuesNow[V1 >: V <: AnyRef](f: (K, V1) => V1) = {
5353
val w1 = f(k1, v1)
5454
if (v1 eq w1) this else new Map1(k1, w1)
5555
}
@@ -70,7 +70,7 @@ object SimpleMap {
7070
if (k == k1) new Map2(k, v, k2, v2)
7171
else if (k == k2) new Map2(k1, v1, k, v)
7272
else new Map3(k1, v1, k2, v2, k, v)
73-
def mapValues[V1 >: V <: AnyRef](f: (K, V1) => V1) = {
73+
def mapValuesNow[V1 >: V <: AnyRef](f: (K, V1) => V1) = {
7474
val w1 = f(k1, v1); val w2 = f(k2, v2)
7575
if ((v1 eq w1) && (v2 eq w2)) this
7676
else new Map2(k1, w1, k2, w2)
@@ -95,7 +95,7 @@ object SimpleMap {
9595
else if (k == k2) new Map3(k1, v1, k, v, k3, v3)
9696
else if (k == k3) new Map3(k1, v1, k2, v2, k, v)
9797
else new Map4(k1, v1, k2, v2, k3, v3, k, v)
98-
def mapValues[V1 >: V <: AnyRef](f: (K, V1) => V1) = {
98+
def mapValuesNow[V1 >: V <: AnyRef](f: (K, V1) => V1) = {
9999
val w1 = f(k1, v1); val w2 = f(k2, v2); val w3 = f(k3, v3)
100100
if ((v1 eq w1) && (v2 eq w2) && (v3 eq w3)) this
101101
else new Map3(k1, w1, k2, w2, k3, w3)
@@ -123,7 +123,7 @@ object SimpleMap {
123123
else if (k == k3) new Map4(k1, v1, k2, v2, k, v, k4, v4)
124124
else if (k == k4) new Map4(k1, v1, k2, v2, k3, v3, k, v)
125125
else new MapMore(Array[AnyRef](k1, v1, k2, v2, k3, v3, k4, v4, k, v))
126-
def mapValues[V1 >: V <: AnyRef](f: (K, V1) => V1) = {
126+
def mapValuesNow[V1 >: V <: AnyRef](f: (K, V1) => V1) = {
127127
val w1 = f(k1, v1); val w2 = f(k2, v2); val w3 = f(k3, v3); val w4 = f(k4, v4)
128128
if ((v1 eq w1) && (v2 eq w2) && (v3 eq w3) && (v4 eq w4)) this
129129
else new Map4(k1, w1, k2, w2, k3, w3, k4, w4)
@@ -197,7 +197,7 @@ object SimpleMap {
197197
false
198198
}
199199

200-
def mapValues[V1 >: V <: AnyRef](f: (K, V1) => V1) = {
200+
def mapValuesNow[V1 >: V <: AnyRef](f: (K, V1) => V1) = {
201201
var bindings1: Array[AnyRef] = bindings
202202
var i = 0
203203
while (i < bindings.length) {

tests/pending/pos/t8230a.scala renamed to tests/pos/t8230a.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ object Test {
1515
object Okay {
1616
Arr("1")
1717

18-
import I.{ arrToTrav, longArrToTrav }
19-
foo(Arr("2"))
20-
}
18+
import I.{ arrToTrav, longArrToTrav }
19+
val x = foo(Arr("2"))
20+
}
2121

2222
object Fail {
2323
import I.arrToTrav

0 commit comments

Comments
 (0)