aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2016-07-12 17:12:59 +0200
committerMartin Odersky <odersky@gmail.com>2016-07-12 18:14:04 +0200
commit84a1a7ae7b1e4931fe04a5a21a04bb858e8acebb (patch)
tree0cb537aeafff402970ce51c0790cd9ba4e8de846 /src/dotty/tools/dotc
parentcdebd91712b36b048233d7cf9501cc7a5bb50b31 (diff)
downloaddotty-84a1a7ae7b1e4931fe04a5a21a04bb858e8acebb.tar.gz
dotty-84a1a7ae7b1e4931fe04a5a21a04bb858e8acebb.tar.bz2
dotty-84a1a7ae7b1e4931fe04a5a21a04bb858e8acebb.zip
Avoid dealiasing on type application
When applying a type alias of a type lambda, keep the original application instead of reducing. But reduce anyway if - the reduced type is an application where the type constructor has the same kind as the original type constructor, or - some of the arguments are wildcards.
Diffstat (limited to 'src/dotty/tools/dotc')
-rw-r--r--src/dotty/tools/dotc/core/ConstraintHandling.scala12
-rw-r--r--src/dotty/tools/dotc/core/Symbols.scala2
-rw-r--r--src/dotty/tools/dotc/core/TypeApplications.scala81
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala7
-rw-r--r--src/dotty/tools/dotc/core/TypeParamInfo.scala10
-rw-r--r--src/dotty/tools/dotc/core/Types.scala30
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)