aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2016-06-29 19:43:44 +0200
committerMartin Odersky <odersky@gmail.com>2016-07-11 13:35:01 +0200
commit8e84fb013abeb613af4a3414b836f02140e2e866 (patch)
tree26b66d75631822c1190a5f6fb9adf74182427579 /src/dotty/tools/dotc
parent6a7e466fa2ff5d6d01a25bed0c685188c9a84a63 (diff)
downloaddotty-8e84fb013abeb613af4a3414b836f02140e2e866.tar.gz
dotty-8e84fb013abeb613af4a3414b836f02140e2e866.tar.bz2
dotty-8e84fb013abeb613af4a3414b836f02140e2e866.zip
Eta-expand unapplied types that have type parameters
We would like to change from a scheme where eta-expansion was prototype driven to one where unapplied parameterized types are always eta expanded. The reason is that we might miss some eta expansions due to cyclic references. run/colltest4 is an exmaple. Here, we missed an eta expansion in the type of Iterator. The class definition is: trait Iterable[+A] extends IterableOnce[A] with FromIterable[Iterable] { We'd expect that the second parent would expand to FromIterable[[X0] -> Iterable[X0]] But we miss the expansion because at the time we complete Iterable we have not completed FromIterable yet. In fact this happens in both the old and the new hk scheme. But in the old scheme we did not notice the error whereas in the new scheme we get an error in PostTyper that the type Iterable does not conform to its bound `[X0] -> Iterable[X0]`. With this commit, we change the scheme, so that eta-expansion depends on the type parameters of a type itself, instead of the expected type. We should investigate whether we can do a similar change for Scala2 classloading. Check kinds of type parameters Also, do not allow a hk type if the bound is a * type.
Diffstat (limited to 'src/dotty/tools/dotc')
-rw-r--r--src/dotty/tools/dotc/core/TypeApplications.scala11
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala3
-rw-r--r--src/dotty/tools/dotc/typer/Checking.scala7
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala8
-rw-r--r--src/dotty/tools/dotc/typer/ProtoTypes.scala3
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala17
6 files changed, 36 insertions, 13 deletions
diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala
index be0eb9230..1700a9c9c 100644
--- a/src/dotty/tools/dotc/core/TypeApplications.scala
+++ b/src/dotty/tools/dotc/core/TypeApplications.scala
@@ -378,15 +378,18 @@ class TypeApplications(val self: Type) extends AnyVal {
}
}
+ /** If `self` is a higher-kinded type, its type parameters $hk_i, otherwise Nil */
final def hkTypeParams(implicit ctx: Context): List[MemberBinding] =
if (Config.newHK)
if (isHK) typeParams else Nil
else LambdaTraitOBS.typeParams
- final def typeParamSymbols(implicit ctx: Context): List[TypeSymbol] = {
- val tparams = typeParams
- assert(tparams.isEmpty || tparams.head.isInstanceOf[Symbol], self)
- tparams.asInstanceOf[List[TypeSymbol]]
+ /** If `self` is a generic class, its type parameter symbols, otherwise Nil */
+ final def typeParamSymbols(implicit ctx: Context): List[TypeSymbol] = typeParams match {
+ case (_: Symbol) :: _ =>
+ assert(typeParams.forall(_.isInstanceOf[Symbol]))
+ typeParams.asInstanceOf[List[TypeSymbol]]
+ case _ => Nil
}
/** The named type parameters declared or inherited by this type.
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index 14071e27c..cdbf692cd 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -17,6 +17,7 @@ import Types._
import Decorators._
import ErrorReporting._
import Trees._
+import config.Config
import Names._
import StdNames._
import ProtoTypes._
@@ -644,7 +645,7 @@ trait Applications extends Compatibility { self: Typer =>
}
def adaptTypeArg(tree: tpd.Tree, bound: Type)(implicit ctx: Context): tpd.Tree =
- tree.withType(tree.tpe.etaExpandIfHK(bound))
+ if (Config.newHK) tree else tree.withType(tree.tpe.etaExpandIfHK(bound))
/** Rewrite `new Array[T](....)` if T is an unbounded generic to calls to newGenericArray.
* It is performed during typer as creation of generic arrays needs a classTag.
diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala
index 6944197a1..cfad4e77e 100644
--- a/src/dotty/tools/dotc/typer/Checking.scala
+++ b/src/dotty/tools/dotc/typer/Checking.scala
@@ -36,11 +36,16 @@ object Checking {
/** A general checkBounds method that can be used for TypeApply nodes as
* well as for AppliedTypeTree nodes.
*/
- def checkBounds(args: List[tpd.Tree], boundss: List[TypeBounds], instantiate: (Type, List[Type]) => Type)(implicit ctx: Context) =
+ def checkBounds(args: List[tpd.Tree], boundss: List[TypeBounds], instantiate: (Type, List[Type]) => Type)(implicit ctx: Context) = {
+ (args, boundss).zipped.foreach { (arg, bound) =>
+ if (!bound.isHK && arg.tpe.isHK)
+ ctx.error(d"missing type parameter(s) for $arg", arg.pos)
+ }
for ((arg, which, bound) <- ctx.boundsViolations(args, boundss, instantiate))
ctx.error(
d"Type argument ${arg.tpe} does not conform to $which bound $bound ${err.whyNoMatchStr(arg.tpe, bound)}",
arg.pos)
+ }
/** Check that type arguments `args` conform to corresponding bounds in `poly`
* Note: This does not check the bounds of AppliedTypeTrees. These
diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala
index a8f3b8918..7982f288d 100644
--- a/src/dotty/tools/dotc/typer/Namer.scala
+++ b/src/dotty/tools/dotc/typer/Namer.scala
@@ -14,6 +14,7 @@ import collection.mutable
import annotation.tailrec
import ErrorReporting._
import tpd.ListOfTreeDecorator
+import config.Config
import config.Printers._
import Annotations._
import Inferencing._
@@ -591,7 +592,7 @@ class Namer { typer: Typer =>
*/
def parentType(parent: untpd.Tree)(implicit ctx: Context): Type =
if (parent.isType) {
- typedAheadType(parent).tpe
+ typedAheadType(parent, AnyTypeConstructorProto).tpe
} else {
val (core, targs) = stripApply(parent) match {
case TypeApply(core, targs) => (core, targs)
@@ -973,7 +974,8 @@ class Namer { typer: Typer =>
ensureUpToDate(sym.typeRef, dummyInfo)
ensureUpToDate(sym.typeRef.appliedTo(tparamSyms.map(_.typeRef)), TypeBounds.empty)
- etaExpandArgs.apply(sym.info)
+ if (Config.newHK) sym.info
+ else etaExpandArgsOBS.apply(sym.info)
}
/** Eta expand all class types C appearing as arguments to a higher-kinded
@@ -982,7 +984,7 @@ class Namer { typer: Typer =>
* of arguments in F-bounds, because the recursive type was initialized with
* TypeBounds.empty.
*/
- def etaExpandArgs(implicit ctx: Context) = new TypeMap {
+ def etaExpandArgsOBS(implicit ctx: Context) = new TypeMap {
def apply(tp: Type): Type = tp match {
case tp: RefinedType =>
val args = tp.argInfos.mapconserve(this)
diff --git a/src/dotty/tools/dotc/typer/ProtoTypes.scala b/src/dotty/tools/dotc/typer/ProtoTypes.scala
index 740258821..68fd99b3f 100644
--- a/src/dotty/tools/dotc/typer/ProtoTypes.scala
+++ b/src/dotty/tools/dotc/typer/ProtoTypes.scala
@@ -311,6 +311,9 @@ object ProtoTypes {
*/
@sharable object AnyFunctionProto extends UncachedGroundType with MatchAlways
+ /** A prototype for type constructors that are followed by a type application */
+ @sharable object AnyTypeConstructorProto extends UncachedGroundType with MatchAlways
+
/** Add all parameters in given polytype `pt` to the constraint's domain.
* If the constraint contains already some of these parameters in its domain,
* make a copy of the polytype and add the copy's type parameters instead.
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 225516503..33a94f5c7 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -928,7 +928,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
}
def typedAppliedTypeTree(tree: untpd.AppliedTypeTree)(implicit ctx: Context): Tree = track("typedAppliedTypeTree") {
- val tpt1 = typed(tree.tpt)(ctx retractMode Mode.Pattern)
+ val tpt1 = typed(tree.tpt, AnyTypeConstructorProto)(ctx.retractMode(Mode.Pattern))
val tparams = tpt1.tpe.typeParams
if (tparams.isEmpty) {
ctx.error(d"${tpt1.tpe} does not take type parameters", tree.pos)
@@ -1672,6 +1672,17 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
}
}
+ def adaptType(tp: Type): Tree = {
+ val tree1 =
+ if (pt != AnyTypeConstructorProto && tp.typeParamSymbols.nonEmpty) {
+ println(i"lam abs $tp with tparams ${tp.typeParamSymbols}%, %")
+ tree.withType(tree.tpe.EtaExpand(tp.typeParamSymbols))
+ }
+ else tree
+ if ((ctx.mode is Mode.Pattern) || tree1.tpe <:< pt) tree1
+ else err.typeMismatch(tree1, pt)
+ }
+
tree match {
case _: MemberDef | _: PackageDef | _: Import | _: WithoutTypeOrPos[_] => tree
case _ => tree.tpe.widen match {
@@ -1705,9 +1716,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
(_, _) => tree // error will be reported in typedTypeApply
}
case _ =>
- if (ctx.mode is Mode.Type)
- if ((ctx.mode is Mode.Pattern) || tree.tpe <:< pt) tree
- else err.typeMismatch(tree, pt)
+ if (ctx.mode is Mode.Type) adaptType(tree.tpe)
else adaptNoArgs(wtp)
}
}