aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/core/TypeOps.scala32
-rw-r--r--src/dotty/tools/dotc/core/Types.scala72
-rw-r--r--src/dotty/tools/dotc/core/pickling/UnPickler.scala28
3 files changed, 98 insertions, 34 deletions
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)
}