From 3b7cba4666be03991083fe89780120eae9843c52 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 24 Aug 2014 17:49:48 +0200 Subject: Make type creators work for erased types. - Some types are different when erased (e.g. prefixes are NoPrefix) - Some types are forbidden when erased. Put in assertions to check that fact. Also, some renaming and doc comments to make creation of TermRefs and TypeRefs clearer. --- src/dotty/tools/dotc/ast/tpd.scala | 2 +- src/dotty/tools/dotc/config/Config.scala | 3 + src/dotty/tools/dotc/core/Annotations.scala | 2 +- src/dotty/tools/dotc/core/Denotations.scala | 4 +- src/dotty/tools/dotc/core/Scopes.scala | 2 +- src/dotty/tools/dotc/core/SymDenotations.scala | 4 +- src/dotty/tools/dotc/core/Types.scala | 142 +++++++++++++++++++------ src/dotty/tools/dotc/typer/Implicits.scala | 2 +- src/dotty/tools/dotc/typer/ImportInfo.scala | 2 +- src/dotty/tools/dotc/typer/Typer.scala | 2 +- 10 files changed, 121 insertions(+), 44 deletions(-) (limited to 'src/dotty') diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index 56cd35344..7cdd8b7ac 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -497,7 +497,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def select(sym: Symbol)(implicit ctx: Context): Select = untpd.Select(tree, sym.name).withType( - TermRef.withSig(tree.tpe, sym.name.asTermName, sym.signature, sym.denot.asSeenFrom(tree.tpe))) + TermRef.withSigAndDenot(tree.tpe, sym.name.asTermName, sym.signature, sym.denot.asSeenFrom(tree.tpe))) def selectWithSig(name: Name, sig: Signature)(implicit ctx: Context) = untpd.SelectWithSig(tree, name, sig) diff --git a/src/dotty/tools/dotc/config/Config.scala b/src/dotty/tools/dotc/config/Config.scala index 906d17380..6360e080f 100644 --- a/src/dotty/tools/dotc/config/Config.scala +++ b/src/dotty/tools/dotc/config/Config.scala @@ -48,4 +48,7 @@ object Config { * variance of the underlying lambda class. */ final val checkLambdaVariance = false + + /** Check that certain types cannot be created in erasedTypes phases */ + final val checkUnerased = true } \ No newline at end of file diff --git a/src/dotty/tools/dotc/core/Annotations.scala b/src/dotty/tools/dotc/core/Annotations.scala index f67381ddc..c61c46858 100644 --- a/src/dotty/tools/dotc/core/Annotations.scala +++ b/src/dotty/tools/dotc/core/Annotations.scala @@ -68,7 +68,7 @@ object Annotations { deferred(atp.classSymbol, implicit ctx => New(atp, args)) def makeAlias(sym: TermSymbol)(implicit ctx: Context) = - apply(defn.AliasAnnot, List(Ident(TermRef.withSig(sym.owner.thisType, sym.name, sym.signature, sym)))) + apply(defn.AliasAnnot, List(Ident(TermRef.withSigAndDenot(sym.owner.thisType, sym.name, sym.signature, sym)))) def makeChild(sym: Symbol)(implicit ctx: Context) = apply(defn.ChildAnnot.typeRef.appliedTo(sym.owner.thisType.select(sym.name, sym)), Nil) diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala index fa2292c60..557c80b21 100644 --- a/src/dotty/tools/dotc/core/Denotations.scala +++ b/src/dotty/tools/dotc/core/Denotations.scala @@ -424,7 +424,7 @@ object Denotations { * and at signature `NotAMethod`. */ def valRef(implicit ctx: Context): TermRef = - TermRef.withSig(symbol.owner.thisType, symbol.name.asTermName, Signature.NotAMethod, this) + TermRef.withSigAndDenot(symbol.owner.thisType, symbol.name.asTermName, Signature.NotAMethod, this) /** The TermRef representing this term denotation at its original location * at the denotation's signature. @@ -432,7 +432,7 @@ object Denotations { * denotation via a call to `info`. */ def termRefWithSig(implicit ctx: Context): TermRef = - TermRef.withSig(symbol.owner.thisType, symbol.name.asTermName, signature, this) + TermRef.withSigAndDenot(symbol.owner.thisType, symbol.name.asTermName, signature, this) /** The NamedType representing this denotation at its original location. * Same as either `typeRef` or `termRefWithSig` depending whether this denotes a type or not. diff --git a/src/dotty/tools/dotc/core/Scopes.scala b/src/dotty/tools/dotc/core/Scopes.scala index 426df83bc..c8252e02e 100644 --- a/src/dotty/tools/dotc/core/Scopes.scala +++ b/src/dotty/tools/dotc/core/Scopes.scala @@ -298,7 +298,7 @@ object Scopes { while (e ne null) { if (e.sym is Implicit) { val d = e.sym.denot - irefs += TermRef.withSig(NoPrefix, e.sym.asTerm.name, d.signature, e.sym.denot) + irefs += TermRef.withSigAndDenot(NoPrefix, d.name.asTermName, d.signature, d) } e = e.prev } diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index 310dde912..e60633bb6 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -830,10 +830,10 @@ object SymDenotations { TermRef(owner.thisType, name.asTermName, this) override def valRef(implicit ctx: Context): TermRef = - TermRef.withSig(owner.thisType, name.asTermName, Signature.NotAMethod, this) + TermRef.withSigAndDenot(owner.thisType, name.asTermName, Signature.NotAMethod, this) override def termRefWithSig(implicit ctx: Context): TermRef = - TermRef.withSig(owner.thisType, name.asTermName, signature, this) + TermRef.withSigAndDenot(owner.thisType, name.asTermName, signature, this) def nonMemberTermRef(implicit ctx: Context): TermRef = TermRef.withNonMemberSym(owner.thisType, name.asTermName, symbol.asTerm) diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 46cb92832..a8bfe61e0 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -717,7 +717,7 @@ object Types { /** The type , reduced if possible */ def select(name: Name)(implicit ctx: Context): Type = name match { case name: TermName => - TermRef(this, name) + TermRef.all(this, name) case name: TypeName => val res = lookupRefined(name) if (res.exists) res else TypeRef(this, name) @@ -1327,7 +1327,7 @@ object Types { override def isOverloaded(implicit ctx: Context) = denot.isOverloaded private def rewrap(sd: SingleDenotation)(implicit ctx: Context) = - TermRef.withSig(prefix, name, sd.signature, sd) + TermRef.withSigAndDenot(prefix, name, sd.signature, sd) def alternatives(implicit ctx: Context): List[TermRef] = denot.alternatives map rewrap @@ -1357,7 +1357,7 @@ object Types { sig != Signature.OverloadedSignature && symbol.exists) { val ownSym = symbol - TermRef(prefix, name).withDenot(asMemberOf(prefix).disambiguate(_ eq ownSym)) + TermRef.all(prefix, name).withDenot(asMemberOf(prefix).disambiguate(_ eq ownSym)) } else TermRef.withSig(prefix, name, sig) } @@ -1409,9 +1409,23 @@ object Types { final class NonMemberTermRef(prefix: Type, name: TermName, val fixedSym: TermSymbol) extends TermRef(prefix, name) with WithNonMemberSym final class NonMemberTypeRef(prefix: Type, name: TypeName, val fixedSym: TypeSymbol) extends TypeRef(prefix, name) with WithNonMemberSym + /** Compute prefix at current phase. If current phase has erasure semantics + * returns NoPrefix, otherwise the given prefix + */ + private def atCurrentPhase(prefix: Type)(implicit ctx: Context) = + if (ctx.phase.erasedTypes) NoPrefix else prefix + + /** Is the prefix seen at current phase the same as NoPrefix? */ + private def isMissing(prefix: Type)(implicit ctx: Context) = + (prefix eq NoPrefix) || ctx.phase.erasedTypes + + /** Assert current phase does not have erasure semantics */ + private def assertUnerased()(implicit ctx: Context) = + if (Config.checkUnerased) assert(!ctx.phase.erasedTypes) + object NamedType { def apply(prefix: Type, name: Name)(implicit ctx: Context) = - if (name.isTermName) TermRef(prefix, name.asTermName) + if (name.isTermName) TermRef.all(prefix, name.asTermName) else TypeRef(prefix, name.asTypeName) def apply(prefix: Type, name: Name, denot: Denotation)(implicit ctx: Context) = if (name.isTermName) TermRef(prefix, name.asTermName, denot) @@ -1422,58 +1436,100 @@ object Types { } object TermRef { - def apply(prefix: Type, name: TermName)(implicit ctx: Context): TermRef = - ctx.uniqueNamedTypes.enterIfNew(prefix, name).asInstanceOf[TermRef] + /** Create term ref with given name, without specifying a signature. + * Its meaning is the (potentially multi-) denotation of the member(s) + * of prefix with given name. + */ + def all(prefix: Type, name: TermName)(implicit ctx: Context): TermRef = { + ctx.uniqueNamedTypes.enterIfNew(atCurrentPhase(prefix), name).asInstanceOf[TermRef] + } + + /** Create term ref referring to given symbol, taking the signature + * from the symbol if it is completed, or creating a term ref without + * signature, if symbol is not yet completed. + */ def apply(prefix: Type, sym: TermSymbol)(implicit ctx: Context): TermRef = withSymAndName(prefix, sym, sym.name) + /** Create term ref to given initial denotation, taking the signature + * from the denotation if it is completed, or creating a term ref without + * signature, if denotation is not yet completed. + */ def apply(prefix: Type, name: TermName, denot: Denotation)(implicit ctx: Context): TermRef = { - if (prefix eq NoPrefix) apply(prefix, denot.symbol.asTerm) + if (isMissing(prefix)) apply(prefix, denot.symbol.asTerm) else denot match { case denot: SymDenotation if denot.isCompleted => withSig(prefix, name, denot.signature) - case _ => apply(prefix, name) + case _ => all(prefix, name) } } withDenot denot + /** Create a non-member term ref (which cannot be reloaded using `member`), + * with given prefix, name, and signature + */ def withNonMemberSym(prefix: Type, name: TermName, sym: TermSymbol)(implicit ctx: Context): TermRef = - unique(new NonMemberTermRef(prefix, name, sym)) - + unique(new NonMemberTermRef(atCurrentPhase(prefix), name, sym)) + + /** Create a term ref referring to given symbol with given name, taking the signature + * from the symbol if it is completed, or creating a term ref without + * signature, if symbol is not yet completed. This is very similar to TermRef(Type, Symbol), + * except for two differences: + * (1) The symbol might not yet have a denotation, so the name needs to be given explicitly. + * (2) The name in the term ref need not be the same as the name of the Symbol. + */ def withSymAndName(prefix: Type, sym: TermSymbol, name: TermName)(implicit ctx: Context): TermRef = - if (prefix eq NoPrefix) + if (isMissing(prefix)) withNonMemberSym(prefix, name, sym) else if (sym.defRunId != NoRunId && sym.isCompleted) withSig(prefix, name, sym.signature) withSym (sym, sym.signature) else - apply(prefix, name) withSym (sym, Signature.NotAMethod) + all(prefix, name) withSym (sym, Signature.NotAMethod) + /** Create a term ref to given symbol, taking the signature from the symbol + * (which must be completed). + */ def withSig(prefix: Type, sym: TermSymbol)(implicit ctx: Context): TermRef = - unique(withSig(prefix, sym.name, sym.signature).withSym(sym, sym.signature)) + if (isMissing(prefix)) withNonMemberSym(prefix, sym.name, sym) + else withSig(prefix, sym.name, sym.signature).withSym(sym, sym.signature) + /** Create a term ref with given prefix, name and signature */ def withSig(prefix: Type, name: TermName, sig: Signature)(implicit ctx: Context): TermRef = - unique(new TermRefWithSignature(prefix, name, sig)) + unique(new TermRefWithSignature(atCurrentPhase(prefix), name, sig)) - def withSig(prefix: Type, name: TermName, sig: Signature, denot: Denotation)(implicit ctx: Context): TermRef = - (if (prefix eq NoPrefix) apply(prefix, denot.symbol.asTerm) + /** Create a term ref with given prefix, name, signature, and initial denotation */ + def withSigAndDenot(prefix: Type, name: TermName, sig: Signature, denot: Denotation)(implicit ctx: Context): TermRef = + (if (isMissing(prefix)) withNonMemberSym(prefix, denot.symbol.asTerm.name, denot.symbol.asTerm) else withSig(prefix, name, sig)) withDenot denot } object TypeRef { + /** Create type ref with given prefix and name */ def apply(prefix: Type, name: TypeName)(implicit ctx: Context): TypeRef = - ctx.uniqueNamedTypes.enterIfNew(prefix, name).asInstanceOf[TypeRef] + ctx.uniqueNamedTypes.enterIfNew(atCurrentPhase(prefix), name).asInstanceOf[TypeRef] + /** Create type ref to given symbol */ def apply(prefix: Type, sym: TypeSymbol)(implicit ctx: Context): TypeRef = withSymAndName(prefix, sym, sym.name) + /** Create a non-member type ref (which cannot be reloaded using `member`), + * with given prefix, name, and symbol. + */ def withNonMemberSym(prefix: Type, name: TypeName, sym: TypeSymbol)(implicit ctx: Context): TypeRef = - unique(new NonMemberTypeRef(prefix, name, sym)) + unique(new NonMemberTypeRef(atCurrentPhase(prefix), name, sym)) + /** Create a type ref referring to given symbol with given name. + * This is very similar to TypeRef(Type, Symbol), + * except for two differences: + * (1) The symbol might not yet have a denotation, so the name needs to be given explicitly. + * (2) The name in the type ref need not be the same as the name of the Symbol. + */ def withSymAndName(prefix: Type, sym: TypeSymbol, name: TypeName)(implicit ctx: Context): TypeRef = - if (prefix eq NoPrefix) withNonMemberSym(prefix, name, sym) + if (isMissing(prefix)) withNonMemberSym(prefix, name, sym) else apply(prefix, name).withSym(sym, Signature.NotAMethod) + /** Create a type ref with given name and initial denotation */ def apply(prefix: Type, name: TypeName, denot: Denotation)(implicit ctx: Context): TypeRef = - (if (prefix eq NoPrefix) apply(prefix, denot.symbol.asType) else apply(prefix, name)) withDenot denot + (if (isMissing(prefix)) apply(prefix, denot.symbol.asType) else apply(prefix, name)) withDenot denot } // --- Other SingletonTypes: ThisType/SuperType/ConstantType --------------------------- @@ -1520,8 +1576,10 @@ object Types { final class CachedConstantType(value: Constant) extends ConstantType(value) object ConstantType { - def apply(value: Constant)(implicit ctx: Context) = + def apply(value: Constant)(implicit ctx: Context) = { + assertUnerased() unique(new CachedConstantType(value)) + } } case class LazyRef(refFn: () => Type) extends UncachedProxyType with ValueType { @@ -1644,6 +1702,7 @@ object Types { unchecked(tp1, tp2) } def unchecked(tp1: Type, tp2: Type)(implicit ctx: Context) = { + assertUnerased() unique(new CachedAndType(tp1, tp2)) } def make(tp1: Type, tp2: Type)(implicit ctx: Context): Type = @@ -1667,8 +1726,10 @@ object Types { final class CachedOrType(tp1: Type, tp2: Type) extends OrType(tp1, tp2) object OrType { - def apply(tp1: Type, tp2: Type)(implicit ctx: Context) = + def apply(tp1: Type, tp2: Type)(implicit ctx: Context) = { + assertUnerased() unique(new CachedOrType(tp1, tp2)) + } def make(tp1: Type, tp2: Type)(implicit ctx: Context): Type = if (tp1 eq tp2) tp1 else apply(tp1, tp2) } @@ -1844,8 +1905,10 @@ object Types { final class CachedExprType(resultType: Type) extends ExprType(resultType) object ExprType { - def apply(resultType: Type)(implicit ctx: Context) = + def apply(resultType: Type)(implicit ctx: Context) = { + assertUnerased() unique(new CachedExprType(resultType)) + } } case class PolyType(paramNames: List[TypeName])(paramBoundsExp: PolyType => List[TypeBounds], resultTypeExp: PolyType => Type) @@ -1907,10 +1970,10 @@ object Types { def paramNum: Int } - case class MethodParam(binder: MethodType, paramNum: Int) extends ParamType with SingletonType { + abstract case class MethodParam(binder: MethodType, paramNum: Int) extends ParamType with SingletonType { type BT = MethodType override def underlying(implicit ctx: Context): Type = binder.paramTypes(paramNum) - def copyBoundType(bt: BT) = MethodParam(bt, paramNum) + def copyBoundType(bt: BT) = new MethodParamImpl(bt, paramNum) // need to customize hashCode and equals to prevent infinite recursion for dep meth types. override def computeHash = addDelta(System.identityHashCode(binder), paramNum) @@ -1924,6 +1987,15 @@ object Types { override def toString = s"MethodParam(${binder.paramNames(paramNum)})" } + class MethodParamImpl(binder: MethodType, paramNum: Int) extends MethodParam(binder, paramNum) + + object MethodParam { + def apply(binder: MethodType, paramNum: Int)(implicit ctx: Context): MethodParam = { + assertUnerased() + new MethodParamImpl(binder, paramNum) + } + } + case class PolyParam(binder: PolyType, paramNum: Int) extends ParamType { type BT = PolyType def copyBoundType(bt: BT) = PolyParam(bt, paramNum) @@ -2111,15 +2183,17 @@ object Types { def selfType(implicit ctx: Context): Type = { if (selfTypeCache == null) { def fullRef = fullyAppliedRef(cls.typeRef, cls.typeParams) - selfTypeCache = selfInfo match { - case NoType => - fullRef - case tp: Type => - if (cls is Module) tp else AndType(tp, fullRef) - case self: Symbol => - assert(!(cls is Module)) - AndType(self.info, fullRef) - } + selfTypeCache = + if (ctx.erasedTypes) fullRef + else selfInfo match { + case NoType => + fullRef + case tp: Type => + if (cls is Module) tp else AndType(tp, fullRef) + case self: Symbol => + assert(!(cls is Module)) + AndType(self.info, fullRef) + } } selfTypeCache } diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala index da1492d61..571b37eb0 100644 --- a/src/dotty/tools/dotc/typer/Implicits.scala +++ b/src/dotty/tools/dotc/typer/Implicits.scala @@ -310,7 +310,7 @@ trait ImplicitRunInfo { self: RunInfo => def addRef(companion: TermRef): Unit = { val compSym = companion.symbol if (compSym is Package) - addRef(TermRef(companion, nme.PACKAGE)) + addRef(TermRef.withSig(companion, nme.PACKAGE, Signature.NotAMethod)) else if (compSym.exists) comps += companion.asSeenFrom(pre, compSym.owner).asInstanceOf[TermRef] } diff --git a/src/dotty/tools/dotc/typer/ImportInfo.scala b/src/dotty/tools/dotc/typer/ImportInfo.scala index 18e5db209..9152a8d54 100644 --- a/src/dotty/tools/dotc/typer/ImportInfo.scala +++ b/src/dotty/tools/dotc/typer/ImportInfo.scala @@ -86,7 +86,7 @@ class ImportInfo(val sym: Symbol, val selectors: List[untpd.Tree], val isRootImp for { renamed <- reverseMapping.keys denot <- pre.member(reverseMapping(renamed)).altsWith(_ is Implicit) - } yield TermRef.withSig(pre, renamed, denot.signature, denot) + } yield TermRef.withSigAndDenot(pre, renamed, denot.signature, denot) } /** The root import symbol hidden by this symbol, or NoSymbol if no such symbol is hidden. diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index e1f860589..1cfd03e4c 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -1143,7 +1143,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit val altDenots = ref.denot.alternatives typr.println(i"adapt overloaded $ref with alternatives ${altDenots map (_.info)}%, %") val alts = altDenots map (alt => - TermRef.withSig(ref.prefix, ref.name, alt.info.signature, alt)) + TermRef.withSigAndDenot(ref.prefix, ref.name, alt.info.signature, alt)) def expectedStr = err.expectedTypeStr(pt) resolveOverloaded(alts, pt) match { case alt :: Nil => -- cgit v1.2.3