Skip to content

Commit dc137d3

Browse files
committed
Added methods to convert between (virtual) type application and refinements.
Refactored parent normalization from Unpickler to TypeOps.
1 parent 00cd39a commit dc137d3

File tree

3 files changed

+98
-34
lines changed

3 files changed

+98
-34
lines changed

src/dotty/tools/dotc/core/TypeOps.scala

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package dotty.tools.dotc.core
22

3-
import Contexts._, Types._, Symbols._, Names._, Flags._
3+
import Contexts._, Types._, Symbols._, Names._, Flags._, Scopes._
44

55
trait TypeOps { this: Context =>
66

@@ -183,5 +183,35 @@ trait TypeOps { this: Context =>
183183
case _ =>
184184
NoType
185185
}
186+
187+
/** Normalize a list of parent types of class `cls` that may contain refinements
188+
* to a list of typerefs, by converting all refinements to member
189+
* definitions in scope `decls`.
190+
*/
191+
def normalizeToRefs(parents: List[Type], cls: ClassSymbol, decls: Scope): List[TypeRef] = {
192+
var refinements = Map[TypeName, Type]()
193+
var formals = Map[TypeName, Symbol]()
194+
def normalizeToRef(tp: Type): TypeRef = tp match {
195+
case tp @ RefinedType(tp1, name: TypeName) =>
196+
refinements = refinements.updated(name,
197+
refinements get name match {
198+
case Some(info) => info & tp.info
199+
case none => tp.info
200+
})
201+
formals = formals.updated(name, tp1.member(name).symbol)
202+
normalizeToRef(tp1)
203+
case tp: TypeRef =>
204+
tp
205+
case _ =>
206+
throw new TypeError(s"unexpected parent type: $tp")
207+
}
208+
val parentRefs = parents map normalizeToRef
209+
for ((name, tpe) <- refinements) decls.enter {
210+
val formal = formals(name)
211+
val bounds = tpe.toRHS(formal)
212+
ctx.newSymbol(cls, name, formal.flags & RetainedTypeArgFlags, bounds)
213+
}
214+
parentRefs
215+
}
186216
}
187217

src/dotty/tools/dotc/core/Types.scala

