diff options
author | Martin Odersky <odersky@gmail.com> | 2017-03-19 12:44:27 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2017-04-06 13:15:29 +0200 |
commit | 8d33ca7460493427055daaecca53c66127772831 (patch) | |
tree | 2c8f539d138a1374dde36c58ffb2f1d4c0841dfa /compiler | |
parent | 15317555c94f613f266d7b0fb0a75b0b6ed2da6d (diff) | |
download | dotty-8d33ca7460493427055daaecca53c66127772831.tar.gz dotty-8d33ca7460493427055daaecca53c66127772831.tar.bz2 dotty-8d33ca7460493427055daaecca53c66127772831.zip |
Merge MethodType and PolyType functionality where possible
Two benefits: (1) less code. (2) finding subtle bugs about
parameter dependent method types. By merging with PolyTypes
we are forced to take parameter dependencies into account.
Diffstat (limited to 'compiler')
12 files changed, 78 insertions, 130 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 9360cabb1..b70fcb093 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -150,7 +150,7 @@ class Definitions { private def enterPolyMethod(cls: ClassSymbol, name: TermName, typeParamCount: Int, resultTypeFn: PolyType => Type, flags: FlagSet = EmptyFlags) = { - val tparamNames = tpnme.syntheticTypeParamNames(typeParamCount) + val tparamNames = PolyType.syntheticParamNames(typeParamCount) val tparamInfos = tparamNames map (_ => TypeBounds.empty) val ptype = PolyType(tparamNames)(_ => tparamInfos, resultTypeFn) enterMethod(cls, name, ptype, flags) diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 7e552eda9..7341b96af 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -252,13 +252,12 @@ object Denotations { else throw new Error(s"cannot merge ${showType(tp1)} with ${showType(tp2)}") // flip condition for debugging } - /** Merge two lists of names. If names in corresponding positions match, keep them, + /** Merge parameter names of lambda types. If names in corresponding positions match, keep them, * otherwise generate new synthetic names. */ - def mergeNames[N <: Name](names1: List[N], names2: List[N], syntheticName: Int => N): List[N] = { - for ((name1, name2, idx) <- (names1, names2, 0 until names1.length).zipped) - yield if (name1 == name2) name1 else syntheticName(idx) - }.toList + private def mergeParamNames(tp1: LambdaType, tp2: LambdaType): List[tp1.ThisName] = + (for ((name1, name2, idx) <- (tp1.paramNames, tp2.paramNames, tp1.paramNames.indices).zipped) + yield if (name1 == name2) name1 else tp1.companion.syntheticParamName(idx)).toList /** Form a denotation by conjoining with denotation `that`. * @@ -308,27 +307,17 @@ object Denotations { case tp2: TypeBounds if tp2 contains tp1 => tp1 case _ => mergeConflict(tp1, tp2) } - case tp1: MethodType if isTerm => + case tp1: MethodOrPoly => tp2 match { - case tp2: MethodType if ctx.typeComparer.matchingParams(tp1.paramInfos, tp2.paramInfos, tp1.isJava, tp2.isJava) && - tp1.isImplicit == tp2.isImplicit => + case tp2: MethodOrPoly + if ctx.typeComparer.matchingParams(tp1, tp2) && + tp1.isImplicit == tp2.isImplicit => tp1.derivedLambdaType( - mergeNames(tp1.paramNames, tp2.paramNames, nme.syntheticParamName), - tp1.paramInfos, + mergeParamNames(tp1, tp2), tp1.paramInfos, infoMeet(tp1.resultType, tp2.resultType.subst(tp2, tp1))) case _ => mergeConflict(tp1, tp2) } - case tp1: PolyType if isTerm => - tp2 match { - case tp2: PolyType if ctx.typeComparer.matchingTypeParams(tp1, tp2) => - tp1.derivedLambdaType( - mergeNames(tp1.paramNames, tp2.paramNames, tpnme.syntheticTypeParamName), - tp1.paramInfos, - infoMeet(tp1.resultType, tp2.resultType.subst(tp2, tp1))) - case _: MethodicType => - mergeConflict(tp1, tp2) - } case _ => tp1 & tp2 } @@ -471,23 +460,14 @@ object Denotations { case tp2: TypeBounds if tp2 contains tp1 => tp2 case _ => mergeConflict(tp1, tp2) } - case tp1: MethodType => - tp2 match { - case tp2: MethodType - if ctx.typeComparer.matchingParams(tp1.paramInfos, tp2.paramInfos, tp1.isJava, tp2.isJava) && - tp1.isImplicit == tp2.isImplicit => - tp1.derivedLambdaType( - mergeNames(tp1.paramNames, tp2.paramNames, nme.syntheticParamName), - tp1.paramInfos, tp1.resultType | tp2.resultType.subst(tp2, tp1)) - case _ => - mergeConflict(tp1, tp2) - } - case tp1: PolyType => + case tp1: MethodOrPoly => tp2 match { - case tp2: PolyType if ctx.typeComparer.matchingTypeParams(tp1, tp2) => + case tp2: MethodOrPoly + if ctx.typeComparer.matchingParams(tp1, tp2) && + tp1.isImplicit == tp2.isImplicit => tp1.derivedLambdaType( - mergeNames(tp1.paramNames, tp2.paramNames, tpnme.syntheticTypeParamName), - tp1.paramInfos, tp1.resultType | tp2.resultType.subst(tp2, tp1)) + mergeParamNames(tp1, tp2), tp1.paramInfos, + tp1.resultType | tp2.resultType.subst(tp2, tp1)) case _ => mergeConflict(tp1, tp2) } diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index 30fa03537..e7928fd09 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -722,9 +722,6 @@ object StdNames { case _ => termName("_" + j) } - def syntheticParamNames(num: Int): List[TermName] = - (0 until num).map(syntheticParamName)(breakOut) - def localDummyName(clazz: Symbol)(implicit ctx: Context): TermName = LOCALDUMMY_PREFIX ++ clazz.name ++ ">" @@ -747,9 +744,6 @@ object StdNames { def syntheticTypeParamName(i: Int): TypeName = "X" + i - def syntheticTypeParamNames(num: Int): List[TypeName] = - (0 until num).map(syntheticTypeParamName)(breakOut) - final val Conforms = encode("<:<") final val Uninstantiated: TypeName = "?$" diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 0ce61de95..56acbd9d6 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1146,8 +1146,7 @@ object SymDenotations { case tp: NamedType => hasSkolems(tp.prefix) case tp: RefinedType => hasSkolems(tp.parent) || hasSkolems(tp.refinedInfo) case tp: RecType => hasSkolems(tp.parent) - case tp: TypeLambda => tp.paramInfos.exists(hasSkolems) || hasSkolems(tp.resType) - case tp: MethodType => tp.paramInfos.exists(hasSkolems) || hasSkolems(tp.resType) + case tp: LambdaType => tp.paramInfos.exists(hasSkolems) || hasSkolems(tp.resType) case tp: ExprType => hasSkolems(tp.resType) case tp: HKApply => hasSkolems(tp.tycon) || tp.args.exists(hasSkolems) case tp: AndOrType => hasSkolems(tp.tp1) || hasSkolems(tp.tp2) diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 131c31d6b..173520a10 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -428,9 +428,9 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { compareRec case tp2 @ HKApply(tycon2, args2) => compareHkApply2(tp1, tp2, tycon2, args2) - case tp2: TypeLambda => + case tp2: HKTypeLambda => def compareTypeLambda: Boolean = tp1.stripTypeVar match { - case tp1: TypeLambda if tp1.isInstanceOf[PolyType] == tp2.isInstanceOf[PolyType] => + case tp1: TypeLambda => /* Don't compare bounds of lambdas under language:Scala2, or t2994 will fail * The issue is that, logically, bounds should compare contravariantly, * but that would invalidate a pattern exploited in t2994: @@ -484,12 +484,12 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { case _ => } either(isSubType(tp1, tp21), isSubType(tp1, tp22)) || fourthTry(tp1, tp2) - case tp2: MethodType => + case tp2: MethodOrPoly => def compareMethod = tp1 match { - case tp1: MethodType => + case tp1: MethodOrPoly => (tp1.signature consistentParams tp2.signature) && - matchingParams(tp1.paramInfos, tp2.paramInfos, tp1.isJava, tp2.isJava) && - (tp1.isImplicit == tp2.isImplicit) && + matchingParams(tp1, tp2) && + tp1.isImplicit == tp2.isImplicit && isSubType(tp1.resultType, tp2.resultType.subst(tp2, tp1)) case _ => false @@ -1021,7 +1021,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { tp2.widen match { case tp2: MethodType => // implicitness is ignored when matching - matchingParams(tp1.paramInfos, tp2.paramInfos, tp1.isJava, tp2.isJava) && + matchingParams(tp1, tp2) && matchesType(tp1.resultType, tp2.resultType.subst(tp2, tp1), relaxed) case tp2 => relaxed && tp1.paramNames.isEmpty && @@ -1031,7 +1031,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { tp2.widen match { case tp2: PolyType => sameLength(tp1.paramNames, tp2.paramNames) && - matchesType(tp1.resultType, tp2.resultType.subst(tp2, tp1), relaxed) + matchesType(tp1.resultType, tp2.resultType.subst(tp2, tp1), relaxed) case _ => false } @@ -1047,28 +1047,28 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { } } - /** Are `syms1` and `syms2` parameter lists with pairwise equivalent types? */ - def matchingParams(formals1: List[Type], formals2: List[Type], isJava1: Boolean, isJava2: Boolean): Boolean = formals1 match { - case formal1 :: rest1 => - formals2 match { - case formal2 :: rest2 => - (isSameTypeWhenFrozen(formal1, formal2) - || isJava1 && (formal2 isRef ObjectClass) && (formal1 isRef AnyClass) - || isJava2 && (formal1 isRef ObjectClass) && (formal2 isRef AnyClass)) && - matchingParams(rest1, rest2, isJava1, isJava2) - case nil => - false - } - case nil => - formals2.isEmpty - } - - /** Do generic types `poly1` and `poly2` have type parameters that - * have the same bounds (after renaming one set to the other)? + /** Do lambda types `lam1` and `lam2` have parameters that have the same types + * and the same implicit status? (after renaming one set to the other) */ - def matchingTypeParams(poly1: PolyType, poly2: PolyType): Boolean = - (poly1.paramInfos corresponds poly2.paramInfos)((b1, b2) => - isSameType(b1, b2.subst(poly2, poly1))) + def matchingParams(lam1: MethodOrPoly, lam2: MethodOrPoly): Boolean = { + /** Are `syms1` and `syms2` parameter lists with pairwise equivalent types? */ + def loop(formals1: List[Type], formals2: List[Type]): Boolean = formals1 match { + case formal1 :: rest1 => + formals2 match { + case formal2 :: rest2 => + val formal2a = if (lam2.isParamDependent) formal2.subst(lam2, lam1) else formal2 + (isSameTypeWhenFrozen(formal1, formal2a) + || lam1.isJava && (formal2 isRef ObjectClass) && (formal1 isRef AnyClass) + || lam2.isJava && (formal1 isRef ObjectClass) && (formal2 isRef AnyClass)) && + loop(rest1, rest2) + case nil => + false + } + case nil => + formals2.isEmpty + } + loop(lam1.paramInfos, lam2.paramInfos) + } // Type equality =:= @@ -1281,7 +1281,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { original(tp1.appliedTo(tp1.typeParams.map(_.paramInfoAsSeenFrom(tp1))), tp2) else HKTypeLambda( - paramNames = (tpnme.syntheticTypeParamNames(tparams1.length), tparams1, tparams2) + paramNames = (HKTypeLambda.syntheticParamNames(tparams1.length), tparams1, tparams2) .zipped.map((pname, tparam1, tparam2) => pname.withVariance((tparam1.paramVariance + tparam2.paramVariance) / 2)))( paramInfosExp = tl => (tparams1, tparams2).zipped.map((tparam1, tparam2) => diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 1855e3376..dd314c589 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -215,17 +215,15 @@ object Types { /** Is this the type of a method that has a repeated parameter type as * last parameter type? */ - def isVarArgsMethod(implicit ctx: Context): Boolean = this match { - case tp: PolyType => tp.resultType.isVarArgsMethod + def isVarArgsMethod(implicit ctx: Context): Boolean = stripPoly match { case mt: MethodType => mt.paramInfos.nonEmpty && mt.paramInfos.last.isRepeatedParam case _ => false } /** Is this the type of a method with a leading empty parameter list? */ - def isNullaryMethod(implicit ctx: Context): Boolean = this match { + def isNullaryMethod(implicit ctx: Context): Boolean = stripPoly match { case MethodType(Nil) => true - case tp: PolyType => tp.resultType.isNullaryMethod case _ => false } @@ -2355,7 +2353,11 @@ object Types { override def resultType(implicit ctx: Context) = resType + def isJava: Boolean = false + def isImplicit = false + def isDependent(implicit ctx: Context): Boolean + def isParamDependent(implicit ctx: Context): Boolean final def isTermLambda = paramNames.head.isTermName final def isTypeLambda = paramNames.head.isTypeName @@ -2369,7 +2371,7 @@ object Types { if (isDependent) resultType.substParams(this, argTypes) else resultType - protected def companion: LambdaTypeCompanion[ThisName, PInfo, This] + def companion: LambdaTypeCompanion[ThisName, PInfo, This] /** The type `[tparams := paramRefs] tp`, where `tparams` can be * either a list of type parameter symbols or a list of lambda parameters @@ -2519,11 +2521,6 @@ object Types { type This = MethodType - protected def companion: MethodTypeCompanion - - def isJava = false - def isImplicit = false - val paramInfos = paramInfosExp(this) val resType = resultTypeExp(this) assert(resType.exists) @@ -2554,7 +2551,12 @@ object Types { } abstract class LambdaTypeCompanion[N <: Name, PInfo <: Type, LT <: LambdaType] { - def syntheticParamNames(n: Int): List[N] + def syntheticParamName(n: Int): N + + @sharable private val memoizedNames = new mutable.HashMap[Int, List[N]] + def syntheticParamNames(n: Int): List[N] = synchronized { + memoizedNames.getOrElseUpdate(n, (0 until n).map(syntheticParamName).toList) + } def apply(paramNames: List[N])(paramInfosExp: LT => List[PInfo], resultTypeExp: LT => Type)(implicit ctx: Context): LT def apply(paramNames: List[N], paramInfos: List[PInfo], resultType: Type)(implicit ctx: Context): LT = @@ -2576,12 +2578,12 @@ object Types { abstract class TermLambdaCompanion[LT <: TermLambda] extends LambdaTypeCompanion[TermName, Type, LT] { - def syntheticParamNames(n: Int) = nme.syntheticParamNames(n) + def syntheticParamName(n: Int) = nme.syntheticParamName(n) } abstract class TypeLambdaCompanion[LT <: TypeLambda] extends LambdaTypeCompanion[TypeName, TypeBounds, LT] { - def syntheticParamNames(n: Int) = tpnme.syntheticTypeParamNames(n) + def syntheticParamName(n: Int) = tpnme.syntheticTypeParamName(n) } abstract class MethodTypeCompanion extends TermLambdaCompanion[MethodType] { @@ -2653,6 +2655,7 @@ object Types { type This <: TypeLambda def isDependent(implicit ctx: Context): Boolean = true + def isParamDependent(implicit ctx: Context): Boolean = true def newParamRef(n: Int) = TypeParamRef(this, n) @@ -3422,8 +3425,7 @@ object Types { object SAMType { def zeroParamClass(tp: Type)(implicit ctx: Context): Type = tp match { case tp: ClassInfo => - def zeroParams(tp: Type): Boolean = tp match { - case pt: PolyType => zeroParams(pt.resultType) + def zeroParams(tp: Type): Boolean = tp.stripPoly match { case mt: MethodType => mt.paramInfos.isEmpty && !mt.resultType.isInstanceOf[MethodType] case et: ExprType => true case _ => false @@ -3541,27 +3543,18 @@ object Types { variance = -variance derivedTypeBounds(tp, lo1, this(tp.hi)) - case tp: MethodType => - def mapOverMethod = { + case tp: LambdaType => + def mapOverLambda = { variance = -variance - val ptypes1 = tp.paramInfos mapConserve this + val ptypes1 = tp.paramInfos.mapConserve(this).asInstanceOf[List[tp.PInfo]] variance = -variance derivedLambdaType(tp)(ptypes1, this(tp.resultType)) } - mapOverMethod + mapOverLambda case tp: ExprType => derivedExprType(tp, this(tp.resultType)) - case tp: TypeLambda => - def mapOverPoly = { - variance = -variance - val bounds1 = tp.paramInfos.mapConserve(this).asInstanceOf[List[TypeBounds]] - variance = -variance - derivedLambdaType(tp)(bounds1, this(tp.resultType)) - } - mapOverPoly - case tp: RecType => derivedRecType(tp, this(tp.parent)) @@ -3769,7 +3762,7 @@ object Types { this(y, hi) } - case tp: MethodType => + case tp: LambdaType => variance = -variance val y = foldOver(x, tp.paramInfos) variance = -variance @@ -3778,12 +3771,6 @@ object Types { case ExprType(restpe) => this(x, restpe) - case tp: TypeLambda => - variance = -variance - val y = foldOver(x, tp.paramInfos) - variance = -variance - this(y, tp.resultType) - case tp: RecType => this(x, tp.parent) @@ -3884,9 +3871,7 @@ object Types { apply(x, tp.tref) case tp: ConstantType => apply(x, tp.underlying) - case tp: TermParamRef => - apply(x, tp.underlying) - case tp: TypeParamRef => + case tp: ParamRef => apply(x, tp.underlying) case _ => foldOver(x, tp) diff --git a/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala b/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala index 28ce9aa5a..0a061c841 100644 --- a/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala +++ b/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala @@ -256,9 +256,7 @@ private class ExtractDependenciesCollector(implicit val ctx: Context) extends tp traverse(tp.underlying) case tp: ConstantType => traverse(tp.underlying) - case tp: TermParamRef => - traverse(tp.underlying) - case tp: TypeParamRef => + case tp: ParamRef => traverse(tp.underlying) case _ => traverseChildren(tp) diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 25c9c13d8..4e43e429b 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -1284,8 +1284,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => case x => x } - def sizeFits(alt: TermRef, tp: Type): Boolean = tp match { - case tp: PolyType => sizeFits(alt, tp.resultType) + def sizeFits(alt: TermRef, tp: Type): Boolean = tp.stripPoly match { case tp: MethodType => val ptypes = tp.paramInfos val numParams = ptypes.length diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 703d2fc3c..6c0be51df 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -107,9 +107,8 @@ object Implicits { !(isFunctionInS2 || isImplicitConverter || isConforms) } - def discardForValueType(tpw: Type): Boolean = tpw match { + def discardForValueType(tpw: Type): Boolean = tpw.stripPoly match { case tpw: MethodType => !tpw.isImplicit - case tpw: PolyType => discardForValueType(tpw.resultType) case _ => false } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 9a9e45941..723e7007f 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -748,7 +748,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit case _ => } val ofFun = - if (nme.syntheticParamNames(args.length + 1) contains param.name) + if (MethodType.syntheticParamNames(args.length + 1) contains param.name) i" of expanded function $tree" else "" @@ -1285,9 +1285,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit * @param psym Its type symbol * @param cinfo The info of its constructor */ - def maybeCall(ref: Tree, psym: Symbol, cinfo: Type): Tree = cinfo match { - case cinfo: PolyType => - maybeCall(ref, psym, cinfo.resultType) + def maybeCall(ref: Tree, psym: Symbol, cinfo: Type): Tree = cinfo.stripPoly match { case cinfo @ MethodType(Nil) if cinfo.resultType.isInstanceOf[ImplicitMethodType] => val icall = New(ref).select(nme.CONSTRUCTOR).appliedToNone typedExpr(untpd.TypedSplice(icall))(superCtx) diff --git a/compiler/src/dotty/tools/dotc/typer/VarianceChecker.scala b/compiler/src/dotty/tools/dotc/typer/VarianceChecker.scala index d5dd5a024..f88098519 100644 --- a/compiler/src/dotty/tools/dotc/typer/VarianceChecker.scala +++ b/compiler/src/dotty/tools/dotc/typer/VarianceChecker.scala @@ -88,10 +88,8 @@ class VarianceChecker()(implicit ctx: Context) { if (sym.variance != 0 && base.isContainedIn(sym.owner)) checkVarianceOfSymbol(sym) else if (sym.isAliasType) this(status, sym.info.bounds.hi) else foldOver(status, tp) - case tp: MethodType => - this(status, tp.resultType) // params will be checked in their TypeDef nodes. - case tp: PolyType => - this(status, tp.resultType) // params will be checked in their ValDef nodes. + case tp: MethodOrPoly => + this(status, tp.resultType) // params will be checked in their TypeDef or ValDef nodes. case AnnotatedType(_, annot) if annot.symbol == defn.UncheckedVarianceAnnot => status //case tp: ClassInfo => diff --git a/compiler/src/dotty/tools/dotc/typer/Variances.scala b/compiler/src/dotty/tools/dotc/typer/Variances.scala index 83ac23f7e..aeeef0275 100644 --- a/compiler/src/dotty/tools/dotc/typer/Variances.scala +++ b/compiler/src/dotty/tools/dotc/typer/Variances.scala @@ -79,7 +79,7 @@ object Variances { varianceInType(parent)(tparam) & varianceInType(rinfo)(tparam) case tp: RecType => varianceInType(tp.parent)(tparam) - case tp: MethodType => + case tp: MethodOrPoly => flip(varianceInTypes(tp.paramInfos)(tparam)) & varianceInType(tp.resultType)(tparam) case ExprType(restpe) => varianceInType(restpe)(tparam) @@ -94,8 +94,6 @@ object Variances { v } varianceInArgs(varianceInType(tycon)(tparam), args, tycon.typeParams) - case tp: PolyType => - flip(varianceInTypes(tp.paramInfos)(tparam)) & varianceInType(tp.resultType)(tparam) case AnnotatedType(tp, annot) => varianceInType(tp)(tparam) & varianceInAnnot(annot)(tparam) case tp: AndOrType => |