From dc137d37524e560e89a10e2ebd2e78c818e2205e Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 8 Feb 2013 22:45:30 +0100 Subject: Added methods to convert between (virtual) type application and refinements. Refactored parent normalization from Unpickler to TypeOps. --- src/dotty/tools/dotc/core/TypeOps.scala | 32 +++++++++- src/dotty/tools/dotc/core/Types.scala | 72 ++++++++++++++++++---- src/dotty/tools/dotc/core/pickling/UnPickler.scala | 28 ++------- 3 files changed, 98 insertions(+), 34 deletions(-) (limited to 'src/dotty/tools/dotc') diff --git a/src/dotty/tools/dotc/core/TypeOps.scala b/src/dotty/tools/dotc/core/TypeOps.scala index e75dc74f1..52f0ef23e 100644 --- a/src/dotty/tools/dotc/core/TypeOps.scala +++ b/src/dotty/tools/dotc/core/TypeOps.scala @@ -1,6 +1,6 @@ package dotty.tools.dotc.core -import Contexts._, Types._, Symbols._, Names._, Flags._ +import Contexts._, Types._, Symbols._, Names._, Flags._, Scopes._ trait TypeOps { this: Context => @@ -183,5 +183,35 @@ trait TypeOps { this: Context => case _ => NoType } + + /** Normalize a list of parent types of class `cls` that may contain refinements + * to a list of typerefs, by converting all refinements to member + * definitions in scope `decls`. + */ + def normalizeToRefs(parents: List[Type], cls: ClassSymbol, decls: Scope): List[TypeRef] = { + var refinements = Map[TypeName, Type]() + var formals = Map[TypeName, Symbol]() + def normalizeToRef(tp: Type): TypeRef = tp match { + case tp @ RefinedType(tp1, name: TypeName) => + refinements = refinements.updated(name, + refinements get name match { + case Some(info) => info & tp.info + case none => tp.info + }) + formals = formals.updated(name, tp1.member(name).symbol) + normalizeToRef(tp1) + case tp: TypeRef => + tp + case _ => + throw new TypeError(s"unexpected parent type: $tp") + } + val parentRefs = parents map normalizeToRef + for ((name, tpe) <- refinements) decls.enter { + val formal = formals(name) + val bounds = tpe.toRHS(formal) + ctx.newSymbol(cls, name, formal.flags & RetainedTypeArgFlags, bounds) + } + parentRefs + } } diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index c04ccd60c..aca1aef1d 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -40,6 +40,7 @@ object Types { * | | +--- ConstantType * | | +--- MethodParam * | | +--- RefinedThis + * | | +--- NoPrefix * | +- TypeBounds * | +- ExprType * | +- AnnotatedType @@ -440,24 +441,72 @@ object Types { case _ => Nil } - final def applyToArgs(args: List[Type])(implicit ctx: Context) = { - def loop(tp: Type, tparams: List[TypeSymbol], args: List[Type]): Type = args match { + /** Encode the type resulting from applying this type to given arguments */ + final def appliedTo(args: List[Type])(implicit ctx: Context): Type = { + def recur(tp: Type, tparams: List[TypeSymbol], args: List[Type]): Type = args match { case arg :: args1 => val tparam = tparams.head - val tp1 = RefinedType(tp, tparam.name, tp.toAlias(tparam)) - loop(tp1, tparams.tail, args1) + val tp1 = RefinedType(tp, tparam.name, arg.toRHS(tparam)) + recur(tp1, tparams.tail, args1) case nil => tp } - if (args.isEmpty) this else loop(this, typeParams, args) + if (args.isEmpty) this else recur(this, typeParams, args) } - final def toAlias(tparam: Symbol)(implicit ctx: Context): TypeBounds = { - val flags = tparam.flags - if (flags is Covariant) TypeBounds(defn.NothingType, this) - else if (flags is Contravariant) TypeBounds(this, defn.AnyType) + final def appliedTo(args: Type*)(implicit ctx: Context): Type = appliedTo(args.toList) + + /** If this type equals `tycon applyToArgs args`, for some + * non-refinement type `tycon` and (possibly partial) type arguments + * `args`, return a pair consisting of `tycon` and `args`. + * Otherwise return the type itself and `Nil`. + */ + final def splitArgs(implicit ctx: Context): (Type, List[Type]) = { + def recur(tp: Type, nparams: Int): (Type, List[Type]) = tp match { + case tp @ RefinedType(parent, name) => + def fail = (NoType, Nil) + if (nparams >= 0) { + val result @ (tycon, args) = recur(parent, nparams - 1) + if (tycon != NoType) { + val tparam = tycon.typeParams.apply(nparams) + if (tparam.name == name) { + (tycon, args :+ tp.info.argType(tparam)) + } else fail + } else fail + } else fail + case tp => + (tp, Nil) + } + val result @ (tycon, args) = recur(this, typeParams.length) + if (tycon != NoType) result else (this, Nil) + } + + final def splitArgsCompletely(implicit ctx: Context): (Type, List[Type]) = { + val result @ (tycon, args) = splitArgs + if (args.length == tycon.typeParams.length) result else (NoType, Nil) + } + + /** Turn this type into a TypeBounds RHS */ + final def toRHS(tparam: Symbol)(implicit ctx: Context): TypeBounds = { + val v = tparam.variance + if (v > 0) TypeBounds(defn.NothingType, this) + else if (v < 0) TypeBounds(this, defn.AnyType) else TypeBounds(this, this) } + /** If this is the image of a type argument, recover the type argument, + * otherwise NoType. + */ + final def argType(tparam: Symbol)(implicit ctx: Context): Type = this match { + case TypeBounds(lo, hi) => + val v = tparam.variance + if (v > 0 && lo.typeSymbol == defn.NothingClass) hi + else if (v < 0 && hi.typeSymbol == defn.AnyClass) lo + else if (v == 0 && (lo eq hi)) lo + else NoType + case _ => + NoType + } + final def isWrong: Boolean = !exists // !!! needed? final def exists: Boolean = true @@ -661,7 +710,7 @@ object Types { } } - final class TermRefBySym(prefix: Type, val fixedSym: TermSymbol)(implicit initctx: Context) + final class TermRefBySym(prefix: Type, val fixedSym: TermSymbol)(initctx: Context) extends TermRef(prefix, fixedSym.name(initctx).asTermName) with HasFixedSym { } @@ -671,7 +720,7 @@ object Types { super.loadDenot.atSignature(signature) } - final class TypeRefBySym(prefix: Type, val fixedSym: TypeSymbol)(implicit initctx: Context) + final class TypeRefBySym(prefix: Type, val fixedSym: TypeSymbol)(initctx: Context) extends TypeRef(prefix, fixedSym.name(initctx).asTypeName) with HasFixedSym { } @@ -1017,6 +1066,7 @@ object Types { final class CachedTypeBounds(lo: Type, hi: Type) extends TypeBounds(lo, hi) object TypeBounds { + def empty(implicit ctx: Context) = apply(defn.NothingType, defn.AnyType) def apply(lo: Type, hi: Type)(implicit ctx: Context) = unique(new CachedTypeBounds(lo, hi)) } diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala index b3c0a88f9..ed97217f3 100644 --- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala +++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala @@ -321,7 +321,7 @@ abstract class UnPickler { var flags1 = flags if (flags is TypeParam) { name1 = name1.expandedName(owner) - flags1 |= ProtectedLocal + flags1 |= TypeParamFlags } ctx.newLazySymbol(owner, name1, flags1, completeSym(tag)) case CLASSsym => @@ -428,7 +428,7 @@ abstract class UnPickler { val tycon = if (isLocal(sym)) TypeRef(pre, sym.asType) else TypeRef(pre, sym.name.asTypeName) - tycon.applyToArgs(until(end, readTypeRef)) + tycon.appliedTo(until(end, readTypeRef)) case TYPEBOUNDStpe => TypeBounds(readTypeRef(), readTypeRef()) case REFINEDtpe => @@ -930,7 +930,7 @@ abstract class UnPickler { protected def errorMissingRequirement(name: Name, owner: Symbol): Symbol = MissingRequirementError.signal( - s"bad reference while unpickling $filename: ${ctx.showNameDetailed(name)} not found in $owner" + s"bad reference while unpickling $filename: ${ctx.showDetailed(name)} not found in $owner" ) // def inferMethodAlternative(fun: Tree, argtpes: List[Type], restpe: Type) {} // can't do it; need a compiler for that. @@ -980,26 +980,10 @@ abstract class UnPickler { case cinfo => (Nil, cinfo) } val selfType = if (j > 0) at(j, () => readType()) else denot.typeConstructor - var refinements = Map[TypeName, Type]().withDefaultValue(NoType) - def normalizeToRef(tp: Type): TypeRef = tp match { - case tp @ RefinedType(tp1, name: TypeName) => - refinements = (refinements + (name -> (refinements(name) & tp.info))) - .withDefaultValue(NoType) - normalizeToRef(tp1) - case tp: TypeRef => - tp - case _ => - throw new TypeError(s"unexpected parent type: $tp") - } - denot.parents = parents map normalizeToRef + tparams foreach decls.enter + denot.parents = ctx.normalizeToRefs(parents, cls, decls) denot.selfType = selfType - denot.decls = newScope - tparams foreach denot.decls.enter - for ((name, tpe) <- refinements) denot.decls.enter { - val formal = cls.info.member(name).symbol - val bounds = tpe.toAlias(formal) - ctx.newSymbol(cls, name, formal.flags & RetainedTypeArgFlags, bounds) - } + denot.decls = decls } catch { case e: MissingRequirementError => throw toTypeError(e) } -- cgit v1.2.3