aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-01-19 22:26:23 +0100
committerMartin Odersky <odersky@gmail.com>2014-01-19 22:26:23 +0100
commit38b36268d5d29d25cb430c1e275c06ebb1c8f7dd (patch)
tree166d8147aa0a82a698b72716904befc154459462 /src/dotty/tools
parent6eece756db81a62d6114ff8ce8674cc0c69febaa (diff)
downloaddotty-38b36268d5d29d25cb430c1e275c06ebb1c8f7dd.tar.gz
dotty-38b36268d5d29d25cb430c1e275c06ebb1c8f7dd.tar.bz2
dotty-38b36268d5d29d25cb430c1e275c06ebb1c8f7dd.zip
Normalize parent types so that first one always refers to a class, not a trait.
Also: forward type parameter references of newly added to class scope. This is necessary, or the pattern match in test.scala would fail. Need to find out why.
Diffstat (limited to 'src/dotty/tools')
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala3
-rw-r--r--src/dotty/tools/dotc/core/TypeOps.scala54
-rw-r--r--src/dotty/tools/dotc/typer/Inferencing.scala42
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala9
4 files changed, 85 insertions, 23 deletions
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index 1cf875280..7f5145ba3 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -284,7 +284,8 @@ class Definitions(implicit ctx: Context) {
object FunctionType {
def apply(args: List[Type], resultType: Type) =
FunctionClass(args.length).typeRef.appliedTo(args :+ resultType)
- def unapply(ft: Type) = {
+ def unapply(ft: Type): Option[(List[Type], Type)] = { // Dotty deviation: Type annotation needed because inferred type
+ // is Some[(List[Type], Type)] | None, which is not a legal unapply type.
val tsym = ft.typeSymbol
lazy val targs = ft.typeArgs
if ((FunctionClasses contains tsym) &&
diff --git a/src/dotty/tools/dotc/core/TypeOps.scala b/src/dotty/tools/dotc/core/TypeOps.scala
index c42f0bb36..0411cc613 100644
--- a/src/dotty/tools/dotc/core/TypeOps.scala
+++ b/src/dotty/tools/dotc/core/TypeOps.scala
@@ -85,18 +85,43 @@ trait TypeOps { this: Context =>
}
}
+ private def enterArgBinding(formal: Symbol, info: Type, cls: ClassSymbol, decls: Scope) = {
+ val typeArgFlag = if (formal is Local) TypeArgument else EmptyFlags
+ val sym = ctx.newSymbol(cls, formal.name, formal.flags & RetainedTypeArgFlags | typeArgFlag, info)
+ cls.enter(sym, decls)
+ }
+
+ /** If we have member definitions
+ *
+ * type argSym v= from
+ * type from v= to
+ *
+ * where the variances of both alias are the same, then enter a new definition
+ *
+ * type argSym v= to
+ *
+ * unless a definition for `argSym` already exists in the current scope.
+ */
+ def forwardRef(argSym: Symbol, from: Symbol, to: TypeBounds, cls: ClassSymbol, decls: Scope) =
+ argSym.info match {
+ case info @ TypeBounds(lo2 @ TypeRef(ThisType(_), name), hi2) =>
+ if (name == from.name &&
+ (lo2 eq hi2) &&
+ info.variance == to.variance &&
+ !decls.lookup(argSym.name).exists) {
+ // println(s"short-circuit ${argSym.name} was: ${argSym.info}, now: $to")
+ enterArgBinding(argSym, to, cls, decls)
+ }
+ case _ =>
+ }
+
+
/** Normalize a list of parent types of class `cls` that may contain refinements
* to a list of typerefs referring to classes, by converting all refinements to member
* definitions in scope `decls`. Can add members to `decls` as a side-effect.
*/
def normalizeToClassRefs(parents: List[Type], cls: ClassSymbol, decls: Scope): List[TypeRef] = {
- def enterArgBinding(formal: Symbol, info: Type) = {
- val typeArgFlag = if (formal is Local) TypeArgument else EmptyFlags
- val sym = ctx.newSymbol(cls, formal.name, formal.flags & RetainedTypeArgFlags | typeArgFlag, info)
- cls.enter(sym, decls)
- }
-
/** If we just entered the type argument binding
*
* type From = To
@@ -117,19 +142,8 @@ trait TypeOps { this: Context =>
case to @ TypeBounds(lo1, hi1) if lo1 eq hi1 =>
for (pref <- prefs)
for (argSym <- pref.decls)
- if (argSym is TypeArgument) {
- argSym.info match {
- case info @ TypeBounds(lo2 @ TypeRef(ThisType(_), name), hi2) =>
- if (name == from.name &&
- (lo2 eq hi2) &&
- info.variance == to.variance &&
- !decls.lookup(argSym.name).exists) {
-// println(s"short-circuit ${argSym.name} was: ${argSym.info}, now: $to")
- enterArgBinding(argSym, to)
- }
- case _ =>
- }
- }
+ if (argSym is TypeArgument)
+ forwardRef(argSym, from, to, cls, decls)
case _ =>
}
@@ -155,7 +169,7 @@ trait TypeOps { this: Context =>
refinements foreachBinding { (name, refinedInfo) =>
assert(decls.lookup(name) == NoSymbol, // DEBUG
s"redefinition of ${decls.lookup(name).debugString} in ${cls.showLocated}")
- enterArgBinding(formals(name), refinedInfo)
+ enterArgBinding(formals(name), refinedInfo, cls, decls)
}
// These two loops cannot be fused because second loop assumes that
// all arguments have been entered in `decls`.
diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala
index 9da57ea53..fba2201bf 100644
--- a/src/dotty/tools/dotc/typer/Inferencing.scala
+++ b/src/dotty/tools/dotc/typer/Inferencing.scala
@@ -7,6 +7,7 @@ import ast._
import Contexts._, Types._, Flags._, Denotations._, Names._, StdNames._, NameOps._, Symbols._
import Trees._
import Constants._
+import Scopes._
import annotation.unchecked
import util.Positions._
import util.{Stats, SimpleMap}
@@ -397,6 +398,47 @@ object Inferencing {
defn.ObjectClass.typeRef
}
+ /** Ensure that first typeref in a list of parents points to a non-trait class.
+ * If that's not already the case, add one.
+ */
+ def ensureFirstIsClass(prefs: List[TypeRef])(implicit ctx: Context): List[TypeRef] = {
+ def isRealClass(sym: Symbol) = sym.isClass && !(sym is Trait)
+ def realClassParent(tref: TypeRef): TypeRef =
+ if (isRealClass(tref.symbol)) tref
+ else tref.info.parents match {
+ case pref :: _ => if (isRealClass(pref.symbol)) pref else realClassParent(pref)
+ case nil => defn.ObjectClass.typeRef
+ }
+ def improve(clsRef: TypeRef, parent: TypeRef): TypeRef = {
+ val pclsRef = realClassParent(parent)
+ if (pclsRef.symbol derivesFrom clsRef.symbol) pclsRef else clsRef
+ }
+ prefs match {
+ case pref :: _ if isRealClass(pref.symbol) => prefs
+ case _ => (defn.ObjectClass.typeRef /: prefs)(improve) :: prefs
+ }
+ }
+
+ /** Forward bindings of all type parameters of `pcls`. That is, if the type parameter
+ * if instantiated in a parent class, include its type binding in the current class.
+ */
+ def forwardTypeParams(pcls: ClassSymbol, cls: ClassSymbol, decls: Scope)(implicit ctx: Context): Unit = {
+ for (tparam <- pcls.typeParams) {
+ val argSym: Symbol = cls.thisType.member(tparam.name).symbol
+ argSym.info match {
+ case TypeAlias(TypeRef(ThisType(_), name)) =>
+ val from = cls.thisType.member(name).symbol
+ from.info match {
+ case bounds: TypeBounds =>
+ typr.println(s"forward ref $argSym $from $bounds")
+ ctx.forwardRef(argSym, from, bounds, cls, decls)
+ case _ =>
+ }
+ case _ =>
+ }
+ }
+ }
+
/** Check that class does not define */
def checkNoDoubleDefs(cls: Symbol)(implicit ctx: Context): Unit = {
val seen = new mutable.HashMap[Name, List[Symbol]] {
diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala
index ece9f51a7..92441d899 100644
--- a/src/dotty/tools/dotc/typer/Namer.scala
+++ b/src/dotty/tools/dotc/typer/Namer.scala
@@ -7,7 +7,7 @@ import ast._
import Trees._, Constants._, StdNames._, Scopes._, Denotations._
import Contexts._, Symbols._, Types._, SymDenotations._, Names._, NameOps._, Flags._, Decorators._
import ast.desugar, ast.desugar._
-import Inferencing.{fullyDefinedType, AnySelectionProto, checkClassTypeWithStablePrefix}
+import Inferencing.{fullyDefinedType, AnySelectionProto, checkClassTypeWithStablePrefix, ensureFirstIsClass, forwardTypeParams}
import util.Positions._
import util.SourcePosition
import collection.mutable
@@ -422,10 +422,15 @@ class Namer { typer: Typer =>
val parentClsRefs =
for ((parentRef, constr) <- parentRefs zip parents)
yield checkClassTypeWithStablePrefix(parentRef, constr.pos)
+ val normalizedParentClsRefs = ensureFirstIsClass(parentClsRefs)
index(constr)
index(rest)(inClassContext(selfInfo))
- denot.info = ClassInfo(cls.owner.thisType, cls, parentClsRefs, decls, selfInfo)
+ denot.info = ClassInfo(cls.owner.thisType, cls, normalizedParentClsRefs, decls, selfInfo)
+ if (parentClsRefs ne normalizedParentClsRefs) {
+ forwardTypeParams(normalizedParentClsRefs.head.symbol.asClass, cls, decls)
+ typr.println(i"expanded parents of $denot: $normalizedParentClsRefs%, %")
+ }
}
}