diff options
Diffstat (limited to 'src/dotty/tools/dotc/core/TypeComparer.scala')
-rw-r--r-- | src/dotty/tools/dotc/core/TypeComparer.scala | 128 |
1 files changed, 104 insertions, 24 deletions
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index cf3086323..566865eb4 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -365,11 +365,11 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { fourthTry(tp1, tp2) || compareRefinedSlow case _ => if (tp2.isTypeParam) { - compareHkLambda(tp1, tp2) || + compareHkLambdaOLD(tp1, tp2) || fourthTry(tp1, tp2) } else { - compareHkApply(tp2, tp1, inOrder = false) || + compareHkApplyOLD(tp2, tp1, inOrder = false) || compareRefinedSlow || fourthTry(tp1, tp2) || compareAliasedRefined(tp2, tp1, inOrder = false) @@ -389,6 +389,53 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { val tp1stable = ensureStableSingleton(tp1) isSubType(fixRecs(tp1stable, tp1stable.widenExpr), tp2.parent.substRecThis(tp2, tp1stable)) } + case tp2 @ HKApply(tycon2, args2) => + def compareHkApply(tycon2: Type): Boolean = tycon2 match { + case tycon2: TypeVar => compareHkApply(tycon2.underlying) + case param2: PolyParam if canConstrain(param2) => + val tparams2 = tycon2.typeParams + + def tyconOK(tycon1a: Type) = + variancesConform(tycon1a.typeParams, tparams2) && { + if (ctx.mode.is(Mode.TypevarsMissContext)) isSubType(tp1, tycon1a.appliedTo(args2)) + else tryInstantiate(param2, tycon1a) && isSubType(tp1, tp2) + } + + tp1 match { + case tp1 @ HKApply(tycon1, _) => + tyconOK(tycon1) || isSubType(tp1.upperBound, tp2) + case _ if tp1.widenDealias.typeSymbol.isClass => + val classBounds = tp2.classSymbols + def liftToBase(bcs: List[ClassSymbol]): Boolean = bcs match { + case bc :: bcs1 => + classBounds.exists(bc.derivesFrom) && tyconOK(tp1.baseTypeRef(bc)) || + liftToBase(bcs1) + case _ => + false + } + liftToBase(tp1.baseClasses) + case tp1: TypeProxy => + isSubType(tp1.underlying, tp2) + case _ => + false + } + case _ => + // TODO handle lower bounds of hk params here + false + } + compareHkApply(tycon2) || fourthTry(tp1, tp2) + case tp2 @ TypeLambda(tparams2, body2) => + def compareHkLambda = tp1.stripTypeVar match { + case tp1 @ TypeLambda(tparams1, body1) => + val boundsConform = + tparams1.corresponds(tparams2)((tparam1, tparam2) => + isSubType(tparam2.memberBounds.subst(tp2, tp1), tparam1.memberBounds)) + val bodiesConform = isSubType(body1, body2.subst(tp2, tp1)) + variancesConform(tparams1, tparams2) && boundsConform && bodiesConform + case _ => + fourthTry(tp1, tp2) + } + compareHkLambda case OrType(tp21, tp22) => // Rewrite T1 <: (T211 & T212) | T22 to T1 <: (T211 | T22) and T1 <: (T212 | T22) // and analogously for T1 <: T21 | (T221 & T222) @@ -502,11 +549,22 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { } isNewSubType(tp1.underlying.widenExpr, tp2) || comparePaths case tp1: RefinedType => - compareHkApply(tp1, tp2, inOrder = true) || + compareHkApplyOLD(tp1, tp2, inOrder = true) || isNewSubType(tp1.parent, tp2) || compareAliasedRefined(tp1, tp2, inOrder = true) case tp1: RecType => isNewSubType(tp1.parent, tp2) + case HKApply(tycon1, args1) => + tp2 match { + case AppliedType(tycon2, args2) => + assert(!tycon2.isHK) // this should have been handled by thirdTry + isSubType(tycon1, EtaExpansion(tycon2)) && + isSubArgs(args1, args2, tycon2.typeParams) + case _ => + false + } + case EtaExpansion(tycon1) => + isSubType(tycon1, tp2) case AndType(tp11, tp12) => // Rewrite (T111 | T112) & T12 <: T2 to (T111 & T12) <: T2 and (T112 | T12) <: T2 // and analogously for T11 & (T121 | T122) & T12 <: T2 @@ -537,6 +595,14 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { false } + def isSubArgs(args1: List[Type], args2: List[Type], tparams: List[MemberBinding]): Boolean = + if (args1.isEmpty) args2.isEmpty + else args2.nonEmpty && { + val v = tparams.head.memberVariance + (v > 0 || isSubType(args2.head, args1.head)) && + (v < 0 || isSubType(args1.head, args2.head)) + } + /** Test whether `tp1` has a base type of the form `B[T1, ..., Tn]` where * - `B` derives from one of the class symbols of `tp2`, * - the type parameters of `B` match one-by-one the variances of `tparams`, @@ -588,7 +654,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { * * (4) If `inOrder`, test `app <: other` else test `other <: app`. */ - def compareHkApply(app: RefinedType, other: Type, inOrder: Boolean): Boolean = { + def compareHkApplyOLD(app: RefinedType, other: Type, inOrder: Boolean): Boolean = { def tryInfer(tp: Type): Boolean = ctx.traceIndented(i"compareHK($app, $other, inOrder = $inOrder, constr = $tp)", subtyping) { tp match { case tp: TypeVar => tryInfer(tp.underlying) @@ -597,7 +663,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { def unifyWith(liftedOther: Type): Boolean = { subtyping.println(i"unify with $liftedOther") liftedOther.typeConstructor.widen match { - case tycon: TypeRef if tycon.isEtaExpandable && tycon.typeParams.nonEmpty => + case tycon: TypeRef if tycon.isEtaExpandableOLD && tycon.typeParams.nonEmpty => val (ok, app1) = if (ctx.mode.is(Mode.TypevarsMissContext)) (true, EtaExpansion(tycon).appliedTo(app.argInfos)) @@ -634,8 +700,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { false } } - app.isHKApply && !other.isHKApply && { - val reduced = if (inOrder) app else app.normalizeHkApply + app.isHKApplyOLD && !other.isHKApplyOLD && { + val reduced = if (inOrder) app else app.normalizeHkApplyOLD if (reduced ne app) if (inOrder) isSubType(reduced, other) else isSubType(other, reduced) else tryInfer(app.typeConstructor.dealias) @@ -643,11 +709,11 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { } /** Compare type lambda with non-lambda type. */ - def compareHkLambda(tp1: Type, tp2: RefinedType): Boolean = tp1.stripTypeVar match { - case TypeLambda(args1, body1) => + def compareHkLambdaOLD(tp1: Type, tp2: RefinedType): Boolean = tp1.stripTypeVar match { + case TypeLambdaOLD(args1, body1) => //println(i"comparing $tp1 <:< $tp2") tp2 match { - case TypeLambda(args2, body2) => + case TypeLambdaOLD(args2, body2) => args1.corresponds(args2)((arg1, arg2) => varianceConforms(BindingKind.toVariance(arg1.bindingKind), BindingKind.toVariance(arg2.bindingKind))) && @@ -656,7 +722,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { case _ => false } case RefinedType(parent1, _, _) => - compareHkLambda(parent1, tp2) + compareHkLambdaOLD(parent1, tp2) case _ => false } @@ -1161,22 +1227,36 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { val tparams2 = tp2.typeParams if (tparams1.isEmpty || tparams2.isEmpty) op(tp1, tp2) else if (tparams1.length != tparams2.length) mergeConflict(tp1, tp2) + else if (Config.newHK) { + val numArgs = tparams1.length + def argRefs(tl: PolyType) = List.range(0, numArgs).map(PolyParam(tl, _)) + TypeLambda( + paramNames = tpnme.syntheticLambdaParamNames(numArgs), + variances = (tparams1, tparams2).zipped.map((tparam1, tparam2) => + (tparam1.memberVariance + tparam2.memberVariance) / 2))( + paramBoundsExp = tl => (tparams1, tparams2).zipped.map((tparam1, tparam2) => + tl.lifted(tparams1, tparam1.memberBoundsAsSeenFrom(tp1)).bounds & + tl.lifted(tparams2, tparam2.memberBoundsAsSeenFrom(tp2)).bounds), + resultTypeExp = tl => + op(tl.lifted(tparams1, tp1).appliedTo(argRefs(tl)), + tl.lifted(tparams2, tp2).appliedTo(argRefs(tl)))) + } else { val bindings: List[RecType => TypeBounds] = (tparams1, tparams2).zipped.map { (tparam1, tparam2) => val b1: RecType => TypeBounds = - tparam1.memberBoundsAsSeenFrom(tp1).recursify(tparams1) + tparam1.memberBoundsAsSeenFrom(tp1).recursifyOLD(tparams1) val b2: RecType => TypeBounds = - tparam2.memberBoundsAsSeenFrom(tp2).recursify(tparams2) + tparam2.memberBoundsAsSeenFrom(tp2).recursifyOLD(tparams2) (rt: RecType) => (b1(rt) & b2(rt)) .withBindingKind( BindingKind.fromVariance( (tparam1.memberVariance + tparam2.memberVariance) / 2)) } - val app1: RecType => Type = rt => tp1.appliedTo(argRefs(rt, tparams1.length)) - val app2: RecType => Type = rt => tp2.appliedTo(argRefs(rt, tparams2.length)) + val app1: RecType => Type = rt => tp1.appliedTo(argRefsOLD(rt, tparams1.length)) + val app2: RecType => Type = rt => tp2.appliedTo(argRefsOLD(rt, tparams2.length)) val body: RecType => Type = rt => op(app1(rt), app2(rt)) - TypeLambda(bindings, body) + TypeLambdaOLD(bindings, body) } } @@ -1459,19 +1539,19 @@ class ExplainingTypeComparer(initctx: Context) extends TypeComparer(initctx) { override def copyIn(ctx: Context) = new ExplainingTypeComparer(ctx) - override def compareHkApply(app: RefinedType, other: Type, inOrder: Boolean) = - if (app.isHKApply) - traceIndented(i"compareHkApply $app, $other, $inOrder, ${app.normalizeHkApply}") { - super.compareHkApply(app, other, inOrder) + override def compareHkApplyOLD(app: RefinedType, other: Type, inOrder: Boolean) = + if (app.isHKApplyOLD) + traceIndented(i"compareHkApply $app, $other, $inOrder, ${app.normalizeHkApplyOLD}") { + super.compareHkApplyOLD(app, other, inOrder) } - else super.compareHkApply(app, other, inOrder) + else super.compareHkApplyOLD(app, other, inOrder) - override def compareHkLambda(tp1: Type, tp2: RefinedType): Boolean = + override def compareHkLambdaOLD(tp1: Type, tp2: RefinedType): Boolean = if (tp2.isTypeParam) traceIndented(i"compareHkLambda $tp1, $tp2") { - super.compareHkLambda(tp1, tp2) + super.compareHkLambdaOLD(tp1, tp2) } - else super.compareHkLambda(tp1, tp2) + else super.compareHkLambdaOLD(tp1, tp2) override def toString = "Subtype trace:" + { try b.toString finally b.clear() } } |