@@ -300,10 +300,14 @@ abstract class Recheck extends Phase, SymTransformer:
300
300
301
301
val rawType = recheck(tree.expr)
302
302
val ownType = avoidMap(rawType)
303
+
303
304
// The pattern matching translation, which runs before this phase
304
305
// sometimes instantiates return types with singleton type alternatives
305
306
// but the returned expression is widened. We compensate by widening the expected
306
- // type as well.
307
+ // type as well. See also `widenSkolems` in `checkConformsExpr` which fixes
308
+ // a more general problem. It turns out that pattern matching returns
309
+ // are not checked by Ycheck, that's why these problems were allowed to slip
310
+ // through.
307
311
def widened (tp : Type ): Type = tp match
308
312
case tp : SingletonType => tp.widen
309
313
case tp : AndOrType => tp.derivedAndOrType(widened(tp.tp1), widened(tp.tp2))
@@ -435,6 +439,27 @@ abstract class Recheck extends Phase, SymTransformer:
435
439
throw ex
436
440
}
437
441
442
+ /** Typing and previous transforms sometiems leaves skolem types in prefixes of
443
+ * NamedTypes in `expected` that do not match the `actual` Type. -Ycheck does
444
+ * not complain (need to find out why), but a full recheck does. We compensate
445
+ * by de-skolemizing everywhere in `expected` except when variance is negative.
446
+ * @return If `tp` contains SkolemTypes in covariant or invariant positions,
447
+ * the type where these SkolemTypes are mapped to their underlying type.
448
+ * Otherwise, `tp` itself
449
+ */
450
+ def widenSkolems (tp : Type )(using Context ): Type =
451
+ object widenSkolems extends TypeMap , IdempotentCaptRefMap :
452
+ var didWiden : Boolean = false
453
+ def apply (t : Type ): Type = t match
454
+ case t : SkolemType if variance >= 0 =>
455
+ didWiden = true
456
+ apply(t.underlying)
457
+ case t : LazyRef => t
458
+ case t @ AnnotatedType (t1, ann) => t.derivedAnnotatedType(apply(t1), ann)
459
+ case _ => mapOver(t)
460
+ val tp1 = widenSkolems(tp)
461
+ if widenSkolems.didWiden then tp1 else tp
462
+
438
463
/** If true, print info for some successful checkConforms operations (failing ones give
439
464
* an error message in any case).
440
465
*/
@@ -450,18 +475,24 @@ abstract class Recheck extends Phase, SymTransformer:
450
475
451
476
def checkConformsExpr (actual : Type , expected : Type , tree : Tree )(using Context ): Unit =
452
477
// println(i"check conforms $actual <:< $expected")
453
- val isCompatible =
478
+
479
+ def isCompatible (expected : Type ): Boolean =
454
480
actual <:< expected
455
481
|| expected.isRepeatedParam
456
- && actual <:< expected.translateFromRepeated(toArray = tree.tpe.isRef(defn.ArrayClass ))
457
- if ! isCompatible then
482
+ && isCompatible(expected.translateFromRepeated(toArray = tree.tpe.isRef(defn.ArrayClass )))
483
+ || {
484
+ val widened = widenSkolems(expected)
485
+ (widened ne expected) && isCompatible(widened)
486
+ }
487
+ if ! isCompatible(expected) then
458
488
recheckr.println(i " conforms failed for ${tree}: $actual vs $expected" )
459
489
err.typeMismatch(tree.withType(actual), expected)
460
490
else if debugSuccesses then
461
491
tree match
462
492
case _ : Ident =>
463
493
println(i " SUCCESS $tree: \n ${TypeComparer .explained(_.isSubType(actual, expected))}" )
464
494
case _ =>
495
+ end checkConformsExpr
465
496
466
497
def checkUnit (unit : CompilationUnit )(using Context ): Unit =
467
498
recheck(unit.tpdTree)
0 commit comments