aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/config/Config.scala5
-rw-r--r--src/dotty/tools/dotc/core/TypeApplications.scala7
-rw-r--r--src/dotty/tools/dotc/core/Types.scala45
-rw-r--r--src/dotty/tools/dotc/typer/Checking.scala19
-rw-r--r--tests/neg/t7278.scala8
-rw-r--r--tests/pos-scala2/t2994.scala2
-rw-r--r--tests/pos/hklower.scala34
7 files changed, 67 insertions, 53 deletions
diff --git a/src/dotty/tools/dotc/config/Config.scala b/src/dotty/tools/dotc/config/Config.scala
index 0fad2e105..a50945108 100644
--- a/src/dotty/tools/dotc/config/Config.scala
+++ b/src/dotty/tools/dotc/config/Config.scala
@@ -72,10 +72,9 @@ object Config {
/** If this flag is set, take the fast path when comparing same-named type-aliases and types */
final val fastPathForRefinedSubtype = true
- /** If this flag is set, $apply projections are checked that they apply to a
- * higher-kinded type.
+ /** If this flag is set, higher-kinded applications are checked for validity
*/
- final val checkProjections = false
+ final val checkHKApplications = false
/** The recursion depth for showing a summarized string */
final val summarizeDepth = 2
diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala
index ef241cb66..314233709 100644
--- a/src/dotty/tools/dotc/core/TypeApplications.scala
+++ b/src/dotty/tools/dotc/core/TypeApplications.scala
@@ -338,13 +338,12 @@ class TypeApplications(val self: Type) extends AnyVal {
*
* TODO: Handle parameterized lower bounds
*/
- def LambdaAbstract(tparams: List[Symbol])(implicit ctx: Context): Type = {
+ def LambdaAbstract(tparams: List[TypeParamInfo])(implicit ctx: Context): Type = {
def expand(tp: Type) =
TypeLambda(
- tpnme.syntheticLambdaParamNames(tparams.length), tparams.map(_.variance))(
+ tpnme.syntheticLambdaParamNames(tparams.length), tparams.map(_.paramVariance))(
tl => tparams.map(tparam => tl.lifted(tparams, tparam.paramBounds).bounds),
tl => tl.lifted(tparams, tp))
- assert(!isHK, self)
self match {
case self: TypeAlias =>
self.derivedTypeAlias(expand(self.alias))
@@ -489,6 +488,8 @@ class TypeApplications(val self: Type) extends AnyVal {
}
else dealiased.resType match {
case AppliedType(tycon, args1) if tycon.safeDealias ne tycon =>
+ // In this case we should always dealias since we cannot handle
+ // higher-kinded applications to wildcard arguments.
dealiased
.derivedTypeLambda(resType = tycon.safeDealias.appliedTo(args1))
.appliedTo(args)
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 1bfe9cbd1..fa402f9fc 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -517,7 +517,7 @@ object Types {
def goApply(tp: HKApply) = tp.tycon match {
case tl: TypeLambda =>
go(tl.resType).mapInfo(info =>
- tl.derivedTypeLambda(tl.paramNames, tl.paramBounds, info).appliedTo(tp.args))
+ tl.derivedLambdaAbstraction(tl.paramNames, tl.paramBounds, info).appliedTo(tp.args))
case _ =>
go(tp.superType)
}
@@ -879,12 +879,6 @@ object Types {
case _ => this
}
- /** If this is a TypeAlias type, its alias, otherwise this type itself */
- final def followTypeAlias(implicit ctx: Context): Type = this match {
- case TypeAlias(alias) => alias
- case _ => this
- }
-
/** If this is a (possibly aliased, annotated, and/or parameterized) reference to
* a class, the class type ref, otherwise NoType.
* @param refinementOK If `true` we also skip non-parameter refinements.
@@ -1923,13 +1917,9 @@ object Types {
}
object TypeRef {
- def checkProjection(prefix: Type, name: TypeName)(implicit ctx: Context) = ()
-
/** Create type ref with given prefix and name */
- def apply(prefix: Type, name: TypeName)(implicit ctx: Context): TypeRef = {
- if (Config.checkProjections) checkProjection(prefix, name)
+ def apply(prefix: Type, name: TypeName)(implicit ctx: Context): TypeRef =
ctx.uniqueNamedTypes.enterIfNew(prefix, name).asInstanceOf[TypeRef]
- }
/** Create type ref to given symbol */
def apply(prefix: Type, sym: TypeSymbol)(implicit ctx: Context): TypeRef =
@@ -1938,10 +1928,8 @@ object Types {
/** Create a non-member type ref (which cannot be reloaded using `member`),
* with given prefix, name, and symbol.
*/
- def withFixedSym(prefix: Type, name: TypeName, sym: TypeSymbol)(implicit ctx: Context): TypeRef = {
- if (Config.checkProjections) checkProjection(prefix, name)
+ def withFixedSym(prefix: Type, name: TypeName, sym: TypeSymbol)(implicit ctx: Context): TypeRef =
unique(new TypeRefWithFixedSym(prefix, name, sym))
- }
/** Create a type ref referring to given symbol with given name.
* This is very similar to TypeRef(Type, Symbol),
@@ -2057,9 +2045,7 @@ object Types {
private def badInst =
throw new AssertionError(s"bad instantiation: $this")
- def checkInst(implicit ctx: Context): this.type = {
- this
- }
+ def checkInst(implicit ctx: Context): this.type = this // debug hook
def derivedRefinedType(parent: Type, refinedName: Name, refinedInfo: Type)(implicit ctx: Context): Type =
if ((parent eq this.parent) && (refinedName eq this.refinedName) && (refinedInfo eq this.refinedInfo)) this
@@ -2139,7 +2125,7 @@ object Types {
override def computeHash = doHash(parent)
override def toString = s"RecType($parent | $hashCode)"
- private def checkInst(implicit ctx: Context): this.type = this
+ private def checkInst(implicit ctx: Context): this.type = this // debug hook
}
object RecType {
@@ -2550,8 +2536,8 @@ object Types {
case _ => false
}
- def derivedPolyType(paramNames: List[TypeName], paramBounds: List[TypeBounds], resType: Type)(implicit ctx: Context) =
- derivedGenericType(paramNames, paramBounds, resType)
+ def derivedPolyType(paramNames: List[TypeName], paramBounds: List[TypeBounds], resType: Type)(implicit ctx: Context): PolyType =
+ derivedGenericType(paramNames, paramBounds, resType).asInstanceOf[PolyType]
def duplicate(paramNames: List[TypeName] = this.paramNames, paramBounds: List[TypeBounds] = this.paramBounds, resType: Type)(implicit ctx: Context): PolyType =
PolyType(paramNames)(
@@ -2591,7 +2577,7 @@ object Types {
lazy val typeParams: List[LambdaParam] =
paramNames.indices.toList.map(new LambdaParam(this, _))
- def derivedTypeLambda(paramNames: List[TypeName] = paramNames, paramBounds: List[TypeBounds] = paramBounds, resType: Type)(implicit ctx: Context): Type =
+ def derivedLambdaAbstraction(paramNames: List[TypeName], paramBounds: List[TypeBounds], resType: Type)(implicit ctx: Context): Type =
resType match {
case resType @ TypeAlias(alias) =>
resType.derivedTypeAlias(duplicate(paramNames, paramBounds, alias))
@@ -2600,9 +2586,12 @@ object Types {
if (lo.isRef(defn.NothingClass)) lo else duplicate(paramNames, paramBounds, lo),
duplicate(paramNames, paramBounds, hi))
case _ =>
- derivedGenericType(paramNames, paramBounds, resType)
+ derivedTypeLambda(paramNames, paramBounds, resType)
}
+ def derivedTypeLambda(paramNames: List[TypeName] = paramNames, paramBounds: List[TypeBounds] = paramBounds, resType: Type)(implicit ctx: Context): TypeLambda =
+ derivedGenericType(paramNames, paramBounds, resType).asInstanceOf[TypeLambda]
+
def duplicate(paramNames: List[TypeName] = this.paramNames, paramBounds: List[TypeBounds] = this.paramBounds, resType: Type)(implicit ctx: Context): TypeLambda =
TypeLambda(paramNames, variances)(
x => paramBounds mapConserve (_.subst(this, x).bounds),
@@ -2664,6 +2653,7 @@ object Types {
cachedSuper
}
+ /* (Not needed yet) */
def lowerBound(implicit ctx: Context) = tycon.stripTypeVar match {
case tycon: TypeRef =>
tycon.info match {
@@ -2676,13 +2666,6 @@ object Types {
NoType
}
-/*
- def lowerBound(implicit ctx: Context): Type = tycon.stripTypeVar match {
- case tp: TypeRef =>
- val lb = tp.info.bounds.lo.typeParams.length == args.lengt
- case _ => defn.NothingType
- }
-*/
def typeParams(implicit ctx: Context): List[TypeParamInfo] = {
val tparams = tycon.typeParams
if (tparams.isEmpty) TypeLambda.any(args.length).typeParams else tparams
@@ -2705,7 +2688,7 @@ object Types {
case _ =>
assert(false, s"illegal type constructor in $this")
}
- check(tycon)
+ if (Config.checkHKApplications) check(tycon)
this
}
}
diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala
index 9e55216c1..b1cceea88 100644
--- a/src/dotty/tools/dotc/typer/Checking.scala
+++ b/src/dotty/tools/dotc/typer/Checking.scala
@@ -83,15 +83,16 @@ object Checking {
case AppliedTypeTree(tycon, args) =>
// If `args` is a list of named arguments, return corresponding type parameters,
// otherwise return type parameters unchanged
- def matchNamed(tparams: List[TypeSymbol], args: List[Tree]): List[Symbol] =
- if (hasNamedArg(args))
- for (NamedArg(name, _) <- args) yield tycon.tpe.member(name).symbol
- else
- tparams
- val tparams = matchNamed(tycon.tpe.typeSymbol.typeParams, args)
- val bounds = tparams.map(tparam =>
- tparam.info.asSeenFrom(tycon.tpe.normalizedPrefix, tparam.owner.owner).bounds)
- checkBounds(args, bounds, _.substDealias(tparams, _))
+ val tparams = tycon.tpe.typeParams
+ def argNamed(tparam: TypeParamInfo) = args.find {
+ case NamedArg(name, _) => name == tparam.paramName
+ case _ => false
+ }.getOrElse(TypeTree(tparam.paramRef))
+ val orderedArgs = if (hasNamedArg(args)) tparams.map(argNamed) else args
+ val bounds = tparams.map(_.paramBoundsAsSeenFrom(tycon.tpe))
+ def instantiate(bound: Type, args: List[Type]) =
+ bound.LambdaAbstract(tparams).appliedTo(args)
+ checkBounds(orderedArgs, bounds, instantiate)
def checkValidIfHKApply(implicit ctx: Context): Unit =
checkWildcardHKApply(tycon.tpe.appliedTo(args.map(_.tpe)), tree.pos)
diff --git a/tests/neg/t7278.scala b/tests/neg/t7278.scala
index 7aafbb76f..643a3c858 100644
--- a/tests/neg/t7278.scala
+++ b/tests/neg/t7278.scala
@@ -13,8 +13,8 @@ object Test {
def fail1(): Unit = {
val b = new B
- var x1: EE[A] = null
- var x2: EE[B] = new b.E // old-error: found: B#E, required: A#E
+ var x1: EE[A] = null // error: Type argument A does not conform to upper bound EC
+ var x2: EE[B] = new b.E // error: Type argument B does not conform to upper bound EC
// x1 = x2 // gives a prior type error: B#E, required: A#E, masked to get at the real thing.
}
@@ -27,8 +27,8 @@ object Test {
}
*/
def fail3(): Unit = {
- var x1: EE[C] = 5
- var x2: EE[C & D] = ""
+ var x1: EE[C] = 5 // error: Type argument C does not conform to upper bound EC
+ var x2: EE[C & D] = "" // error: Type argument C & D does not conform to upper bound EC
x1 = x2
}
diff --git a/tests/pos-scala2/t2994.scala b/tests/pos-scala2/t2994.scala
index c7421c42a..f3009b12f 100644
--- a/tests/pos-scala2/t2994.scala
+++ b/tests/pos-scala2/t2994.scala
@@ -20,7 +20,7 @@ object Naturals {
// crashes scala-2.8.0 beta1
trait MUL[n <: NAT, m <: NAT] extends NAT {
- trait curry[n[_, _], s[_]] { type f[z <: NAT] = n[s, z] }
+ trait curry[n[_[_], _], s[_]] { type f[z <: NAT] = n[s, z] }
type a[s[_ <: NAT] <: NAT, z <: NAT] = n#a[curry[m#a, s]#f, z]
}
diff --git a/tests/pos/hklower.scala b/tests/pos/hklower.scala
index 033ee3a34..90aa343ba 100644
--- a/tests/pos/hklower.scala
+++ b/tests/pos/hklower.scala
@@ -1,4 +1,4 @@
-class Test { // error: conflicting bounds
+class Test {
type T[X]
type U[X] = T[X]
@@ -6,6 +6,36 @@ class Test { // error: conflicting bounds
type V[X] >: T[X]
type W[X] >: T[X] <: T[X]
- def f[C[X] >: T[X]]() = ???
+ def f[C[X] >: T[X]](x: C[Int]) = ???
+
+ val v: V[Int] = ???
+ val t: T[Int] = ???
+
+ f[V](v)
+
+ f[V](t)
+
+
+}
+class Test2 {
+
+ class T[X]
+ type U[X] = T[X]
+
+ type V[X] >: T[X]
+ type W[X] >: T[X] <: T[X]
+
+ def f[C[X] >: T[X]](x: C[Int]) = ???
+
+ val v: V[Int] = ???
+ val t: T[Int] = ???
+
+ f[V](v)
+
+ f[V](t)
+
+ var x: V[Int] = _
+ x = t
+
}