@@ -10,7 +10,7 @@ import TypeOps.refineUsingParent
1010import collection .mutable
1111import util .{Stats , NoSourcePosition , EqHashMap }
1212import config .Config
13- import config .Feature .{migrateTo3 , sourceVersion }
13+ import config .Feature .{betterMatchTypeExtractorsEnabled , migrateTo3 , sourceVersion }
1414import config .Printers .{subtyping , gadts , matchTypes , noPrinter }
1515import config .SourceVersion
1616import TypeErasure .{erasedLub , erasedGlb }
@@ -3518,20 +3518,77 @@ class MatchReducer(initctx: Context) extends TypeComparer(initctx) {
35183518 false
35193519
35203520 case MatchTypeCasePattern .TypeMemberExtractor (typeMemberName, capture) =>
3521+ /** Try to remove references to `skolem` from a type in accordance with the spec.
3522+ *
3523+ * If `betterMatchTypeExtractorsEnabled` is enabled then references
3524+ * to `skolem` occuring are avoided by following aliases and
3525+ * singletons, otherwise no attempt made to avoid references to
3526+ * `skolem`.
3527+ *
3528+ * If any reference to `skolem` remains in the result type,
3529+ * `refersToSkolem` is set to true.
3530+ */
3531+ class DropSkolemMap (skolem : SkolemType ) extends TypeMap :
3532+ var refersToSkolem = false
3533+ def apply (tp : Type ): Type =
3534+ if refersToSkolem then
3535+ return tp
3536+ tp match
3537+ case `skolem` =>
3538+ refersToSkolem = true
3539+ tp
3540+ case tp : NamedType if betterMatchTypeExtractorsEnabled =>
3541+ val pre1 = apply(tp.prefix)
3542+ if refersToSkolem then
3543+ tp match
3544+ case tp : TermRef => tp.info.widenExpr.dealias match
3545+ case info : SingletonType =>
3546+ refersToSkolem = false
3547+ apply(info)
3548+ case _ =>
3549+ tp.derivedSelect(pre1)
3550+ case tp : TypeRef => tp.info match
3551+ case info : AliasingBounds =>
3552+ refersToSkolem = false
3553+ apply(info.alias)
3554+ case _ =>
3555+ tp.derivedSelect(pre1)
3556+ else
3557+ tp.derivedSelect(pre1)
3558+ case tp : LazyRef if betterMatchTypeExtractorsEnabled =>
3559+ // By default, TypeMap maps LazyRefs lazily. We need to
3560+ // force it for `refersToSkolem` to be correctly set.
3561+ apply(tp.ref)
3562+ case _ =>
3563+ mapOver(tp)
3564+ end DropSkolemMap
3565+ /** Try to remove references to `skolem` from `u` in accordance with the spec.
3566+ *
3567+ * If any reference to `skolem` remains in the result type, return
3568+ * NoType instead.
3569+ */
3570+ def dropSkolem (u : Type , skolem : SkolemType ): Type =
3571+ val dmap = DropSkolemMap (skolem)
3572+ val res = dmap(u)
3573+ if dmap.refersToSkolem then NoType else res
3574+
35213575 val stableScrut : SingletonType = scrut match
35223576 case scrut : SingletonType => scrut
35233577 case _ => SkolemType (scrut)
3578+
35243579 stableScrut.member(typeMemberName) match
35253580 case denot : SingleDenotation if denot.exists =>
35263581 val info = denot.info match
35273582 case alias : AliasingBounds => alias.alias // Extract the alias
35283583 case ClassInfo (prefix, cls, _, _, _) => prefix.select(cls) // Re-select the class from the prefix
35293584 case info => info // Notably, RealTypeBounds, which will eventually give a MatchResult.NoInstances
3530- val infoRefersToSkolem = stableScrut.isInstanceOf [SkolemType ] && stableScrut.occursIn(info)
3531- val info1 = info match
3532- case info : TypeBounds => info // Will already trigger a MatchResult.NoInstances
3533- case _ if infoRefersToSkolem => RealTypeBounds (info, info) // Explicitly trigger a MatchResult.NoInstances
3534- case _ => info // We have a match
3585+ val info1 = stableScrut match
3586+ case skolem : SkolemType =>
3587+ dropSkolem(info, skolem).orElse:
3588+ info match
3589+ case info : TypeBounds => info // Will already trigger a MatchResult.NoInstances
3590+ case _ => RealTypeBounds (info, info) // Explicitly trigger a MatchResult.NoInstances
3591+ case _ => info
35353592 rec(capture, info1, variance = 0 , scrutIsWidenedAbstract)
35363593 case _ =>
35373594 false
0 commit comments