aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-11-27 14:17:12 +0100
committerMartin Odersky <odersky@gmail.com>2013-11-27 14:17:12 +0100
commitf8c9dc95929655a198066652cd12109329836198 (patch)
tree32f8c29e89ad426b7c0d6947cdda44878dc414fe /src/dotty/tools/dotc
parentf0b4fc58e0c5e5372c23bd817954ed3aa82b2102 (diff)
downloaddotty-f8c9dc95929655a198066652cd12109329836198.tar.gz
dotty-f8c9dc95929655a198066652cd12109329836198.tar.bz2
dotty-f8c9dc95929655a198066652cd12109329836198.zip
Changed Signatures
Signatures have a different meaning before and after erasure. After erasure, the result type counts also whereas before it doesn't. The new definitions refelect this behavior.
Diffstat (limited to 'src/dotty/tools/dotc')
-rw-r--r--src/dotty/tools/dotc/config/Config.scala3
-rw-r--r--src/dotty/tools/dotc/core/Denotations.scala48
-rw-r--r--src/dotty/tools/dotc/core/Signature.scala56
-rw-r--r--src/dotty/tools/dotc/core/SymDenotations.scala53
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala2
-rw-r--r--src/dotty/tools/dotc/core/Types.scala12
-rw-r--r--src/dotty/tools/dotc/core/pickling/UnPickler.scala2
-rw-r--r--src/dotty/tools/dotc/core/transform/Erasure.scala18
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala1
9 files changed, 116 insertions, 79 deletions
diff --git a/src/dotty/tools/dotc/config/Config.scala b/src/dotty/tools/dotc/config/Config.scala
index 4d93fae29..124b8d61c 100644
--- a/src/dotty/tools/dotc/config/Config.scala
+++ b/src/dotty/tools/dotc/config/Config.scala
@@ -2,9 +2,10 @@ package dotty.tools.dotc.config
object Config {
- final val cacheMemberNames = true
+ final val cacheMembersNamed = true
final val cacheAsSeenFrom = true
final val useFingerPrints = true
+ final val cacheMemberNames = true
/** When set, use new signature-based matching.
* Advantantage of doing so: It's supposed to be faster
diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala
index 8aafa5e64..f904f8d78 100644
--- a/src/dotty/tools/dotc/core/Denotations.scala
+++ b/src/dotty/tools/dotc/core/Denotations.scala
@@ -9,6 +9,7 @@ import Names.TypeName
import Symbols.NoSymbol
import Symbols._
import Types._, Periods._, Flags._, Transformers._, Decorators._
+import transform.Erasure
import printing.Texts._
import printing.Printer
import io.AbstractFile
@@ -26,8 +27,7 @@ import Decorators.SymbolIteratorDecorator
*
* Lines ending in a horizontal line mean subtying (right is a subtype of left).
*
- * NamedType------NamedTypeWithSignature
- *
+ * NamedType------TermRefWithSignature
* | | Symbol---------ClassSymbol
* | | | |
* | denot | denot | denot | denot
@@ -44,8 +44,9 @@ import Decorators.SymbolIteratorDecorator
* NamedType A type consisting of a prefix type and a name, with fields
* prefix: Type
* name: Name
- * NamedTypeWithSignature A named type that has in addition a signature to select an overloaded variant, with new field
- * signature: Signature
+ * It has two subtypes: TermRef and TypeRef
+ * TermRefWithSignature A TermRef that has in addition a signature to select an overloaded variant, with new field
+ * sig: Signature
* Symbol A label for a definition or declaration in one compiler run
* ClassSymbol A symbol representing a class
* Denotation The meaning of a named type or symbol during a period
@@ -65,27 +66,6 @@ import Decorators.SymbolIteratorDecorator
*/
object Denotations {
- /** The signature of a denotation.
- * Overloaded denotations with the same name are distinguished by
- * their signatures. A signature is a list of the fully qualified names
- * of the type symbols of the erasure of the parameters of the
- * denotation. For instance a definition
- *
- * def f(x: Int)(y: List[String]): String
- *
- * would have signature
- *
- * List("scala.Int".toTypeName, "scala.collection.immutable.List".toTypeName)
- *
- * TODO: discriminate on result type as well !!!
- */
- type Signature = List[TypeName]
-
- /** The signature of a val or parameterless def, as opposed
- * to List(), which is the signature of a zero-parameter def.
- */
- val NotAMethod: Signature = List(Names.EmptyTypeName)
-
/** A denotation is the result of resolving
* a name (either simple identifier or select) during a given period.
*
@@ -231,8 +211,7 @@ object Denotations {
}
case denot1: SingleDenotation =>
if (denot1 eq denot2) denot1
- else if (denot1.signature != denot2.signature) NoDenotation
- else {
+ else if (denot1.signature matches denot2.signature) {
val info1 = denot1.info
val info2 = denot2.info
val sym2 = denot2.symbol
@@ -254,6 +233,7 @@ object Denotations {
}
}
}
+ else NoDenotation
}
if (this eq that) this
@@ -275,8 +255,7 @@ object Denotations {
def | (that: Denotation, pre: Type)(implicit ctx: Context): Denotation = {
def unionDenot(denot1: SingleDenotation, denot2: SingleDenotation): Denotation =
- if (denot1.signature != denot2.signature) NoDenotation
- else {
+ if (denot1.signature matches denot2.signature) {
val info1 = denot1.info
val info2 = denot2.info
val sym2 = denot2.symbol
@@ -304,6 +283,7 @@ object Denotations {
}
}
}
+ else NoDenotation
def throwError = throw new MatchError(s"$this | $that")
@@ -378,15 +358,15 @@ object Denotations {
def hasUniqueSym: Boolean
override def isType = info.isInstanceOf[TypeType]
override def signature(implicit ctx: Context): Signature = {
- if (isType) NotAMethod
+ if (isType) Signature.NotAMethod
else info match {
case tp: PolyType =>
tp.resultType match {
case mt: MethodType => mt.signature
- case _ => List()
+ case tp => Signature(tp)
}
case mt: MethodType => mt.signature
- case _ => NotAMethod
+ case _ => Signature.NotAMethod
}
}
@@ -411,7 +391,7 @@ object Denotations {
if (symbol isAccessibleFrom (pre, superAccess)) this else NoDenotation
def atSignature(sig: Signature)(implicit ctx: Context): SingleDenotation =
- if (sig == signature) this else NoDenotation
+ if (sig matches signature) this else NoDenotation
// ------ Transformations -----------------------------------------
@@ -535,7 +515,7 @@ object Denotations {
final def containsSym(sym: Symbol): Boolean =
hasUniqueSym && (symbol eq sym)
final def containsSig(sig: Signature)(implicit ctx: Context) =
- exists && signature == sig
+ exists && (signature matches sig)
final def filterWithPredicate(p: SingleDenotation => Boolean): SingleDenotation =
if (p(this)) this else NoDenotation
final def filterDisjoint(denots: PreDenotation)(implicit ctx: Context): SingleDenotation =
diff --git a/src/dotty/tools/dotc/core/Signature.scala b/src/dotty/tools/dotc/core/Signature.scala
new file mode 100644
index 000000000..50c42e96d
--- /dev/null
+++ b/src/dotty/tools/dotc/core/Signature.scala
@@ -0,0 +1,56 @@
+package dotty.tools.dotc
+package core
+
+import Names._, Types._, Contexts._
+import transform.Erasure.sigName
+
+/** The signature of a denotation.
+ * Overloaded denotations with the same name are distinguished by
+ * their signatures. A signature of a method (of type PolyType,MethodType, or ExprType) is
+ * composed of a list of signature names, one for each parameter type, plus a signature for
+ * the result type. Methods are uncurried before taking their signatures.
+ * The signature name of a type is the fully qualified name of the type symbol of the type's erasure.
+ *
+ * For instance a definition
+ *
+ * def f(x: Int)(y: List[String]): String
+ *
+ * would have signature
+ *
+ * Signature(
+ * List("scala.Int".toTypeName, "scala.collection.immutable.List".toTypeName),
+ * "scala.String".toTypeName)
+ *
+ * The signatures of non-method types are always `NotAMethod`.
+ */
+case class Signature private (paramsSig: List[TypeName], resSig: TypeName) {
+
+ /** Does this signature conincide with that signature on their parameter parts? */
+ final def sameParams(that: Signature): Boolean = this.paramsSig == that.paramsSig
+
+ /** The meaning of `matches` depends on the phase. If types are not erased,
+ * it means `sameParams`. Once types are erased, it means `==`, comparing parameter as
+ * well as result type parts.
+ */
+ final def matches(that: Signature)(implicit ctx: Context) =
+ if (ctx.erasedTypes) equals(that) else sameParams(that)
+
+ /** Construct a signature by prepending the signature names of the given `params`
+ * to the parameter part of this signature.
+ */
+ def ++:(params: List[Type])(implicit ctx: Context) =
+ Signature((params map sigName) ++ paramsSig, resSig)
+
+}
+
+object Signature {
+
+ /** The signature of everything that's not a method, i.e. that has
+ * a type different from PolyType, MethodType, or ExprType.
+ */
+ val NotAMethod = Signature(List(EmptyTypeName), EmptyTypeName)
+
+ /** The signature of a method with no parameters and result type `resultType`. */
+ def apply(resultType: Type)(implicit ctx: Context): Signature =
+ apply(Nil, sigName(resultType))
+} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala
index fa7b71450..2a0b9e9ce 100644
--- a/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -10,6 +10,7 @@ import collection.immutable.BitSet
import scala.reflect.io.AbstractFile
import Decorators.SymbolIteratorDecorator
import annotation.tailrec
+import util.SimpleMap
import config.Config
trait SymDenotations { this: Context =>
@@ -655,7 +656,7 @@ object SymDenotations {
* and at signature `NotAMethod`.
*/
def valRef(implicit ctx: Context): TermRef =
- TermRef.withSig(owner.thisType, name.asTermName, NotAMethod).withDenot(this)
+ TermRef.withSig(owner.thisType, name.asTermName, Signature.NotAMethod).withDenot(this)
/** The TermRef representing this term denotation at its original location
* at the denotation's signature.
@@ -931,7 +932,7 @@ object SymDenotations {
* have existing symbols.
*/
final def membersNamed(name: Name)(implicit ctx: Context): PreDenotation =
- if (Config.cacheMemberNames) {
+ if (Config.cacheMembersNamed) {
var denots: PreDenotation = memberCache lookup name
if (denots == null) {
denots = computeMembersNamed(name)
@@ -1027,7 +1028,7 @@ object SymDenotations {
}
}
- private[this] var memberNamesCache: Map[NameFilter, Set[Name]] = Map()
+ private[this] var memberNamesCache: SimpleMap[NameFilter, Set[Name]] = SimpleMap.Empty
def memberNames(keepOnly: NameFilter)(implicit ctx: Context): Set[Name] = {
def computeMemberNames: Set[Name] = {
@@ -1036,36 +1037,35 @@ object SymDenotations {
val candidates = inheritedNames ++ ownNames
candidates filter (keepOnly(thisType, _))
}
- if (this is PackageClass) computeMemberNames // don't cache package member names; they might change
- else memberNamesCache get keepOnly match {
- case Some(names) =>
- names
- case _ =>
+ if ((this is PackageClass) || !Config.cacheMemberNames) computeMemberNames // don't cache package member names; they might change
+ else {
+ val cached = memberNamesCache(keepOnly)
+ if (cached != null) cached
+ else {
setFlag(Frozen)
val names = computeMemberNames
memberNamesCache = memberNamesCache.updated(keepOnly, names)
names
+ }
}
}
- private[this] var fullNameCache: Map[Char, Name] = Map()
-
- override final def fullName(separator: Char)(implicit ctx: Context): Name =
- fullNameCache get separator match {
- case Some(fn) =>
- fn
- case _ =>
- val fn = super.fullName(separator)
- fullNameCache = fullNameCache.updated(separator, fn)
- fn
+ private[this] var fullNameCache: SimpleMap[Character, Name] = SimpleMap.Empty
+ override final def fullName(separator: Char)(implicit ctx: Context): Name = {
+ val cached = fullNameCache(separator)
+ if (cached != null) cached
+ else {
+ val fn = super.fullName(separator)
+ fullNameCache = fullNameCache.updated(separator, fn)
+ fn
}
+ }
// to avoid overloading ambiguities
override def fullName(implicit ctx: Context): Name = super.fullName
override def primaryConstructor(implicit ctx: Context): Symbol = {
- val cname =
- if (this is Trait | ImplClass) nme.TRAIT_CONSTRUCTOR else nme.CONSTRUCTOR
+ val cname = if (this is Trait | ImplClass) nme.TRAIT_CONSTRUCTOR else nme.CONSTRUCTOR
decls.denotsNamed(cname).first.symbol
}
}
@@ -1086,7 +1086,7 @@ object SymDenotations {
* Note: LazyTypes double up as (constant) functions from Symbol and
* from (TermSymbol, ClassSymbol) to LazyType. That way lazy types can be
* directly passed to symbol creation methods in Symbols that demand instances
- * of these types.
+ * of these function types.
*/
abstract class LazyType extends UncachedGroundType
with (Symbol => LazyType)
@@ -1102,6 +1102,9 @@ object SymDenotations {
private var mySourceModuleFn: () => Symbol = NoSymbolFn
private var myModuleClassFn: () => Symbol = NoSymbolFn
+ /** A proxy to this lazy type that keeps the complete operation
+ * but provides fresh slots for scope/sourceModule/moduleClass
+ */
def proxy: LazyType = new LazyType {
override def complete(denot: SymDenotation) = self.complete(denot)
}
@@ -1117,15 +1120,11 @@ object SymDenotations {
val NoSymbolFn = () => NoSymbol
+ /** A missing completer */
class NoCompleter extends LazyType {
def complete(denot: SymDenotation): Unit = unsupported("complete")
}
- /** A missing completer */
- object NoCompleter extends LazyType {
- override def complete(denot: SymDenotation): Unit = unsupported("complete")
- }
-
/** A lazy type for modules that points to the module class.
* Needed so that `moduleClass` works before completion.
* Completion of modules is always completion of the underlying
@@ -1134,7 +1133,7 @@ object SymDenotations {
class ModuleCompleter(override val moduleClass: ClassSymbol)(implicit cctx: CondensedContext)
extends LazyType {
def complete(denot: SymDenotation): Unit = {
- val from = denot.moduleClass.denot.asClass
+ val from = moduleClass.denot.asClass
denot.setFlag(from.flags.toTermFlags & RetainedModuleValFlags)
denot.annotations = from.annotations filter (_.appliesToModule)
// !!! ^^^ needs to be revised later. The problem is that annotations might
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index dfb9b382f..53098e943 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -313,7 +313,7 @@ class TypeComparer(initctx: Context) extends DotClass {
case tp2: PolyType =>
tp1 match {
case tp1: PolyType =>
- tp1.signature == tp2.signature &&
+ (tp1.signature sameParams tp2.signature) &&
matchingTypeParams(tp1, tp2) &&
isSubType(tp1.resultType, tp2.resultType.subst(tp2, tp1))
case _ =>
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 9c849bfdf..fb430f336 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -487,7 +487,7 @@ object Types {
* poly types.
*/
def matches(that: Type)(implicit ctx: Context): Boolean =
- if (Config.newMatch) this.signature == that.signature
+ if (Config.newMatch) this.signature matches that.signature
else track("matches") {
ctx.typeComparer.matchesType(
this, that, alwaysMatchSimple = !ctx.phase.erasedTypes)
@@ -798,7 +798,7 @@ object Types {
* pattern is that method signatures use caching, so encapsulation
* is improved using an OO scheme).
*/
- def signature(implicit ctx: Context): Signature = NotAMethod
+ def signature(implicit ctx: Context): Signature = Signature.NotAMethod
/** Convert to text */
def toText(printer: Printer): Text = printer.toText(this)
@@ -1406,11 +1406,11 @@ object Types {
override def signature(implicit ctx: Context): Signature = {
def computeSignature: Signature = {
- val followSig = resultType match {
+ val followSig: Signature = resultType match {
case rtp: MethodType => rtp.signature
- case _ => Nil
+ case tp => Signature(tp)
}
- (paramTypes map Erasure.paramSignature) ++ followSig
+ paramTypes ++: followSig
}
if (ctx.runId != mySignatureRunId) {
mySignature = computeSignature
@@ -1499,7 +1499,7 @@ object Types {
abstract case class ExprType(override val resultType: Type)
extends CachedProxyType with TermType {
override def underlying(implicit ctx: Context): Type = resultType
- override def signature(implicit ctx: Context): Signature = Nil
+ override def signature(implicit ctx: Context): Signature = Signature(resultType) // todo: cache?
def derivedExprType(resultType: Type)(implicit ctx: Context) =
if (resultType eq this.resultType) this else ExprType(resultType)
override def computeHash = doHash(resultType)
diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala
index 57fc3007a..0f4e42987 100644
--- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala
+++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala
@@ -599,7 +599,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot:
val pre = readTypeRef()
val sym = readDisambiguatedSymbolRef(_.info.isParameterless)
if (isLocal(sym) || (pre == NoPrefix)) pre select sym
- else TermRef.withSig(pre, sym.name.asTermName, NotAMethod) // !!! should become redundant
+ else TermRef.withSig(pre, sym.name.asTermName, Signature.NotAMethod) // !!! should become redundant
case SUPERtpe =>
val thistpe = readTypeRef()
val supertpe = readTypeRef()
diff --git a/src/dotty/tools/dotc/core/transform/Erasure.scala b/src/dotty/tools/dotc/core/transform/Erasure.scala
index 03726e4f5..1b86eff68 100644
--- a/src/dotty/tools/dotc/core/transform/Erasure.scala
+++ b/src/dotty/tools/dotc/core/transform/Erasure.scala
@@ -99,31 +99,31 @@ object Erasure {
if (bcs1.isEmpty) defn.ObjectClass else bcs1.head
}
- /** The parameter signature of a type.
- * Need to ensure correspondence with erasure
+ /** The name of the type as it is used in `Signature`s.
+ * Need to ensure correspondence with erasure!
*/
- def paramSignature(tp: Type)(implicit ctx: Context): TypeName = tp match {
+ def sigName(tp: Type)(implicit ctx: Context): TypeName = tp match {
case tp: TypeRef =>
val sym = tp.symbol
if (sym.isClass)
/*if (sym.isDerivedValueClass) eraseDerivedValueClassRef(tref)
else */if (sym.owner is Package) normalizeClass(sym.asClass).name
else sym.asClass.name
- else paramSignature(tp.info)
+ else sigName(tp.info)
case tp: RefinedType =>
val parent = tp.parent
if (parent isRef defn.ArrayClass)
eraseArray(tp) match {
case tp1: RefinedType if tp1.parent isRef defn.ArrayClass =>
- paramSignature(tp1.refinedInfo) ++ "[]"
+ sigName(tp1.refinedInfo) ++ "[]"
case tp1 =>
- paramSignature(tp1)
+ sigName(tp1)
}
- else paramSignature(parent)
+ else sigName(parent)
case tp: TypeProxy =>
- paramSignature(tp.underlying)
+ sigName(tp.underlying)
case AndType(tp1, tp2) =>
- paramSignature(tp1)
+ sigName(tp1)
case OrType(tp1, tp2) =>
lubClass(tp1, tp2).name
case ErrorType =>
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index a4b968c9a..e4081f633 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -979,6 +979,7 @@ class Typer extends Namer with Applications with Implicits {
def adaptOverloaded(ref: TermRef) = {
val altDenots = ref.denot.alternatives
+ println(i"adapt overloaded $ref with alternatives ${altDenots map (_.info)}%, %")
val alts = altDenots map (alt =>
TermRef.withSig(ref.prefix, ref.name, alt.info.signature).withDenot(alt))
def expectedStr = err.expectedTypeStr(pt)