@@ -230,12 +230,47 @@ trait ConstraintHandling {
230
230
}
231
231
232
232
/** The instance type of `param` in the current constraint (which contains `param`).
233
- * If `fromBelow` is true, the instance type is the lub of the parameter's
234
- * lower bounds; otherwise it is the glb of its upper bounds. However,
235
- * a lower bound instantiation can be a singleton type only if the upper bound
236
- * is also a singleton type.
233
+ * The instance type TI is computed depending on the given variance as follows:
234
+ *
235
+ * If `variance < 0`, `TI` is the glb of `param`'s upper bounds.
236
+ * If `variance > 0`, `TI` is the lub of `param`'s lower bounds.
237
+ * However, if `TI` would be a singleton type, and the upper bound is
238
+ * not a singleton type, `TI` is widened to a non-singleton type.
239
+ * If `variance = 0`, let `Lo1` be the lower bound of `param` and let `Lo2` be the
240
+ * |-dominator of `Lo1`. If `Lo2` is not more ugly than `Lo1`, we add the
241
+ * additional constraint that `param` should be a supertype of `Lo2`.
242
+ * We then proceed as if `variance > 0`.
243
+ *
244
+ * The reason for tweaking the `variance = 0` case is that in this case we have to make
245
+ * a guess, since no possible instance type is better than the other. We apply the heuristic
246
+ * that usually an |-type is not what is intended. E.g. given two cases of types
247
+ * `Some[Int]` and `None`, we'd naturally want `Option[Int]` as the inferred type, not
248
+ * `Some[Int] | None`. If `variance > 0` it's OK to infer the smaller `|-type` since
249
+ * we can always widen later to the intended type. But in non-variant situations, we
250
+ * have to stick to the initial guess.
251
+ *
252
+ * On the other hand, sometimes the |-dominator is _not_ what we want. For instance, taking
253
+ * run/hmap.scala as an example, we have a lower bound
254
+ *
255
+ * HEntry[$param$5, V] | HEntry[String("name"), V]
256
+ *
257
+ * Its |-dominator is
258
+ *
259
+ * HEntry[_ >: $param$11 & String("cat") <: String, V]
260
+ *
261
+ * If we apply the additional constraint we get compilation failures because while
262
+ * we can find implicits for the |-type above, we cannot find implicits for the |-dominator.
263
+ * There's no hard criterion what should be considered ugly or not. For now we
264
+ * pick the degree of undefinedness of type parameters, i.e. how many type
265
+ * parameters are instantiated with wildcard types. Maybe we have to refine this
266
+ * in the future.
267
+ *
268
+ * The whole thing is clearly not nice, and I would love to have a better criterion.
269
+ * In principle we are grappling with the fundamental shortcoming that local type inference
270
+ * sometimes has to guess what was intended. The more refined our type lattice becomes,
271
+ * the harder it is to make a choice.
237
272
*/
238
- def instanceType (param : TypeParamRef , fromBelow : Boolean ): Type = {
273
+ def instanceType (param : TypeParamRef , variance : Int ): Type = {
239
274
def upperBound = constraint.fullUpperBound(param)
240
275
def isSingleton (tp : Type ): Boolean = tp match {
241
276
case tp : SingletonType => true
@@ -257,22 +292,44 @@ trait ConstraintHandling {
257
292
case _ => false
258
293
}
259
294
260
- // First, solve the constraint.
295
+ // First, consider whether we need to constrain with |-dominator
296
+ if (variance == 0 ) {
297
+ val lo1 = ctx.typeComparer.bounds(param).lo
298
+ val lo2 = ctx.orDominator(lo1)
299
+ if (lo1 ne lo2) {
300
+ val ugliness = new TypeAccumulator [Int ] {
301
+ def apply (x : Int , tp : Type ) = tp match {
302
+ case tp : TypeBounds if ! tp.isAlias => apply(apply(x + 1 , tp.lo), tp.hi)
303
+ case tp : AndOrType => apply(x, tp.tp1) max apply(x, tp.tp2)
304
+ case _ => foldOver(x, tp)
305
+ }
306
+ }
307
+ if (ugliness(0 , lo2) <= ugliness(0 , lo1)) {
308
+ constr.println(i " apply additional constr $lo2 <: $param, was $lo1" )
309
+ lo2 <:< param
310
+ }
311
+ }
312
+ }
313
+
314
+ // Then, solve the constraint.
315
+ val fromBelow = variance >= 0
261
316
var inst = approximation(param, fromBelow)
262
317
263
- // Then, approximate by (1.) - (3.) and simplify as follows.
264
- // 1. If instance is from below and is a singleton type, yet
318
+ // Then, if instance is from below and is a singleton type, yet
265
319
// upper bound is not a singleton type, widen the instance.
266
320
if (fromBelow && isSingleton(inst) && ! isSingleton(upperBound))
267
321
inst = inst.widen
268
322
323
+ // Then, simplify.
269
324
inst = inst.simplified
270
325
271
- // 2. If instance is from below and is a fully-defined union type, yet upper bound
272
- // is not a union type, approximate the union type from above by an intersection
273
- // of all common base types.
274
- if (fromBelow && isOrType(inst) && isFullyDefined(inst) && ! isOrType(upperBound))
326
+ // Finally, if the instance is from below and is a fully-defined union type, yet upper bound
327
+ // is not a union type, harmonize the union type.
328
+ // TODO: See whether we can merge this with the special treatment of dependent params in
329
+ // simplified.
330
+ if (fromBelow && isOrType(inst) && isFullyDefined(inst) && ! isOrType(upperBound)) {
275
331
inst = ctx.harmonizeUnion(inst)
332
+ }
276
333
277
334
inst
278
335
}
0 commit comments