diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/dotty/tools/dotc/core/ConstraintHandling.scala | 12 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Symbols.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/TypeApplications.scala | 81 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/TypeComparer.scala | 7 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/TypeParamInfo.scala | 10 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Types.scala | 30 |
6 files changed, 89 insertions, 53 deletions
diff --git a/src/dotty/tools/dotc/core/ConstraintHandling.scala b/src/dotty/tools/dotc/core/ConstraintHandling.scala index c5e3bad40..18e47a7f2 100644 --- a/src/dotty/tools/dotc/core/ConstraintHandling.scala +++ b/src/dotty/tools/dotc/core/ConstraintHandling.scala @@ -300,19 +300,21 @@ trait ConstraintHandling { * to refer to such a lambda parameter because the lambda parameter is * not visible where `A` is defined. Consequently, we need to * approximate the bound so that the lambda parameter does not appear in it. - * Test case in neg/i94-nada.scala. This test crashes with an illegal instance - * error when the rest of the SI-2712 fix is applied but `pruneLambdaParams` is + * If `tp` is an upper bound, we need to approximate with something smaller, + * otherwise something larger. + * Test case in pos/i94-nada.scala. This test crashes with an illegal instance + * error in Test2 when the rest of the SI-2712 fix is applied but `pruneLambdaParams` is * missing. */ def pruneLambdaParams(tp: Type) = - if (comparingLambdas) { + if (comparingLambdas && param.binder.isInstanceOf[PolyType]) { val approx = new ApproximatingTypeMap { def apply(t: Type): Type = t match { case t @ PolyParam(tl: TypeLambda, n) => val effectiveVariance = if (fromBelow) -variance else variance val bounds = tl.paramBounds(n) - if (effectiveVariance > 0) bounds.hi - else if (effectiveVariance < 0 ) bounds.lo + if (effectiveVariance > 0) bounds.lo + else if (effectiveVariance < 0) bounds.hi else NoType case _ => mapOver(t) diff --git a/src/dotty/tools/dotc/core/Symbols.scala b/src/dotty/tools/dotc/core/Symbols.scala index 229df4576..d46ea6b0f 100644 --- a/src/dotty/tools/dotc/core/Symbols.scala +++ b/src/dotty/tools/dotc/core/Symbols.scala @@ -491,7 +491,7 @@ object Symbols { // TypeParamInfo methods def isTypeParam(implicit ctx: Context) = denot.is(TypeParam) - def paramName(implicit ctx: Context): Name = name + def paramName(implicit ctx: Context) = name.asTypeName def paramBounds(implicit ctx: Context) = denot.info.bounds def paramBoundsAsSeenFrom(pre: Type)(implicit ctx: Context) = pre.memberInfo(this).bounds def paramBoundsOrCompleter(implicit ctx: Context): Type = denot.infoOrCompleter diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala index 09f006a11..b9957ccb2 100644 --- a/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/src/dotty/tools/dotc/core/TypeApplications.scala @@ -338,10 +338,10 @@ class TypeApplications(val self: Type) extends AnyVal { * * TODO: Handle parameterized lower bounds */ - def LambdaAbstract(tparams: List[TypeParamInfo])(implicit ctx: Context): Type = { + def LambdaAbstract(tparams: List[Symbol])(implicit ctx: Context): Type = { def expand(tp: Type) = TypeLambda( - tpnme.syntheticLambdaParamNames(tparams.length), tparams.map(_.paramVariance))( + tpnme.syntheticLambdaParamNames(tparams.length), tparams.map(_.variance))( tl => tparams.map(tparam => tl.lifted(tparams, tparam.paramBounds).bounds), tl => tl.lifted(tparams, tp)) assert(!isHK, self) @@ -439,20 +439,13 @@ class TypeApplications(val self: Type) extends AnyVal { } } - /** Encode + /** The type representing * * T[U1, ..., Un] * * where * @param self = `T` * @param args = `U1,...,Un` - * performing the following simplifications - * - * 1. If `T` is an eta expansion `[X1,..,Xn] -> C[X1,...,Xn]` of class `C` compute - * `C[U1, ..., Un]` instead. - * 2. If `T` is some other type lambda `[X1,...,Xn] -> S` none of the arguments - * `U1,...,Un` is a wildcard, compute `[X1:=U1, ..., Xn:=Un]S` instead. - * 3. If `T` is a polytype, instantiate it to `U1,...,Un`. */ final def appliedTo(args: List[Type])(implicit ctx: Context): Type = /*>|>*/ track("appliedTo") /*<|<*/ { val typParams = self.typeParams @@ -469,30 +462,52 @@ class TypeApplications(val self: Type) extends AnyVal { } case nil => t } + val stripped = self.stripTypeVar + val dealiased = stripped.safeDealias if (args.isEmpty || ctx.erasedTypes) self - else self.stripTypeVar.safeDealias match { - case self: TypeLambda => - if (!args.exists(_.isInstanceOf[TypeBounds])) self.instantiate(args) - else { - val reducer = new Reducer(self, args) - val reduced = reducer(self.resType) - if (reducer.allReplaced) reduced - else HKApply(self, args) - } - case self: PolyType => - self.instantiate(args) - case self: AndOrType => - self.derivedAndOrType(self.tp1.appliedTo(args), self.tp2.appliedTo(args)) - case self: TypeAlias => - self.derivedTypeAlias(self.alias.appliedTo(args)) - case self: TypeBounds => - self.derivedTypeBounds(self.lo, self.hi.appliedTo(args)) - case self: LazyRef => - LazyRef(() => self.ref.appliedTo(args)) - case self: WildcardType => - self - case self: TypeRef if self.symbol == defn.NothingClass => - self + else dealiased match { + case dealiased: TypeLambda => + def tryReduce = + if (!args.exists(_.isInstanceOf[TypeBounds])) { + val reduced = dealiased.instantiate(args) + if (dealiased eq stripped) reduced + else reduced match { + case AppliedType(tycon, args) if variancesConform(typParams, tycon.typeParams) => + // Reducing is safe for type inference, as kind of type constructor does not change + //println(i"reduced: $reduced instead of ${HKApply(self, args)}") + reduced + case _ => + // Reducing changes kind, keep hk application instead + //println(i"fallback: ${HKApply(self, args)} instead of $reduced") + HKApply(self, args) + } + } + else dealiased.resType match { + case AppliedType(tycon, args1) if tycon.safeDealias ne tycon => + dealiased + .derivedTypeLambda(resType = tycon.safeDealias.appliedTo(args1)) + .appliedTo(args) + case _ => + val reducer = new Reducer(dealiased, args) + val reduced = reducer(dealiased.resType) + if (reducer.allReplaced) reduced + else HKApply(dealiased, args) + } + tryReduce + case dealiased: PolyType => + dealiased.instantiate(args) + case dealiased: AndOrType => + dealiased.derivedAndOrType(dealiased.tp1.appliedTo(args), dealiased.tp2.appliedTo(args)) + case dealiased: TypeAlias => + dealiased.derivedTypeAlias(dealiased.alias.appliedTo(args)) + case dealiased: TypeBounds => + dealiased.derivedTypeBounds(dealiased.lo, dealiased.hi.appliedTo(args)) + case dealiased: LazyRef => + LazyRef(() => dealiased.ref.appliedTo(args)) + case dealiased: WildcardType => + dealiased + case dealiased: TypeRef if dealiased.symbol == defn.NothingClass => + dealiased case _ if typParams.isEmpty || typParams.head.isInstanceOf[LambdaParam] => HKApply(self, args) case dealiased => diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index faa4e1b16..a763e1de8 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -628,9 +628,10 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { val tparams1 = tparams1a.drop(lengthDiff) variancesConform(tparams1, tparams) && { if (lengthDiff > 0) - tycon1b = tycon1a - .appliedTo(args1.take(lengthDiff) ++ tparams1.map(_.paramRef)) - .LambdaAbstract(tparams1) + tycon1b = TypeLambda(tparams1.map(_.paramName), tparams1.map(_.paramVariance))( + tl => tparams1.map(tparam => tl.lifted(tparams, tparam.paramBounds).bounds), + tl => tycon1a.appliedTo(args1.take(lengthDiff) ++ + tparams1.indices.toList.map(PolyParam(tl, _)))) (ctx.mode.is(Mode.TypevarsMissContext) || tryInstantiate(tycon2, tycon1b.ensureHK)) && isSubType(tp1, tycon1b.appliedTo(args2)) diff --git a/src/dotty/tools/dotc/core/TypeParamInfo.scala b/src/dotty/tools/dotc/core/TypeParamInfo.scala index 1d79e4204..647c895db 100644 --- a/src/dotty/tools/dotc/core/TypeParamInfo.scala +++ b/src/dotty/tools/dotc/core/TypeParamInfo.scala @@ -1,6 +1,6 @@ package dotty.tools.dotc.core -import Names.Name +import Names.TypeName import Contexts.Context import Types.{Type, TypeBounds} @@ -15,22 +15,22 @@ trait TypeParamInfo { def isTypeParam(implicit ctx: Context): Boolean /** The name of the type parameter */ - def paramName(implicit ctx: Context): Name + def paramName(implicit ctx: Context): TypeName /** The info of the type parameter */ def paramBounds(implicit ctx: Context): TypeBounds /** The info of the type parameter as seen from a prefix type. * For type parameter symbols, this is the `memberInfo` as seen from `prefix`. - * For type lambda parameters, it's the same as `paramBounds` as + * For type lambda parameters, it's the same as `paramBounds` as * `asSeenFrom` has already been applied to the whole type lambda. */ def paramBoundsAsSeenFrom(pre: Type)(implicit ctx: Context): TypeBounds - + /** The parameter bounds, or the completer if the type parameter * is an as-yet uncompleted symbol. */ - def paramBoundsOrCompleter(implicit ctx: Context): Type + def paramBoundsOrCompleter(implicit ctx: Context): Type /** The variance of the type parameter */ def paramVariance(implicit ctx: Context): Int diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 63f39637b..938e40128 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -117,6 +117,7 @@ object Types { case _ => this1.symbol eq sym } case this1: RefinedOrRecType => this1.parent.isRef(sym) + case this1: HKApply => this1.superType.isRef(sym) case _ => false } @@ -857,6 +858,10 @@ object Types { tp.derivedAnnotatedType(tp.tpe.dealias, tp.annot) case tp: LazyRef => tp.ref.dealias + case app @ HKApply(tycon, args) => + val tycon1 = tycon.dealias + if (tycon1 ne tycon) app.superType.dealias + else this case _ => this } @@ -2586,7 +2591,7 @@ object Types { lazy val typeParams: List[LambdaParam] = paramNames.indices.toList.map(new LambdaParam(this, _)) - def derivedTypeLambda(paramNames: List[TypeName], paramBounds: List[TypeBounds], resType: Type)(implicit ctx: Context): Type = + def derivedTypeLambda(paramNames: List[TypeName] = paramNames, paramBounds: List[TypeBounds] = paramBounds, resType: Type)(implicit ctx: Context): Type = resType match { case resType @ TypeAlias(alias) => resType.derivedTypeAlias(duplicate(paramNames, paramBounds, alias)) @@ -2640,12 +2645,21 @@ object Types { abstract case class HKApply(tycon: Type, args: List[Type]) extends CachedProxyType with ValueType { + private var validSuper: Period = Nowhere + private var cachedSuper: Type = _ + override def underlying(implicit ctx: Context): Type = tycon - override def superType(implicit ctx: Context): Type = tycon match { - case tp: TypeLambda => defn.AnyType - case tp: TypeProxy => tp.superType.applyIfParameterized(args) - case _ => defn.AnyType + override def superType(implicit ctx: Context): Type = { + if (ctx.period != validSuper) { + cachedSuper = tycon match { + case tp: TypeLambda => defn.AnyType + case tp: TypeProxy => tp.superType.applyIfParameterized(args) + case _ => defn.AnyType + } + validSuper = ctx.period + } + cachedSuper } /* def lowerBound(implicit ctx: Context): Type = tycon.stripTypeVar match { @@ -2760,7 +2774,11 @@ object Types { else bounds(paramNum) } // no customized hashCode/equals needed because cycle is broken in PolyType - override def toString = s"PolyParam($paramName)" + override def toString = + try s"PolyParam($paramName)" + catch { + case ex: IndexOutOfBoundsException => s"PolyParam(<bad index: $paramNum>)" + } override def computeHash = doHash(paramNum, binder.identityHash) |