@@ -32,7 +32,11 @@ trait ConstraintHandling {
32
32
33
33
private var addConstraintInvocations = 0
34
34
35
- private var needsCleanup = false
35
+ /** Does `constraint` contain parameters that are instantiated but
36
+ * that have not yet been checked for removal? In that case we should
37
+ * remove them when we are at a top-level subtype check.
38
+ */
39
+ private var hasInstantiations = false
36
40
37
41
/** If the constraint is frozen we cannot add new bounds to the constraint. */
38
42
protected var frozenConstraint = false
@@ -115,7 +119,7 @@ trait ConstraintHandling {
115
119
constr.println(s " unifying $p1 $p2" )
116
120
val down = constraint.exclusiveLower(p2, p1)
117
121
val up = constraint.exclusiveUpper(p1, p2)
118
- needsCleanup = true
122
+ hasInstantiations = true
119
123
constraint = constraint.unify(p1, p2)
120
124
val bounds = constraint.nonParamBounds(p1)
121
125
val lo = bounds.lo
@@ -176,6 +180,83 @@ trait ConstraintHandling {
176
180
inst
177
181
}
178
182
183
+ /** The instance type of `param` in the current constraint (which contains `param`).
184
+ * `fromBelow` is true, the isntance type is the lub of the parameter's
185
+ * lower bounds; otherwise it is the glb of its upper bounds. However,
186
+ * a lower bound instantiation can be a singleton type only if the upper bound
187
+ * is also a singleton type.
188
+ */
189
+ def instanceType (param : PolyParam , fromBelow : Boolean ): Type = {
190
+ def upperBound = ctx.typerState.constraint.fullUpperBound(param)
191
+ def isSingleton (tp : Type ): Boolean = tp match {
192
+ case tp : SingletonType => true
193
+ case AndType (tp1, tp2) => isSingleton(tp1) | isSingleton(tp2)
194
+ case OrType (tp1, tp2) => isSingleton(tp1) & isSingleton(tp2)
195
+ case _ => false
196
+ }
197
+ def isFullyDefined (tp : Type ): Boolean = tp match {
198
+ case tp : TypeVar => tp.isInstantiated && isFullyDefined(tp.instanceOpt)
199
+ case tp : TypeProxy => isFullyDefined(tp.underlying)
200
+ case tp : AndOrType => isFullyDefined(tp.tp1) && isFullyDefined(tp.tp2)
201
+ case _ => true
202
+ }
203
+ def isOrType (tp : Type ): Boolean = tp.stripTypeVar.dealias match {
204
+ case tp : OrType => true
205
+ case tp : RefinedOrRecType => isOrType(tp.parent)
206
+ case AndType (tp1, tp2) => isOrType(tp1) | isOrType(tp2)
207
+ case WildcardType (bounds : TypeBounds ) => isOrType(bounds.hi)
208
+ case _ => false
209
+ }
210
+
211
+ // First, solve the constraint.
212
+ var inst = approximation(param, fromBelow)
213
+
214
+ // Then, approximate by (1.) - (3.) and simplify as follows.
215
+ // 1. If instance is from below and is a singleton type, yet
216
+ // upper bound is not a singleton type, widen the instance.
217
+ if (fromBelow && isSingleton(inst) && ! isSingleton(upperBound))
218
+ inst = inst.widen
219
+
220
+ inst = inst.simplified
221
+
222
+ // 2. If instance is from below and is a fully-defined union type, yet upper bound
223
+ // is not a union type, approximate the union type from above by an intersection
224
+ // of all common base types.
225
+ if (fromBelow && isOrType(inst) && isFullyDefined(inst) && ! isOrType(upperBound))
226
+ inst = inst.approximateUnion
227
+
228
+ // 3. If instance is from below, and upper bound has open named parameters
229
+ // make sure the instance has all named parameters of the bound.
230
+ if (fromBelow) inst = inst.widenToNamedTypeParams(param.namedTypeParams)
231
+
232
+ if (ctx.typerState.isGlobalCommittable)
233
+ assert(! inst.isInstanceOf [PolyParam ], i " bad inst $this := $inst, constr = ${ctx.typerState.constraint}" )
234
+ // If this fails, you might want to turn on Config.debugCheckConstraintsClosed
235
+ // to help find the root of the problem.
236
+ inst
237
+ }
238
+
239
+ def instantiateLambdaParam (param : PolyParam , variance : Int ): Type = {
240
+ val inst = instanceType(param, fromBelow = variance >= 0 )
241
+ hk.println(i " remove type lambda param $param with inst = $inst in $constraint" )
242
+ constraint = constraint.replace(param, inst, canRemove = true )
243
+ inst
244
+ }
245
+
246
+ /*
247
+ def dropConstrainedLambdas() =
248
+ if (hasConstrainedLambdas) {
249
+ constraint.domainPolys.foreach {
250
+ case tl: TypeLambda =>
251
+ tl.paramRefs.foreach { param =>
252
+ if (constraint.contains(param)) instantiateLambdaParam(param, 0)
253
+ }
254
+ case _ =>
255
+ }
256
+ hasConstrainedLambdas = false
257
+ }
258
+ */
259
+
179
260
/** Constraint `c1` subsumes constraint `c2`, if under `c2` as constraint we have
180
261
* for all poly params `p` defined in `c2` as `p >: L2 <: U2`:
181
262
*
@@ -320,13 +401,21 @@ trait ConstraintHandling {
320
401
constraint =
321
402
if (addConstraint(param, tp, fromBelow = true ) &&
322
403
addConstraint(param, tp, fromBelow = false )) {
323
- needsCleanup = true
404
+ hasInstantiations = true
324
405
constraint.replace(param, tp, canRemove = false )
325
406
}
326
407
else saved
327
408
constraint ne saved
328
409
}
329
410
411
+ /** A new constraint with all polytypes that only have instantiated parameters removed */
412
+ protected def cleanupConstraint () =
413
+ if (hasInstantiations) {
414
+ constraint =
415
+ (constraint /: constraint.domainPolys.filter(constraint.isRemovable(_)))(_.remove(_))
416
+ hasInstantiations = false
417
+ }
418
+
330
419
/** Check that constraint is fully propagated. See comment in Config.checkConstraintsPropagated */
331
420
def checkPropagated (msg : => String )(result : Boolean ): Boolean = {
332
421
if (Config .checkConstraintsPropagated && result && addConstraintInvocations == 0 ) {
@@ -346,12 +435,4 @@ trait ConstraintHandling {
346
435
}
347
436
result
348
437
}
349
-
350
- /** A new constraint with all polytypes that only have instantiated parameters removed */
351
- protected def cleanup (): Unit =
352
- if (needsCleanup) {
353
- constraint =
354
- (constraint /: constraint.domainPolys.filter(constraint.isRemovable(_)))(_.remove(_))
355
- needsCleanup = false
356
- }
357
438
}
0 commit comments