Lines changed: 61 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ object Types {
4040
* | | +--- ConstantType
4141
* | | +--- MethodParam
4242
* | | +--- RefinedThis
43+
* | | +--- NoPrefix
4344
* | +- TypeBounds
4445
* | +- ExprType
4546
* | +- AnnotatedType
@@ -440,24 +441,72 @@ object Types {
440441
case _ => Nil
441442
}
442443

443-
final def applyToArgs(args: List[Type])(implicit ctx: Context) = {
444-
def loop(tp: Type, tparams: List[TypeSymbol], args: List[Type]): Type = args match {
444+
/** Encode the type resulting from applying this type to given arguments */
445+
final def appliedTo(args: List[Type])(implicit ctx: Context): Type = {
446+
def recur(tp: Type, tparams: List[TypeSymbol], args: List[Type]): Type = args match {
445447
case arg :: args1 =>
446448
val tparam = tparams.head
447-
val tp1 = RefinedType(tp, tparam.name, tp.toAlias(tparam))
448-
loop(tp1, tparams.tail, args1)
449+
val tp1 = RefinedType(tp, tparam.name, arg.toRHS(tparam))
450+
recur(tp1, tparams.tail, args1)
449451
case nil => tp
450452
}
451-
if (args.isEmpty) this else loop(this, typeParams, args)
453+
if (args.isEmpty) this else recur(this, typeParams, args)
452454
}
453455

454-
final def toAlias(tparam: Symbol)(implicit ctx: Context): TypeBounds = {
455-
val flags = tparam.flags
456-
if (flags is Covariant) TypeBounds(defn.NothingType, this)
457-
else if (flags is Contravariant) TypeBounds(this, defn.AnyType)
456+
final def appliedTo(args: Type*)(implicit ctx: Context): Type = appliedTo(args.toList)
457+
458+
/** If this type equals `tycon applyToArgs args`, for some
459+
* non-refinement type `tycon` and (possibly partial) type arguments
460+
* `args`, return a pair consisting of `tycon` and `args`.
461+
* Otherwise return the type itself and `Nil`.
462+
*/
463+
final def splitArgs(implicit ctx: Context): (Type, List[Type]) = {
464+
def recur(tp: Type, nparams: Int): (Type, List[Type]) = tp match {
465+
case tp @ RefinedType(parent, name) =>
466+
def fail = (NoType, Nil)
467+
if (nparams >= 0) {
468+
val result @ (tycon, args) = recur(parent, nparams - 1)
469+
if (tycon != NoType) {
470+
val tparam = tycon.typeParams.apply(nparams)
471+
if (tparam.name == name) {
472+
(tycon, args :+ tp.info.argType(tparam))
473+
} else fail
474+
} else fail
475+
} else fail
476+
case tp =>
477+
(tp, Nil)
478+
}
479+
val result @ (tycon, args) = recur(this, typeParams.length)
480+
if (tycon != NoType) result else (this, Nil)
481+
}
482+
483+
final def splitArgsCompletely(implicit ctx: Context): (Type, List[Type]) = {
484+
val result @ (tycon, args) = splitArgs
485+
if (args.length == tycon.typeParams.length) result else (NoType, Nil)
486+
}
487+
488+
/** Turn this type into a TypeBounds RHS */
489+
final def toRHS(tparam: Symbol)(implicit ctx: Context): TypeBounds = {
490+
val v = tparam.variance
491+
if (v > 0) TypeBounds(defn.NothingType, this)
492+
else if (v < 0) TypeBounds(this, defn.AnyType)
458493
else TypeBounds(this, this)
459494
}
460495

496+
/** If this is the image of a type argument, recover the type argument,
497+
* otherwise NoType.
498+
*/
499+
final def argType(tparam: Symbol)(implicit ctx: Context): Type = this match {
500+
case TypeBounds(lo, hi) =>
501+
val v = tparam.variance
502+
if (v > 0 && lo.typeSymbol == defn.NothingClass) hi
503+
else if (v < 0 && hi.typeSymbol == defn.AnyClass) lo
504+
else if (v == 0 && (lo eq hi)) lo
505+
else NoType
506+
case _ =>
507+
NoType
508+
}
509+
461510
final def isWrong: Boolean = !exists // !!! needed?
462511
final def exists: Boolean = true
463512

@@ -661,7 +710,7 @@ object Types {
661710
}
662711
}
663712

664-
final class TermRefBySym(prefix: Type, val fixedSym: TermSymbol)(implicit initctx: Context)
713+
final class TermRefBySym(prefix: Type, val fixedSym: TermSymbol)(initctx: Context)
665714
extends TermRef(prefix, fixedSym.name(initctx).asTermName) with HasFixedSym {
666715
}
667716

@@ -671,7 +720,7 @@ object Types {
671720
super.loadDenot.atSignature(signature)
672721
}
673722

674-
final class TypeRefBySym(prefix: Type, val fixedSym: TypeSymbol)(implicit initctx: Context)
723+
final class TypeRefBySym(prefix: Type, val fixedSym: TypeSymbol)(initctx: Context)
675724
extends TypeRef(prefix, fixedSym.name(initctx).asTypeName) with HasFixedSym {
676725
}
677726

@@ -1017,6 +1066,7 @@ object Types {
10171066
final class CachedTypeBounds(lo: Type, hi: Type) extends TypeBounds(lo, hi)
10181067

10191068
object TypeBounds {
1069+
def empty(implicit ctx: Context) = apply(defn.NothingType, defn.AnyType)
10201070
def apply(lo: Type, hi: Type)(implicit ctx: Context) =
10211071
unique(new CachedTypeBounds(lo, hi))
10221072
}

src/dotty/tools/dotc/core/pickling/UnPickler.scala

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ abstract class UnPickler {
321321
var flags1 = flags
322322
if (flags is TypeParam) {
323323
name1 = name1.expandedName(owner)
324-
flags1 |= ProtectedLocal
324+
flags1 |= TypeParamFlags
325325
}
326326
ctx.newLazySymbol(owner, name1, flags1, completeSym(tag))
327327
case CLASSsym =>
@@ -428,7 +428,7 @@ abstract class UnPickler {
428428
val tycon =
429429
if (isLocal(sym)) TypeRef(pre, sym.asType)
430430
else TypeRef(pre, sym.name.asTypeName)
431-
tycon.applyToArgs(until(end, readTypeRef))
431+
tycon.appliedTo(until(end, readTypeRef))
432432
case TYPEBOUNDStpe =>
433433
TypeBounds(readTypeRef(), readTypeRef())
434434
case REFINEDtpe =>
@@ -930,7 +930,7 @@ abstract class UnPickler {
930930

931931
protected def errorMissingRequirement(name: Name, owner: Symbol): Symbol =
932932
MissingRequirementError.signal(
933-
s"bad reference while unpickling $filename: ${ctx.showNameDetailed(name)} not found in $owner"
933+
s"bad reference while unpickling $filename: ${ctx.showDetailed(name)} not found in $owner"
934934
)
935935

936936
// 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 {
980980
case cinfo => (Nil, cinfo)
981981
}
982982
val selfType = if (j > 0) at(j, () => readType()) else denot.typeConstructor
983-
var refinements = Map[TypeName, Type]().withDefaultValue(NoType)
984-
def normalizeToRef(tp: Type): TypeRef = tp match {
985-
case tp @ RefinedType(tp1, name: TypeName) =>
986-
refinements = (refinements + (name -> (refinements(name) & tp.info)))
987-
.withDefaultValue(NoType)
988-
normalizeToRef(tp1)
989-
case tp: TypeRef =>
990-
tp
991-
case _ =>
992-
throw new TypeError(s"unexpected parent type: $tp")
993-
}
994-
denot.parents = parents map normalizeToRef
983+
tparams foreach decls.enter
984+
denot.parents = ctx.normalizeToRefs(parents, cls, decls)
995985
denot.selfType = selfType
996-
denot.decls = newScope
997-
tparams foreach denot.decls.enter
998-
for ((name, tpe) <- refinements) denot.decls.enter {
999-
val formal = cls.info.member(name).symbol
1000-
val bounds = tpe.toAlias(formal)
1001-
ctx.newSymbol(cls, name, formal.flags & RetainedTypeArgFlags, bounds)
1002-
}
986+
denot.decls = decls
1003987
} catch {
1004988
case e: MissingRequirementError => throw toTypeError(e)
1005989
}

0 commit comments

Comments
 (0)