summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2009-02-23 19:21:05 +0000
committerMartin Odersky <odersky@gmail.com>2009-02-23 19:21:05 +0000
commitbf35b888e49afb245883571cc00cbb5ec7341f24 (patch)
tree8c060484dde8c122f1d65fceedf0dd962a4ad90c /src/compiler/scala/tools/nsc
parenta4baf48a5fb38f29d462accc57f93032955efa0e (diff)
downloadscala-bf35b888e49afb245883571cc00cbb5ec7341f24.tar.gz
scala-bf35b888e49afb245883571cc00cbb5ec7341f24.tar.bz2
scala-bf35b888e49afb245883571cc00cbb5ec7341f24.zip
fixed several problems with cyclic references u...
fixed several problems with cyclic references uncovered by experimenting with collections. Added early type definitions.
Diffstat (limited to 'src/compiler/scala/tools/nsc')
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeInfo.scala13
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala7
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala8
-rwxr-xr-xsrc/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala23
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala3
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala68
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala37
-rwxr-xr-xsrc/compiler/scala/tools/nsc/typechecker/Namers.scala.11047
-rwxr-xr-xsrc/compiler/scala/tools/nsc/typechecker/Namers.scala.21046
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala30
-rw-r--r--src/compiler/scala/tools/nsc/util/BitSet.scala155
11 files changed, 2403 insertions, 34 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
index 9cc29f97ec..93124d95f3 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
@@ -151,11 +151,22 @@ abstract class TreeInfo {
def preSuperFields(stats: List[Tree]): List[ValDef] =
for (vdef @ ValDef(mods, _, _, _) <- stats if mods hasFlag PRESUPER) yield vdef
- def isPreSuper(tree: Tree) = tree match {
+ def isEarlyDef(tree: Tree) = tree match {
+ case TypeDef(mods, _, _, _) => mods hasFlag PRESUPER
case ValDef(mods, _, _, _) => mods hasFlag PRESUPER
case _ => false
}
+ def isEarlyValDef(tree: Tree) = tree match {
+ case ValDef(mods, _, _, _) => mods hasFlag PRESUPER
+ case _ => false
+ }
+
+ def isEarlyTypeDef(tree: Tree) = tree match {
+ case TypeDef(mods, _, _, _) => mods hasFlag PRESUPER
+ case _ => false
+ }
+
/** Is type a of the form T* ? */
def isRepeatedParamType(tpt: Tree) = tpt match {
case AppliedTypeTree(Select(_, rp), _) => rp == nme.REPEATED_PARAM_CLASS_NAME.toTypeName
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
index 10e61bc361..cf5b3cde74 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -576,9 +576,10 @@ trait Trees {
ret.symbol = vd.symbol
ret
})
- val (vdefs, rest) = body span treeInfo.isPreSuper
+ val (edefs, rest) = body span treeInfo.isEarlyDef
+ val (evdefs, etdefs) = edefs partition treeInfo.isEarlyValDef
val (lvdefs, gvdefs) = List.unzip {
- vdefs map {
+ evdefs map {
case vdef @ ValDef(mods, name, tpt, rhs) =>
(copy.ValDef(vdef, Modifiers(PRESUPER), name, tpt, rhs),
copy.ValDef(vdef, mods, name, TypeTree(), EmptyTree))
@@ -599,7 +600,7 @@ trait Trees {
List(
DefDef(constrMods, nme.CONSTRUCTOR, List(), vparamss1, TypeTree(), Block(lvdefs ::: List(superCall), Literal(()))))
}
- Template(parents, self, gvdefs ::: List.flatten(vparamss) ::: constrs ::: rest)
+ Template(parents, self, gvdefs ::: List.flatten(vparamss) ::: constrs ::: etdefs ::: rest)
}
/** Block of expressions (semicolon separated expressions) */
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index 12af98f91d..73bed5c8e4 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -2270,18 +2270,20 @@ trait Parsers extends NewScanners with MarkupParsers {
// @S: pre template body cannot stub like post body can!
val (self, body) = templateBody(true)
if (inToken == WITH && self.isEmpty) {
- val vdefs: List[ValDef] = body flatMap {
+ val earlyDefs: List[Tree] = body flatMap {
case vdef @ ValDef(mods, name, tpt, rhs) if !(mods hasFlag Flags.DEFERRED) =>
List(copy.ValDef(vdef, mods | Flags.PRESUPER, name, tpt, rhs))
+ case tdef @ TypeDef(mods, name, tparams, rhs) =>
+ List(copy.TypeDef(tdef, mods | Flags.PRESUPER, name, tparams, rhs))
case stat if !stat.isEmpty =>
- syntaxError(stat.pos, "only concrete field definitions allowed in early object initialization section", false)
+ syntaxError(stat.pos, "only type definitions and concrete field definitions allowed in early object initialization section", false)
List()
case _ => List()
}
inNextToken
val (parents, argss) = templateParents(isTrait)
val (self1, body1) = templateBodyOpt(isTrait)
- (parents, argss, self1, vdefs ::: body1)
+ (parents, argss, self1, earlyDefs ::: body1)
} else {
(List(), List(List()), self, body)
}
diff --git a/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala b/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala
index a9fc69e0b6..0516a49fff 100755
--- a/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala
+++ b/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala
@@ -4,7 +4,9 @@
*/
package scala.tools.nsc.symtab
+// todo implement in terms of BitSet
import scala.collection.mutable.ListBuffer
+import scala.collection.immutable.Map
import Math.max
/** A base type sequence (BaseTypeSeq) is an ordered sequence spanning all the base types
@@ -31,19 +33,24 @@ trait BaseTypeSeqs {
/** The number of types in the sequence */
def length: Int = elems.length
+ var pending: Map[Int, Type] = Map()
+
/** The type at i'th position in this sequence; lazy types are returned evaluated. */
def apply(i: Int): Type = elems(i) match {
case NoType =>
+ pending = Map()
elems(i) = AnyClass.tpe
throw CyclicInheritance
case rtp @ RefinedType(variants, decls) =>
// can't assert decls.isEmpty; see t0764
//if (!decls.isEmpty) assert(false, "computing closure of "+this+":"+this.isInstanceOf[RefinedType]+"/"+closureCache(j))
//Console.println("compute closure of "+this+" => glb("+variants+")")
+ pending += (i -> rtp)
elems(i) = NoType
try {
mergePrefixAndArgs(variants, -1, lubDepth(variants)) match {
case Some(tp0) =>
+ pending -= i
elems(i) = tp0
tp0
case None =>
@@ -64,9 +71,19 @@ trait BaseTypeSeqs {
/** The type symbol of the type at i'th position in this sequence;
* no evaluation needed.
*/
- def typeSymbol(i: Int): Symbol = elems(i) match {
- case RefinedType(v :: vs, _) => v.typeSymbol
- case tp => tp.typeSymbol
+ def typeSymbol(i: Int): Symbol = {
+ def tsym(tp: Type) = tp match {
+ case RefinedType(v :: vs, _) => v.typeSymbol
+ case _ => tp.typeSymbol
+ }
+ elems(i) match {
+ case NoType =>
+ pending get i match {
+ case Some(tp) => tsym(tp)
+ case _ => NoType.typeSymbol
+ }
+ case tp => tsym(tp)
+ }
}
/** Return all evaluated types in this sequence as a list */
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index 483adbdbc8..47048f2acc 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -1551,6 +1551,9 @@ trait Symbols {
tpeCache
}
+ // needed for experimentlal code for early types as type parameters
+ // def refreshType() { tpePeriod = NoPeriod }
+
override def typeConstructor: Type = {
if ((tyconCache eq null) || tyconRunId != currentRunId) {
tyconCache = typeRef(if (hasFlag(PARAM | EXISTENTIAL)) NoPrefix else owner.thisType,
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index f07454dc76..0a66361dd8 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -422,7 +422,7 @@ trait Types {
def memberType(sym: Symbol): Type = {
trackTypeIDE(sym)
//@M don't prematurely instantiate higher-kinded types, they will be instantiated by transform, typedTypeApply, etc. when really necessary
- sym.tpeHK match {
+ sym.tpeHK match {
case ov @ OverloadedType(pre, alts) =>
OverloadedType(this, alts)
/*
@@ -440,7 +440,14 @@ trait Types {
*/
case tp =>
val res = tp.asSeenFrom(this, sym.owner)
-// if (sym.name.toString == "emitSWITCH") println(this + ".memberType(" + sym +":" + sym.tpe +")" + sym.ownerChain + " = " + res);//debug
+/*
+ if (sym.name.toString == "Elem") {
+ println("pre = "+this)
+ println("pre.normalize = "+this.widen.normalize)
+ println("sym = "+sym+" in "+sym.ownerChain)
+ println("result = "+res)
+ }
+*/
res
}
}
@@ -1406,7 +1413,11 @@ trait Types {
appliedType(tp.asSeenFrom(pre, sym.owner), argsMaybeDummy)
// TODO: argsMaybeDummy --> ok? or don't instantiate type params if isHigherKinded
- def thisInfo = if (sym.isTypeMember) transformInfo(sym.info) else sym.info
+ def thisInfo =
+ if (sym.isAliasType) normalize
+ else if (sym.isTypeMember) transformInfo(sym.info)
+ else sym.info
+
def relativeInfo = if (sym.isTypeMember) transformInfo(pre.memberInfo(sym)) else pre.memberInfo(sym)
override def typeSymbol = if (sym.isAliasType) normalize.typeSymbol else sym
@@ -1478,25 +1489,31 @@ A type's typeSymbol should never be inspected directly.
private def higherKindedArgs = typeParams map (_.typeConstructor) //@M must be .typeConstructor
private def argsMaybeDummy = if (isHigherKinded) higherKindedArgs else args
- override def normalize =
- if (sym.isAliasType) { // beta-reduce
- if (sym.info.typeParams.length == args.length || !isHigherKinded) {
-/* !isHigherKinded && sym.info.typeParams.length != args.length only happens when compiling e.g.,
- `val x: Class' with -Xgenerics, while `type Class = java.lang.Class' had already been compiled without -Xgenerics */
- val xform = transform(sym.info.resultType)
- assert(xform ne this, this)
- xform.normalize // cycles have been checked in typeRef
- } else PolyType(typeParams, transform(sym.info.resultType).normalize) // eta-expand
- // @M TODO: should not use PolyType, as that's the type of a polymorphic value -- we really want a type *function*
- } else if (isHigherKinded) {
- // @M TODO: should not use PolyType, as that's the type of a polymorphic value -- we really want a type *function*
- // @M: initialize needed (see test/files/pos/ticket0137.scala)
- PolyType(typeParams, typeRef(pre, sym.initialize, higherKindedArgs))
- } else if (sym.isRefinementClass) {
- sym.info.normalize // @MO to AM: OK?
- } else {
- super.normalize
+ private var normalized: Type = null
+
+ override def normalize: Type = {
+ if (normalized == null) {
+ normalized = if (sym.isAliasType) { // beta-reduce
+ if (sym.info.typeParams.length == args.length || !isHigherKinded) {
+ /* !isHigherKinded && sym.info.typeParams.length != args.length only happens when compiling e.g.,
+ `val x: Class' with -Xgenerics, while `type Class = java.lang.Class' had already been compiled without -Xgenerics */
+ val xform = transform(sym.info.resultType)
+ assert(xform ne this, this)
+ xform.normalize // cycles have been checked in typeRef
+ } else PolyType(typeParams, transform(sym.info.resultType).normalize) // eta-expand
+ // @M TODO: should not use PolyType, as that's the type of a polymorphic value -- we really want a type *function*
+ } else if (isHigherKinded) {
+ // @M TODO: should not use PolyType, as that's the type of a polymorphic value -- we really want a type *function*
+ // @M: initialize needed (see test/files/pos/ticket0137.scala)
+ PolyType(typeParams, typeRef(pre, sym.initialize, higherKindedArgs))
+ } else if (sym.isRefinementClass) {
+ sym.info.normalize // @MO to AM: OK?
+ } else {
+ super.normalize
+ }
}
+ normalized
+ }
override def decls: Scope = {
sym.info match {
@@ -2070,14 +2087,17 @@ A type's typeSymbol should never be inspected directly.
def transform(tp: Type): Type =
tp.resultType.asSeenFrom(pre, sym1.owner).instantiateTypeParams(sym1.typeParams, args)
if (sym1.isAliasType && sym1.info.typeParams.length == args.length) {
+ if (!sym1.lockOK)
+ throw new TypeError("illegal cyclic reference involving " + sym1)
// note: we require that object is initialized,
// that's why we use info.typeParams instead of typeParams.
+/*
sym1.lock {
throw new TypeError("illegal cyclic reference involving " + sym1)
}
transform(sym1.info) // check there are no cycles
sym1.unlock()
-
+*/
rawTypeRef(pre, sym1, args) // don't expand type alias (cycles checked above)
} else {
val pre1 = removeSuper(pre, sym1)
@@ -2718,7 +2738,9 @@ A type's typeSymbol should never be inspected directly.
} else {
pre1
}
- } else toPrefix(base(pre, clazz).prefix, clazz.owner);
+ } else {
+ toPrefix(base(pre, clazz).prefix, clazz.owner);
+ }
toPrefix(pre, clazz)
case SingleType(pre, sym) =>
if (sym.isPackageClass) tp // short path
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index cd51fbce5f..e43ddddea9 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -547,9 +547,46 @@ trait Namers { self: Analyzer =>
self.symbol = context.scope enter self.symbol
}
}
+
+ /* experimental code for allowiong early types as type parameters
+ val earlyTypes = templ.body filter (treeInfo.isEarlyTypeDef)
+
+ val parentTyper =
+ if (earlyTypes.isEmpty) typer
+ else {
+ val earlyContext = context.outer.makeNewScope(context.tree, context.outer.owner.newLocalDummy(templ.pos))(InnerScopeKind)
+ newNamer(earlyContext).enterSyms(earlyTypes)
+ newTyper(earlyContext).typedStats(earlyTypes, context.owner)
+
+ val parentContext = context.makeNewScope(context.tree, context.owner)(InnerScopeKind)
+ for (etdef <- earlyTypes) parentContext.scope enter etdef.symbol
+ newTyper(parentContext)
+ }
+ var parents = parentTyper.parentTypes(templ) map checkParent
+ if (!earlyTypes.isEmpty) {
+ val earlyMap = new EarlyMap(context.owner)
+ for (etdef <- earlyTypes) {
+ val esym = etdef.symbol
+ esym.owner = context.owner
+ esym.asInstanceOf[TypeSymbol].refreshType()
+ esym setInfo earlyMap(esym.info)
+ }
+
+/*
+ println("earlies: "+(earlyTypes map (_.symbol)))
+ println("earlies: "+(earlyTypes map (_.symbol.tpe)))
+ println("earlies: "+(earlyTypes map (_.symbol.info)))
+ println("parents: "+parents)
+ println(templ)
+
+*/
+
+ }
+*/
var parents = typer.parentTypes(templ) map checkParent
enterSelf(templ.self)
val decls = newClassScope(clazz)
+// for (etdef <- earlyTypes) decls enter etdef.symbol
val templateNamer = newNamer(context.make(templ, clazz, decls))
.enterSyms(templ.body)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala.1 b/src/compiler/scala/tools/nsc/typechecker/Namers.scala.1
new file mode 100755
index 0000000000..910418ba65
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala.1
@@ -0,0 +1,1047 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2009 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id: Namers.scala 17117 2009-02-16 14:56:54Z odersky $
+
+package scala.tools.nsc.typechecker
+
+import scala.collection.mutable.HashMap
+import scala.tools.nsc.util.Position
+import symtab.Flags
+import symtab.Flags._
+
+/** This trait declares methods to create symbols and to enter them into scopes.
+ *
+ * @author Martin Odersky
+ * @version 1.0
+ */
+trait Namers { self: Analyzer =>
+ import global._
+ import definitions._
+ import posAssigner.atPos
+
+ /** Convert to corresponding type parameters all skolems of method parameters
+ * which appear in `tparams`.
+ */
+ class DeSkolemizeMap(tparams: List[Symbol]) extends TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case TypeRef(pre, sym, args)
+ if (sym.isTypeSkolem && (tparams contains sym.deSkolemize)) =>
+// println("DESKOLEMIZING "+sym+" in "+sym.owner)
+ mapOver(rawTypeRef(NoPrefix, sym.deSkolemize, args))
+/*
+ case PolyType(tparams1, restpe) =>
+ new DeSkolemizeMap(tparams1 ::: tparams).mapOver(tp)
+ case ClassInfoType(parents, decls, clazz) =>
+ val parents1 = List.mapConserve(parents)(this)
+ if (parents1 eq parents) tp else ClassInfoType(parents1, decls, clazz)
+*/
+ case _ =>
+ mapOver(tp)
+ }
+ }
+
+ private class NormalNamer(context : Context) extends Namer(context)
+ def newNamer(context : Context) : Namer = new NormalNamer(context)
+
+ private[typechecker] val caseClassOfModuleClass = new HashMap[Symbol, ClassDef]
+
+ def resetNamer() {
+ caseClassOfModuleClass.clear
+ }
+
+ abstract class Namer(val context: Context) {
+
+ val typer = newTyper(context)
+
+ def setPrivateWithin[Sym <: Symbol](tree: Tree, sym: Sym, mods: Modifiers): Sym = {
+ if (!mods.privateWithin.isEmpty)
+ sym.privateWithin = typer.qualifyingClassContext(tree, mods.privateWithin, true).owner
+ sym
+ }
+
+ def inConstructorFlag: Long =
+ if (context.owner.isConstructor && !context.inConstructorSuffix || context.owner.isEarly) INCONSTRUCTOR
+ else 0l
+
+ def moduleClassFlags(moduleFlags: Long) =
+ (moduleFlags & ModuleToClassFlags) | FINAL | inConstructorFlag
+
+ def updatePosFlags(sym: Symbol, pos: Position, flags: Long): Symbol = {
+ if (settings.debug.value) log("overwriting " + sym)
+ val lockedFlag = sym.flags & LOCKED
+ sym.reset(NoType)
+ sym setPos pos
+ sym.flags = flags | lockedFlag
+ if (sym.isModule && sym.moduleClass != NoSymbol)
+ updatePosFlags(sym.moduleClass, pos, moduleClassFlags(flags))
+ if (sym.owner.isPackageClass &&
+ (sym.linkedSym.rawInfo.isInstanceOf[loaders.SymbolLoader] ||
+ sym.linkedSym.rawInfo.isComplete && runId(sym.validTo) != currentRunId))
+ // pre-set linked symbol to NoType, in case it is not loaded together with this symbol.
+ sym.linkedSym.setInfo(NoType)
+ sym
+ }
+
+ private def isTemplateContext(context: Context): Boolean = context.tree match {
+ case Template(_, _, _) => true
+ case Import(_, _) => isTemplateContext(context.outer)
+ case _ => false
+ }
+
+ private var innerNamerCache: Namer = null
+ protected def makeConstructorScope(classContext : Context) : Context = {
+ val outerContext = classContext.outer.outer
+ outerContext.makeNewScope(outerContext.tree, outerContext.owner)(Constructor1ScopeKind)
+ }
+
+ def namerOf(sym: Symbol): Namer = {
+
+ def innerNamer: Namer = {
+ if (innerNamerCache eq null)
+ innerNamerCache =
+ if (!isTemplateContext(context)) this
+ else newNamer(context.make(context.tree, context.owner, scopeFor(context.tree, InnerScopeKind)))
+ innerNamerCache
+ }
+
+ def primaryConstructorParamNamer: Namer = { //todo: can we merge this with SCCmode?
+ val classContext = context.enclClass
+ val paramContext = makeConstructorScope(classContext)
+ val unsafeTypeParams = context.owner.unsafeTypeParams
+ unsafeTypeParams foreach(sym => paramContext.scope.enter(sym))
+ newNamer(paramContext)
+ }
+ if (sym.isTerm) {
+ if (sym.hasFlag(PARAM) && sym.owner.isPrimaryConstructor)
+ primaryConstructorParamNamer
+ else if (sym.hasFlag(PARAMACCESSOR) && !inIDE)
+ primaryConstructorParamNamer
+ else innerNamer
+ } else innerNamer
+ }
+
+ protected def conflict(newS : Symbol, oldS : Symbol) : Boolean = {
+ (!oldS.isSourceMethod ||
+ nme.isSetterName(newS.name) ||
+ newS.owner.isPackageClass) &&
+ !((newS.owner.isTypeParameter || newS.owner.isAbstractType) &&
+ newS.name.length==1 && newS.name(0)=='_') //@M: allow repeated use of `_' for higher-order type params
+ }
+
+ // IDE hook
+ protected def setInfo[Sym <: Symbol](sym : Sym)(tpe : LazyType) : Sym = sym.setInfo(tpe)
+
+ private def doubleDefError(pos: Position, sym: Symbol) {
+ context.error(pos,
+ sym.name.toString() + " is already defined as " +
+ (if (sym.hasFlag(SYNTHETIC))
+ "(compiler-generated) "+ (if (sym.isModule) "case class companion " else "")
+ else "") +
+ (if (sym.hasFlag(CASE)) "case class " + sym.name else sym.toString()))
+ }
+
+ private def inCurrentScope(m: Symbol): Boolean = {
+ if (context.owner.isClass) context.owner == m.owner
+ else m.owner.isClass && context.scope == m.owner.info.decls
+ }
+
+ def enterInScope(sym: Symbol): Symbol = enterInScope(sym, context.scope)
+
+ def enterInScope(sym: Symbol, scope: Scope): Symbol = {
+ // allow for overloaded methods
+ if (!(sym.isSourceMethod && sym.owner.isClass && !sym.owner.isPackageClass)) {
+ var prev = scope.lookupEntryWithContext(sym.name)(context.owner);
+ if ((prev ne null) && inIDE) {
+ var guess = prev
+ while ((guess ne null) && (guess.sym ne sym)) guess = scope.lookupNextEntry(guess)
+ if (guess != null) prev = guess
+ while (prev != null && (!prev.sym.hasRawInfo || !prev.sym.rawInfo.isComplete ||
+ (prev.sym.sourceFile == null && sym.getClass == prev.sym.getClass))) {
+ if (!prev.sym.hasRawInfo || prev.sym.rawInfo.isComplete) {
+ Console.println("DITCHING: " + prev.sym)
+ }
+ scope unlink prev.sym
+ prev = scope.lookupNextEntry(prev)
+ }
+ val sym0 = scope enter sym
+ if (sym0 ne sym) {
+ Console.println("WEIRD: " + sym0 + " vs. " + sym + " " + sym0.id + " " + sym.id + " " + sym.sourceFile + " " + sym0.sourceFile)
+ }
+ if (prev != null && (sym0 ne prev.sym) && conflict(sym0,prev.sym)) {
+ doubleDefError(sym0.pos, prev.sym)
+ }
+ sym0
+ } else if ((prev ne null) && prev.owner == scope && conflict(sym, prev.sym)) {
+ doubleDefError(sym.pos, prev.sym)
+ sym setInfo ErrorType // don't do this in IDE for stability
+ scope unlink prev.sym // let them co-exist...
+ scope enter sym
+ } else scope enter sym
+ } else scope enter sym
+ }
+
+ def enterPackageSymbol(pos: Position, name: Name): Symbol = {
+ val (cscope, cowner) =
+ if (context.owner == EmptyPackageClass) (RootClass.info.decls, RootClass)
+ else (context.scope, context.owner)
+ val p: Symbol = cscope.lookupWithContext(name)(context.owner)
+ if (p.isPackage && cscope == p.owner.info.decls) {
+ p
+ } else {
+ val pkg = cowner.newPackage(pos, name)
+ // IDE: newScope should be ok because packages are never destroyed.
+ if (inIDE) assert(!pkg.moduleClass.hasRawInfo || !pkg.moduleClass.rawInfo.isComplete)
+ pkg.moduleClass.setInfo(new PackageClassInfoType(newScope, pkg.moduleClass, null))
+ pkg.setInfo(pkg.moduleClass.tpe)
+ enterInScope(pkg, cscope)
+ }
+ }
+
+ def enterClassSymbol(tree : ClassDef): Symbol = {
+ var c: Symbol = context.scope.lookupWithContext(tree.name)(context.owner);
+ if (!inIDE && c.isType && c.owner.isPackageClass && context.scope == c.owner.info.decls && !currentRun.compiles(c)) {
+ updatePosFlags(c, tree.pos, tree.mods.flags)
+ setPrivateWithin(tree, c, tree.mods)
+ } else {
+ var sym = context.owner.newClass(tree.pos, tree.name)
+ sym = sym.setFlag(tree.mods.flags | inConstructorFlag)
+ sym = setPrivateWithin(tree, sym, tree.mods)
+ c = enterInScope(sym)
+ }
+ if (c.owner.isPackageClass) {
+ val file = context.unit.source.file
+ val clazz = c.asInstanceOf[ClassSymbol]
+ if (settings.debug.value && (clazz.sourceFile ne null) && !clazz.sourceFile.equals(file)) {
+ Console.err.println("SOURCE MISMATCH: " + clazz.sourceFile + " vs. " + file + " SYM=" + c);
+ }
+ clazz.sourceFile = file
+ if (clazz.sourceFile ne null) {
+ assert(inIDE || !currentRun.compiles(clazz) || clazz.sourceFile == currentRun.symSource(c));
+ currentRun.symSource(c) = clazz.sourceFile
+ }
+ }
+ assert(c.name.toString.indexOf('(') == -1)
+ c
+ }
+
+ /** Enter a module symbol. The tree parameter can be either a module definition
+ * or a class definition */
+ def enterModuleSymbol(tree : ModuleDef): Symbol = {
+ // .pos, mods.flags | MODULE | FINAL, name
+ var m: Symbol = context.scope.lookupWithContext(tree.name)(context.owner)
+ val moduleFlags = tree.mods.flags | MODULE | FINAL
+ if (m.isModule && !m.isPackage && inCurrentScope(m) &&
+ ((!inIDE && !currentRun.compiles(m)) || (m hasFlag SYNTHETIC))) {
+ updatePosFlags(m, tree.pos, moduleFlags)
+ setPrivateWithin(tree, m, tree.mods)
+ context.unit.synthetics -= m
+ } else {
+ m = context.owner.newModule(tree.pos, tree.name)
+ m.setFlag(moduleFlags)
+ m = setPrivateWithin(tree, m, tree.mods)
+ m = enterInScope(m)
+
+ m.moduleClass.setFlag(moduleClassFlags(moduleFlags))
+ setPrivateWithin(tree, m.moduleClass, tree.mods)
+ }
+ if (m.owner.isPackageClass) {
+ m.moduleClass.sourceFile = context.unit.source.file
+ currentRun.symSource(m) = m.moduleClass.sourceFile
+ }
+ m
+ }
+
+ def enterSyms(trees: List[Tree]): Namer = {
+ var namer : Namer = this
+ for (tree <- trees) {
+ val txt = namer.enterSym(tree)
+ if (!(txt eq namer.context)) namer = newNamer(txt)
+ }
+ namer
+ }
+
+ def newTypeSkolems(tparams: List[Symbol]): List[Symbol] = {
+ val tskolems = tparams map (_.newTypeSkolem)
+ val ltp = new LazyType {
+ override def complete(sym: Symbol) {
+ sym setInfo sym.deSkolemize.info.substSym(tparams, tskolems) //@M the info of a skolem is the skolemized info of the actual type parameter of the skolem
+ }
+ }
+ tskolems foreach (_.setInfo(ltp))
+ tskolems
+ }
+
+ /** Replace type parameters with their TypeSkolems, which can later be deskolemized to the original type param
+ * (a skolem is a representation of a bound variable when viewed inside its scope)
+ */
+ def skolemize(tparams: List[TypeDef]) {
+ val tskolems = newTypeSkolems(tparams map (_.symbol))
+ for ((tparam, tskolem) <- tparams zip tskolems) tparam.symbol = tskolem
+ }
+
+ def applicableTypeParams(owner: Symbol): List[Symbol] =
+ if (inIDE && (owner eq NoSymbol)) List()
+ else if (owner.isTerm || owner.isPackageClass) List()
+ else applicableTypeParams(owner.owner) ::: owner.typeParams
+
+ def enterSym(tree: Tree): Context = try {
+
+ def finishWith(tparams: List[TypeDef]) {
+ val sym = tree.symbol
+ if (settings.debug.value) log("entered " + sym + " in " + context.owner + ", scope-id = " + context.scope.hashCode());
+ var ltype = namerOf(sym).typeCompleter(tree)
+ if (!tparams.isEmpty) {
+ //@M! TypeDef's type params are handled differently
+ //@M e.g., in [A[x <: B], B], A and B are entered first as both are in scope in the definition of x
+ //@M x is only in scope in `A[x <: B]'
+ if(!sym.isAbstractType) //@M TODO: change to isTypeMember ?
+ newNamer(context.makeNewScope(tree, sym)(FinishWithScopeKind)).enterSyms(tparams)
+ ltype = new PolyTypeCompleter(tparams, ltype, tree, sym, context) //@M
+ if (sym.isTerm) skolemize(tparams)
+ }
+ setInfo(sym)(ltype)
+ }
+ def finish = finishWith(List())
+
+ if (tree.symbol == NoSymbol) {
+ val owner = context.owner
+ tree match {
+ case PackageDef(name, stats) =>
+ tree.symbol = enterPackageSymbol(tree.pos, name)
+ val namer = newNamer(
+ context.make(tree, tree.symbol.moduleClass, tree.symbol.info.decls))
+ namer.enterSyms(stats)
+ case tree @ ClassDef(mods, name, tparams, impl) =>
+ tree.symbol = enterClassSymbol(tree)
+ finishWith(tparams)
+ if ((mods.flags & CASE) != 0) {
+ var m: Symbol = context.scope.lookupWithContext(tree.name.toTermName)(context.owner).filter(! _.isSourceMethod)
+ if (!(m.isModule && inCurrentScope(m) && (inIDE || currentRun.compiles(m)))) {
+ m = enterSyntheticSym(caseModuleDef(tree))
+ }
+ caseClassOfModuleClass(m.moduleClass) = tree
+ }
+ case tree @ ModuleDef(mods, name, _) =>
+ tree.symbol = enterModuleSymbol(tree)
+ tree.symbol.moduleClass.setInfo(namerOf(tree.symbol).moduleClassTypeCompleter((tree)))
+ finish
+
+ case ValDef(mods, name, tp, rhs) =>
+ if ((!context.owner.isClass ||
+ (mods.flags & (PRIVATE | LOCAL)) == (PRIVATE | LOCAL) ||
+ name.endsWith(nme.OUTER, nme.OUTER.length) ||
+ context.unit.isJava) &&
+ (mods.flags & LAZY) == 0) {
+ tree.symbol = enterInScope(owner.newValue(tree.pos, name)
+ .setFlag(mods.flags))
+ finish
+ } else {
+ // add getter and possibly also setter
+ val accflags: Long = ACCESSOR |
+ (if ((mods.flags & MUTABLE) != 0) mods.flags & ~MUTABLE & ~PRESUPER
+ else mods.flags & ~PRESUPER | STABLE)
+ if (nme.isSetterName(name))
+ context.error(tree.pos, "Names of vals or vars may not end in `_='")
+ var getter = owner.newMethod(tree.pos, name).setFlag(accflags)
+ setPrivateWithin(tree, getter, mods)
+ getter = enterInScope(getter).asInstanceOf[TermSymbol]
+ setInfo(getter)(namerOf(getter).getterTypeCompleter(tree))
+ if ((mods.flags & MUTABLE) != 0) {
+ var setter = owner.newMethod(tree.pos, nme.getterToSetter(name))
+ .setFlag(accflags & ~STABLE & ~CASEACCESSOR)
+ setPrivateWithin(tree, setter, mods)
+ setter = enterInScope(setter).asInstanceOf[TermSymbol]
+ setInfo(setter)(namerOf(setter).setterTypeCompleter(tree))
+ }
+ tree.symbol =
+ if ((mods.flags & DEFERRED) == 0) {
+ var vsym =
+ if (!context.owner.isClass) {
+ assert((mods.flags & LAZY) != 0) // if not a field, it has to be a lazy val
+ owner.newValue(tree.pos, name + "$lzy" ).setFlag(mods.flags | MUTABLE)
+ } else {
+ owner.newValue(tree.pos, nme.getterToLocal(name))
+ .setFlag(mods.flags & FieldFlags | PRIVATE | LOCAL | (if ((mods.flags & LAZY) != 0) MUTABLE else 0))
+ }
+ vsym = enterInScope(vsym).asInstanceOf[TermSymbol]
+ setInfo(vsym)(namerOf(vsym).typeCompleter(tree))
+ if ((mods.flags & LAZY) != 0)
+ vsym.setLazyAccessor(getter)
+ vsym
+ } else getter
+ }
+ case DefDef(mods, nme.CONSTRUCTOR, tparams, _, _, _) =>
+ var sym = owner.newConstructor(tree.pos).setFlag(mods.flags | owner.getFlag(ConstrFlags))
+ setPrivateWithin(tree, sym, mods)
+ tree.symbol = enterInScope(sym)
+ finishWith(tparams)
+ case DefDef(mods, name, tparams, _, _, _) =>
+ var sym = (owner.newMethod(tree.pos, name)).setFlag(mods.flags)
+ setPrivateWithin(tree, sym, mods)
+ tree.symbol = enterInScope(sym)
+ finishWith(tparams)
+ case TypeDef(mods, name, tparams, _) =>
+ var flags: Long = mods.flags
+ if ((flags & PARAM) != 0) flags |= DEFERRED
+ var sym = new TypeSymbol(owner, tree.pos, name).setFlag(flags)
+ setPrivateWithin(tree, sym, mods)
+ tree.symbol = enterInScope(sym)
+ finishWith(tparams)
+ case DocDef(_, defn) =>
+ enterSym(defn)
+ case imp @ Import(_, _) =>
+ tree.symbol = NoSymbol.newImport(tree.pos)
+ setInfo(tree.symbol)(namerOf(tree.symbol).typeCompleter(tree))
+ return (context.makeNewImport(imp))
+ case _ =>
+ }
+ }
+ this.context
+ } catch {
+ case ex: TypeError =>
+ //Console.println("caught " + ex + " in enterSym")//DEBUG
+ typer.reportTypeError(tree.pos, ex)
+ this.context
+ }
+
+ def enterSyntheticSym(tree: Tree): Symbol = {
+ enterSym(tree)
+ context.unit.synthetics(tree.symbol) = tree
+ tree.symbol
+ }
+
+// --- Lazy Type Assignment --------------------------------------------------
+
+ def typeCompleter(tree: Tree) = mkTypeCompleter(tree) { sym =>
+ if (settings.debug.value) log("defining " + sym + Flags.flagsToString(sym.flags)+sym.locationString)
+ val tp = typeSig(tree)
+ tp match {
+ case TypeBounds(lo, hi) =>
+ // check that lower bound is not an F-bound
+ for (val t <- lo) {
+ t match {
+ case TypeRef(_, sym, _) => sym.initialize
+ case _ =>
+ }
+ }
+ case _ =>
+ }
+ sym.setInfo(tp)
+ if ((sym.isAliasType || sym.isAbstractType) && !(sym hasFlag PARAM) &&
+ !typer.checkNonCyclic(tree.pos, tp))
+ sym.setInfo(ErrorType) // this early test is there to avoid infinite baseTypes when
+ // adding setters and getters --> bug798
+ if (settings.debug.value) log("defined " + sym);
+ validate(sym)
+ }
+
+ def moduleClassTypeCompleter(tree: Tree) = {
+ mkTypeCompleter(tree) { sym =>
+ val moduleSymbol = tree.symbol
+ assert(moduleSymbol.moduleClass == sym)
+ if (inIDE && moduleSymbol.rawInfo.isComplete) {
+ // reset!
+ }
+ moduleSymbol.info // sets moduleClass info as a side effect.
+ //assert(sym.rawInfo.isComplete)
+ }
+ }
+
+ def getterTypeCompleter(tree: Tree) = mkTypeCompleter(tree) { sym =>
+ if (settings.debug.value) log("defining " + sym)
+ sym.setInfo(PolyType(List(), typeSig(tree)))
+ if (settings.debug.value) log("defined " + sym)
+ validate(sym)
+ }
+
+ def setterTypeCompleter(tree: Tree) = mkTypeCompleter(tree) { sym =>
+ if (settings.debug.value) log("defining " + sym);
+ sym.setInfo(MethodType(List(typeSig(tree)), UnitClass.tpe))
+ if (settings.debug.value) log("defined " + sym);
+ validate(sym)
+ }
+
+ def selfTypeCompleter(tree: Tree) = mkTypeCompleter(tree) { sym =>
+ var selftpe = typer.typedType(tree).tpe
+ if (!(selftpe.typeSymbol isNonBottomSubClass sym.owner))
+ selftpe = intersectionType(List(sym.owner.tpe, selftpe))
+// println("completing self of "+sym.owner+": "+selftpe)
+ sym.setInfo(selftpe)
+ }
+
+ private def widenIfNotFinal(sym: Symbol, tpe: Type, pt: Type): Type = {
+ val getter =
+ if (sym.isValue && sym.owner.isClass && (sym hasFlag PRIVATE))
+ sym.getter(sym.owner)
+ else sym
+ def isHidden(tp: Type): Boolean = tp match {
+ case SingleType(pre, sym) =>
+ (sym isLessAccessibleThan getter) || isHidden(pre)
+ case ThisType(sym) =>
+ sym isLessAccessibleThan getter
+ case p: SimpleTypeProxy =>
+ isHidden(p.underlying)
+ case _ =>
+ false
+ }
+ val tpe1 = tpe.deconst
+ val tpe2 = tpe1.widen
+ if ((sym.isVariable || sym.isMethod && !(sym hasFlag ACCESSOR)))
+ if (tpe2 <:< pt) tpe2 else tpe1
+ else if (isHidden(tpe)) tpe2
+ else if (!(sym hasFlag FINAL)) tpe1
+ else tpe
+ }
+
+ def enterValueParams(owner: Symbol, vparamss: List[List[ValDef]]): List[List[Symbol]] = {
+ def enterValueParam(param: ValDef): Symbol = {
+ if (inIDE) param.symbol = {
+ var sym = owner.newValueParameter(param.pos, param.name).
+ setFlag(param.mods.flags & (BYNAMEPARAM | IMPLICIT))
+ setPrivateWithin(param, sym, param.mods)
+ sym = enterInScope(sym).asInstanceOf[TermSymbol]
+ if (!sym.hasRawInfo || sym.rawInfo.isComplete)
+ setInfo(sym)(typeCompleter(param))
+ sym
+ } else param.symbol = setInfo(
+ enterInScope{
+ val sym = owner.newValueParameter(param.pos, param.name).
+ setFlag(param.mods.flags & (BYNAMEPARAM | IMPLICIT))
+ setPrivateWithin(param, sym, param.mods)
+ })(typeCompleter(param))
+ param.symbol
+ }
+ vparamss.map(_.map(enterValueParam))
+ }
+
+ private def templateSig(templ: Template): Type = {
+ val clazz = context.owner
+ def checkParent(tpt: Tree): Type = {
+ val tp = tpt.tpe
+ if (tp.typeSymbol == context.owner) {
+ context.error(tpt.pos, ""+tp.typeSymbol+" inherits itself")
+ AnyRefClass.tpe
+ } else if (tp.isError) {
+ AnyRefClass.tpe
+ } else {
+ tp
+ }
+ }
+ def enterSelf(self: ValDef) {
+ if (!self.tpt.isEmpty) {
+ clazz.typeOfThis = selfTypeCompleter(self.tpt)
+ self.symbol = clazz.thisSym.setPos(self.pos)
+ } else {
+ self.tpt.tpe = NoType
+ if (self.name != nme.WILDCARD) {
+ clazz.typeOfThis = clazz.tpe
+ self.symbol = clazz.thisSym
+ } else if (self ne emptyValDef) {
+ self.symbol = clazz.newThisSym(self.pos) setInfo clazz.tpe
+ }
+ }
+ if (self.name != nme.WILDCARD) {
+ self.symbol.name = self.name
+ self.symbol = context.scope enter self.symbol
+ }
+ }
+ var templateNamer = newNamer(context.make(templ, clazz, decls))
+ templateNamer = templateNamer.enterSyms(template.body filter treeInfo.isEarlyType)
+ var parents = typer.parentTypes(templ) map checkParent
+ enterSelf(templ.self)
+ val decls = newClassScope(clazz)
+ templateNamer = templateNamer.enterSyms(templ.body)
+
+ /* add overridden virtuals to parents
+ val overridden = clazz.overriddenVirtuals
+ if (!overridden.isEmpty)
+ parents = parents ::: ( overridden map (
+ sym => TypeRef(clazz.owner.thisType, sym, clazz.typeParams map (_.tpe))))
+ println("Parents of "+clazz+":"+parents)
+
+ // check that virtual classses are only defined as members of templates
+ if (clazz.isVirtualClass && !clazz.owner.isClass)
+ context.error(
+ clazz.pos,
+ "virtual traits and their subclasses must be defined as members of some other class")
+
+ // make subclasses of virtual classes virtual as well; check that
+ // they are defined in same scope.
+ val virtualParents = parents map (_.typeSymbol) filter (_.isVirtualClass)
+ virtualParents find {
+ vp => !(clazz.owner.isClass && (clazz.owner isSubClass vp.owner))
+ } match {
+ case Some(vp) =>
+ context.error(
+ clazz.pos,
+ "subclass of virtual "+vp+
+ " needs to be defined at same level,\nas member of "+vp.owner)
+ case None =>
+ if (!virtualParents.isEmpty) clazz setFlag DEFERRED // make it virtual
+ }
+ */
+
+ // add apply and unapply methods to companion objects of case classes,
+ // unless they exist already
+ Namers.this.caseClassOfModuleClass get clazz match {
+ case Some(cdef) =>
+ val go = if (inIDE) { // garbage collect in the presentaiton compiler.
+ assert(cdef.symbol != null && cdef.symbol != NoSymbol)
+ if (!cdef.symbol.isClass || !cdef.symbol.hasFlag(CASE) || cdef.symbol.rawInfo == NoType) false
+ else true
+ } else true
+ if (go)
+ addApplyUnapply(cdef, templateNamer)
+ if (!go || !inIDE) caseClassOfModuleClass -= clazz
+ if (!go) {
+ val rem = clazz.linkedModuleOfClass
+ assert(rem != NoSymbol)
+ }
+ case None =>
+ }
+ ClassInfoType(parents, decls, clazz)
+ }
+
+ private def classSig(tparams: List[TypeDef], impl: Template): Type =
+ polyType(typer.reenterTypeParams(tparams), templateSig(impl))
+
+ private def methodSig(tparams: List[TypeDef], vparamss: List[List[ValDef]],
+ tpt: Tree, rhs: Tree): Type = {
+ val meth = context.owner
+
+ val tparamSyms = typer.reenterTypeParams(tparams)
+ var vparamSymss =
+ if (inIDE && meth.isPrimaryConstructor) {
+ // @S: because they have already been entered this way....
+
+ enterValueParams(meth.owner.owner, vparamss)
+ } else {
+ enterValueParams(meth, vparamss)
+ }
+ if (tpt.isEmpty && meth.name == nme.CONSTRUCTOR) {
+ tpt.tpe = context.enclClass.owner.tpe
+ tpt setPos meth.pos
+ }
+
+ if (onlyPresentation && methodArgumentNames != null)
+ methodArgumentNames(meth) = vparamss.map(_.map(_.symbol));
+
+ def convertToDeBruijn(vparams: List[Symbol], level: Int): TypeMap = new TypeMap {
+ def debruijnFor(param: Symbol) =
+ DeBruijnIndex(level, vparams indexOf param)
+ def apply(tp: Type) = {
+ tp match {
+ case SingleType(_, sym) =>
+ if (settings.Xexperimental.value && sym.owner == meth && (vparams contains sym)) {
+/*
+ if (sym hasFlag IMPLICIT) {
+ context.error(sym.pos, "illegal type dependence on implicit parameter")
+ ErrorType
+ } else
+*/
+ debruijnFor(sym)
+ } else tp
+ case MethodType(formals, restpe) =>
+ val formals1 = List.mapConserve(formals)(this)
+ val restpe1 = convertToDeBruijn(vparams, level + 1)(restpe)
+ if ((formals1 eq formals) && (restpe1 eq restpe)) tp
+ else copyMethodType(tp, formals1, restpe1)
+ case _ =>
+ mapOver(tp)
+ }
+ }
+
+ object treeTrans extends TypeMapTransformer {
+ override def transform(tree: Tree): Tree =
+ tree match {
+ case Ident(name) if (vparams contains tree.symbol) =>
+ val dtpe = debruijnFor(tree.symbol)
+ val dsym =
+ newLocalDummy(context.owner, tree.symbol.pos)
+ .newValue(tree.symbol.pos, name)
+
+ dsym.setFlag(PARAM)
+ dsym.setInfo(dtpe)
+ Ident(name).setSymbol(dsym).copyAttrs(tree).setType(dtpe)
+ case tree => super.transform(tree)
+ }
+ }
+
+ override def mapOver(arg: Tree) = Some(treeTrans.transform(arg))
+ }
+
+ val checkDependencies: TypeTraverser = new TypeTraverser {
+ def traverse(tp: Type) = {
+ tp match {
+ case SingleType(_, sym) =>
+ if (sym.owner == meth && (vparamSymss exists (_ contains sym)))
+ context.error(
+ sym.pos,
+ "illegal dependent method type"+
+ (if (settings.Xexperimental.value)
+ ": parameter appears in the type of another parameter in the same section or an earlier one"
+ else ""))
+ case _ =>
+ mapOver(tp)
+ }
+ this
+ }
+ }
+
+ def makeMethodType(vparams: List[Symbol], restpe: Type) = {
+ val formals = vparams map (vparam =>
+ if (meth hasFlag JAVA) objToAny(vparam.tpe) else vparam.tpe)
+ val restpe1 = convertToDeBruijn(vparams, 1)(restpe)
+ if (!vparams.isEmpty && vparams.head.hasFlag(IMPLICIT))
+ ImplicitMethodType(formals, restpe1)
+ else if (meth hasFlag JAVA) JavaMethodType(formals, restpe1)
+ else MethodType(formals, restpe1)
+ }
+
+ def thisMethodType(restpe: Type) =
+ polyType(
+ tparamSyms,
+ if (vparamSymss.isEmpty) PolyType(List(), restpe)
+ else checkDependencies((vparamSymss :\ restpe) (makeMethodType)))
+
+ var resultPt = if (tpt.isEmpty) WildcardType else typer.typedType(tpt).tpe
+ val site = meth.owner.thisType
+
+ def overriddenSymbol = intersectionType(meth.owner.info.parents).member(meth.name).filter(sym =>
+ sym != NoSymbol && (site.memberType(sym) matches thisMethodType(resultPt)))
+
+ // fill in result type and parameter types from overridden symbol if there is a unique one.
+ if (meth.owner.isClass && (tpt.isEmpty || vparamss.exists(_.exists(_.tpt.isEmpty)))) {
+ // try to complete from matching definition in base type
+ for (vparams <- vparamss; vparam <- vparams)
+ if (vparam.tpt.isEmpty) vparam.symbol setInfo WildcardType
+ val overridden = overriddenSymbol
+ if (overridden != NoSymbol && !(overridden hasFlag OVERLOADED)) {
+ resultPt = site.memberType(overridden) match {
+ case PolyType(tparams, rt) => rt.substSym(tparams, tparamSyms)
+ case mt => mt
+ }
+
+ for (vparams <- vparamss) {
+ var pfs = resultPt.paramTypes
+ for (vparam <- vparams) {
+ if (vparam.tpt.isEmpty) {
+ vparam.tpt.tpe = pfs.head
+ vparam.tpt setPos vparam.pos
+ vparam.symbol setInfo pfs.head
+ }
+ pfs = pfs.tail
+ }
+ resultPt = resultPt.resultType
+ }
+ resultPt match {
+ case PolyType(List(), rtpe) => resultPt = rtpe
+ case MethodType(List(), rtpe) => resultPt = rtpe
+ case _ =>
+ }
+ if (tpt.isEmpty) {
+ // provisionally assign `meth' a method type with inherited result type
+ // that way, we can leave out the result type even if method is recursive.
+ meth setInfo thisMethodType(resultPt)
+ }
+ }
+ }
+ // Add a () parameter section if this overrides dome method with () parameters.
+ if (meth.owner.isClass && vparamss.isEmpty && overriddenSymbol.alternatives.exists(
+ _.info.isInstanceOf[MethodType])) {
+ vparamSymss = List(List())
+ }
+ for (vparams <- vparamss; vparam <- vparams if vparam.tpt.isEmpty) {
+ context.error(vparam.pos, "missing parameter type")
+ vparam.tpt.tpe = ErrorType
+ }
+
+ thisMethodType(
+ if (tpt.isEmpty) {
+ val pt = resultPt.substSym(tparamSyms, tparams map (_.symbol))
+ tpt.tpe = widenIfNotFinal(meth, typer.computeType(rhs, pt), pt)
+ tpt setPos meth.pos
+ tpt.tpe
+ } else typer.typedType(tpt).tpe)
+ }
+
+ //@M! an abstract type definition (abstract type member/type parameter) may take type parameters, which are in scope in its bounds
+ private def typeDefSig(tpsym: Symbol, tparams: List[TypeDef], rhs: Tree) = {
+ val tparamSyms = typer.reenterTypeParams(tparams) //@M make tparams available in scope (just for this abstypedef)
+ val tp = typer.typedType(rhs).tpe match {
+ case TypeBounds(lt, rt) if (lt.isError || rt.isError) =>
+ TypeBounds(NothingClass.tpe, AnyClass.tpe)
+ case tp @ TypeBounds(lt, rt) if (tpsym hasFlag JAVA) =>
+ TypeBounds(lt, objToAny(rt))
+ case tp =>
+ tp
+ }
+
+ def verifyOverriding(other: Symbol): Boolean = {
+ if(other.unsafeTypeParams.length != tparamSyms.length) {
+ context.error(tpsym.pos,
+ "The kind of "+tpsym.keyString+" "+tpsym.varianceString + tpsym.nameString+
+ " does not conform to the expected kind of " + other.defString + other.locationString + ".")
+ false
+ } else true
+ }
+
+ // @M: make sure overriding in refinements respects rudimentary kinding
+ // have to do this early, as otherwise we might get crashes: (see neg/bug1275.scala)
+ // suppose some parameterized type member is overridden by a type member w/o params,
+ // then appliedType will be called on a type that does not expect type args --> crash
+ if (tpsym.owner.isRefinementClass && // only needed in refinements
+ !tpsym.allOverriddenSymbols.forall{verifyOverriding(_)})
+ ErrorType
+ else polyType(tparamSyms, tp)
+ }
+
+ /** Given a case class
+ *
+ * case class C[Ts] (ps: Us)
+ *
+ * Add the following methods to toScope:
+ *
+ * 1. if case class is not abstract, add
+ *
+ * <synthetic> <case> def apply[Ts](ps: Us): C[Ts] = new C[Ts](ps)
+ *
+ * 2. add a method
+ *
+ * <synthetic> <case> def unapply[Ts](x: C[Ts]) = <ret-val>
+ *
+ * where <ret-val> is the caseClassUnapplyReturnValue of class C (see UnApplies.scala)
+ */
+ def addApplyUnapply(cdef: ClassDef, namer: Namer) {
+ if (!(cdef.symbol hasFlag ABSTRACT))
+ namer.enterSyntheticSym(caseModuleApplyMeth(cdef))
+ namer.enterSyntheticSym(caseModuleUnapplyMeth(cdef))
+ }
+
+ def typeSig(tree: Tree): Type = {
+ val sym: Symbol = tree.symbol
+ tree match {
+ case defn: MemberDef =>
+ val ainfos = for {
+ annot <- defn.mods.annotations
+ val ainfo = typer.typedAnnotation(annot, tree.symbol)
+ if !ainfo.atp.isError && annot != null
+ } yield ainfo
+ if (!ainfos.isEmpty) {
+ val annotated = if (sym.isModule) sym.moduleClass else sym
+ annotated.attributes = ainfos
+ }
+ case _ =>
+ }
+ implicit val scopeKind = TypeSigScopeKind
+ val result =
+ try {
+ tree match {
+ case ClassDef(_, _, tparams, impl) =>
+ newNamer(context.makeNewScope(tree, sym)).classSig(tparams, impl)
+
+ case ModuleDef(_, _, impl) =>
+ val clazz = sym.moduleClass
+ clazz.setInfo(newNamer(context.makeNewScope(tree, clazz)).templateSig(impl))
+ //clazz.typeOfThis = singleType(sym.owner.thisType, sym);
+ clazz.tpe
+
+ case DefDef(_, _, tparams, vparamss, tpt, rhs) =>
+ //val result =
+ newNamer(context.makeNewScope(tree, sym)).methodSig(tparams, vparamss, tpt, rhs)
+
+ case vdef @ ValDef(mods, _, tpt, rhs) =>
+ val typer1 = typer.constrTyperIf(sym.hasFlag(PARAM | PRESUPER) && sym.owner.isConstructor)
+ if (tpt.isEmpty) {
+ if (rhs.isEmpty) {
+ context.error(tpt.pos, "missing parameter type");
+ ErrorType
+ } else {
+ tpt.tpe = widenIfNotFinal(
+ sym,
+ newTyper(typer1.context.make(vdef, sym)).computeType(rhs, WildcardType),
+ WildcardType)
+ tpt setPos vdef.pos
+ tpt.tpe
+ }
+ } else typer1.typedType(tpt).tpe
+
+ case TypeDef(_, _, tparams, rhs) =>
+ newNamer(context.makeNewScope(tree, sym)).typeDefSig(sym, tparams, rhs) //@M!
+
+ case Import(expr, selectors) =>
+ val expr1 = typer.typedQualifier(expr)
+ val base = expr1.tpe
+ typer.checkStable(expr1)
+ if (expr1.symbol.isRootPackage) context.error(tree.pos, "_root_ cannot be imported")
+ def checkNotRedundant(pos: Position, from: Name, to: Name): Boolean = {
+ if (!tree.symbol.hasFlag(SYNTHETIC) &&
+ !((expr1.symbol ne null) && expr1.symbol.isInterpreterWrapper) &&
+ base.member(from) != NoSymbol) {
+ val e = context.scope.lookupEntryWithContext(to)(context.owner)
+ def warnRedundant(sym: Symbol) =
+ context.unit.warning(pos, "imported `"+to+
+ "' is permanently hidden by definition of "+sym+
+ sym.locationString)
+ if ((e ne null) && e.owner == context.scope) {
+ warnRedundant(e.sym); return false
+ } else if (context eq context.enclClass) {
+ val defSym = context.prefix.member(to) filter (
+ sym => sym.exists && context.isAccessible(sym, context.prefix, false))
+ if (defSym != NoSymbol) { warnRedundant(defSym); return false }
+ }
+ }
+ true
+ }
+ def checkSelectors(selectors: List[(Name, Name)]): Unit = selectors match {
+ case (from, to) :: rest =>
+ if (from != nme.WILDCARD && base != ErrorType) {
+ if (base.member(from) == NoSymbol && base.member(from.toTypeName) == NoSymbol)
+ context.error(tree.pos, from.decode + " is not a member of " + expr);
+ if (checkNotRedundant(tree.pos, from, to))
+ checkNotRedundant(tree.pos, from.toTypeName, to.toTypeName)
+ }
+ if (from != nme.WILDCARD && (rest.exists (sel => sel._1 == from)))
+ context.error(tree.pos, from.decode + " is renamed twice");
+ if ((to ne null) && to != nme.WILDCARD && (rest exists (sel => sel._2 == to)))
+ context.error(tree.pos, to.decode + " appears twice as a target of a renaming");
+ checkSelectors(rest)
+ case Nil =>
+ }
+ checkSelectors(selectors)
+ ImportType(expr1)
+ }
+ } catch {
+ case ex: TypeError =>
+ //Console.println("caught " + ex + " in typeSig")//DEBUG
+ typer.reportTypeError(tree.pos, ex)
+ ErrorType
+ }
+ result match {
+ case PolyType(tparams, restpe)
+ if (!tparams.isEmpty && tparams.head.owner.isTerm ||
+ // Adriaan: The added conditon below is quite a hack. It seems that HK type parameters is relying
+ // on a pass that forces all infos in the type to get everything right.
+ // The problem is that the same pass causes cyclic reference errors in
+ // test pos/cyclics.scala. It turned out that deSkolemize is run way more often than necessary,
+ // ruinning it only when needed fixes the cuclic reference errors.
+ // But correcting deSkolemize broke HK types, because we don't do the traversal anymore.
+ // For the moment I made a special hack to do the traversal if we have HK type parameters.
+ // Maybe it's not a hack, then we need to document it better. But ideally, we should find
+ // a way to deal with HK types that's not dependent on accidental side
+ // effects like this.
+ tparams.exists(!_.typeParams.isEmpty)) =>
+ new DeSkolemizeMap(tparams) mapOver result
+ case _ =>
+// println("not skolemizing "+result+" in "+context.owner)
+// new DeSkolemizeMap(List()) mapOver result
+ result
+ }
+ }
+
+ /** Check that symbol's definition is well-formed. This means:
+ * - no conflicting modifiers
+ * - `abstract' modifier only for classes
+ * - `override' modifier never for classes
+ * - `def' modifier never for parameters of case classes
+ * - declarations only in mixins or abstract classes (when not @native)
+ */
+ def validate(sym: Symbol) {
+ def checkNoConflict(flag1: Int, flag2: Int) {
+ if (sym.hasFlag(flag1) && sym.hasFlag(flag2))
+ context.error(sym.pos,
+ if (flag1 == DEFERRED)
+ "abstract member may not have " + Flags.flagsToString(flag2) + " modifier";
+ else
+ "illegal combination of modifiers: " +
+ Flags.flagsToString(flag1) + " and " + Flags.flagsToString(flag2) +
+ " for: " + sym + Flags.flagsToString(sym.rawflags));
+ }
+
+ if (sym.hasFlag(IMPLICIT) && !sym.isTerm)
+ context.error(sym.pos, "`implicit' modifier can be used only for values, variables and methods")
+ if (sym.hasFlag(IMPLICIT) && sym.owner.isPackageClass && !inIDE)
+ context.error(sym.pos, "`implicit' modifier cannot be used for top-level objects")
+ if (sym.hasFlag(ABSTRACT) && !sym.isClass)
+ context.error(sym.pos, "`abstract' modifier can be used only for classes; " +
+ "\nit should be omitted for abstract members")
+ if (sym.hasFlag(OVERRIDE | ABSOVERRIDE) && !sym.hasFlag(TRAIT) && sym.isClass)
+ context.error(sym.pos, "`override' modifier not allowed for classes")
+ if (sym.hasFlag(OVERRIDE | ABSOVERRIDE) && sym.isConstructor)
+ context.error(sym.pos, "`override' modifier not allowed for constructors")
+ if (sym.hasFlag(ABSOVERRIDE) && !sym.owner.isTrait)
+ context.error(sym.pos, "`abstract override' modifier only allowed for members of traits")
+ if (sym.hasFlag(LAZY) && sym.hasFlag(PRESUPER))
+ context.error(sym.pos, "`lazy' definitions may not be initialized early")
+ if (sym.info.typeSymbol == FunctionClass(0) &&
+ sym.isValueParameter && sym.owner.isClass && sym.owner.hasFlag(CASE))
+ context.error(sym.pos, "pass-by-name arguments not allowed for case class parameters");
+ if (sym hasFlag DEFERRED) { // virtual classes count, too
+ if (sym.hasAttribute(definitions.NativeAttr))
+ sym.resetFlag(DEFERRED)
+ else if (!sym.isValueParameter && !sym.isTypeParameterOrSkolem &&
+ !context.tree.isInstanceOf[ExistentialTypeTree] &&
+ (!sym.owner.isClass || sym.owner.isModuleClass || sym.owner.isAnonymousClass)) {
+ context.error(sym.pos,
+ "only classes can have declared but undefined members" + varNotice(sym))
+ sym.resetFlag(DEFERRED)
+ }
+ }
+
+ checkNoConflict(DEFERRED, PRIVATE)
+ checkNoConflict(FINAL, SEALED)
+ checkNoConflict(PRIVATE, PROTECTED)
+ checkNoConflict(PRIVATE, OVERRIDE)
+ /* checkNoConflict(PRIVATE, FINAL) // can't do this because FINAL also means compile-time constant */
+ checkNoConflict(DEFERRED, FINAL)
+ }
+ }
+
+ abstract class TypeCompleter extends LazyType {
+ val tree: Tree
+ }
+
+ def mkTypeCompleter(t: Tree)(c: Symbol => Unit) = new TypeCompleter {
+ val tree = t
+ override def complete(sym: Symbol) = c(sym)
+ }
+
+ /** A class representing a lazy type with known type parameters.
+ */
+ class PolyTypeCompleter(tparams: List[Tree], restp: TypeCompleter, owner: Tree, ownerSym: Symbol, ctx: Context) extends TypeCompleter {
+ override val typeParams: List[Symbol]= tparams map (_.symbol) //@M
+ override val tree = restp.tree
+ override def complete(sym: Symbol) {
+ if(ownerSym.isAbstractType) //@M an abstract type's type parameters are entered -- TODO: change to isTypeMember ?
+ newNamer(ctx.makeNewScope(owner, ownerSym)(PolyTypeCompleterScopeKind)).enterSyms(tparams) //@M
+ restp.complete(sym)
+ }
+ }
+
+ /** The symbol that which this accessor represents (possibly in part).
+ * This is used for error messages, where we want to speak in terms
+ * of the actual declaration or definition, not in terms of the generated setters
+ * and getters */
+ def underlying(member: Symbol): Symbol =
+ if (member hasFlag ACCESSOR) {
+ if (member.isDeferred) {
+ val getter = if (member.isSetter) member.getter(member.owner) else member
+ if (inIDE && getter == NoSymbol) return NoSymbol;
+ val result = getter.owner.newValue(getter.pos, getter.name)
+ .setInfo(getter.tpe.resultType)
+ .setFlag(DEFERRED)
+ if (getter.setter(member.owner) != NoSymbol) result.setFlag(MUTABLE)
+ result
+ } else member.accessed
+ } else member
+
+ /** An explanatory note to be added to error messages
+ * when there's a problem with abstract var defs */
+ def varNotice(sym: Symbol): String =
+ if (underlying(sym).isVariable)
+ "\n(Note that variables need to be initialized to be defined)"
+ else ""
+}
+
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala.2 b/src/compiler/scala/tools/nsc/typechecker/Namers.scala.2
new file mode 100755
index 0000000000..bffde363c0
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala.2
@@ -0,0 +1,1046 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2009 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id: Namers.scala 17114 2009-02-15 16:43:36Z odersky $
+
+package scala.tools.nsc.typechecker
+
+import scala.collection.mutable.HashMap
+import scala.tools.nsc.util.Position
+import symtab.Flags
+import symtab.Flags._
+
+/** This trait declares methods to create symbols and to enter them into scopes.
+ *
+ * @author Martin Odersky
+ * @version 1.0
+ */
+trait Namers { self: Analyzer =>
+ import global._
+ import definitions._
+ import posAssigner.atPos
+
+ /** Convert to corresponding type parameters all skolems of method parameters
+ * which appear in `tparams`.
+ */
+ class DeSkolemizeMap(tparams: List[Symbol]) extends TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case TypeRef(pre, sym, args)
+ if (sym.isTypeSkolem && (tparams contains sym.deSkolemize)) =>
+// println("DESKOLEMIZING "+sym+" in "+sym.owner)
+ mapOver(rawTypeRef(NoPrefix, sym.deSkolemize, args))
+/*
+ case PolyType(tparams1, restpe) =>
+ new DeSkolemizeMap(tparams1 ::: tparams).mapOver(tp)
+ case ClassInfoType(parents, decls, clazz) =>
+ val parents1 = List.mapConserve(parents)(this)
+ if (parents1 eq parents) tp else ClassInfoType(parents1, decls, clazz)
+*/
+ case _ =>
+ mapOver(tp)
+ }
+ }
+
+ private class NormalNamer(context : Context) extends Namer(context)
+ def newNamer(context : Context) : Namer = new NormalNamer(context)
+
+ private[typechecker] val caseClassOfModuleClass = new HashMap[Symbol, ClassDef]
+
+ def resetNamer() {
+ caseClassOfModuleClass.clear
+ }
+
+ abstract class Namer(val context: Context) {
+
+ val typer = newTyper(context)
+
+ def setPrivateWithin[Sym <: Symbol](tree: Tree, sym: Sym, mods: Modifiers): Sym = {
+ if (!mods.privateWithin.isEmpty)
+ sym.privateWithin = typer.qualifyingClassContext(tree, mods.privateWithin, true).owner
+ sym
+ }
+
+ def inConstructorFlag: Long =
+ if (context.owner.isConstructor && !context.inConstructorSuffix || context.owner.isEarly) INCONSTRUCTOR
+ else 0l
+
+ def moduleClassFlags(moduleFlags: Long) =
+ (moduleFlags & ModuleToClassFlags) | FINAL | inConstructorFlag
+
+ def updatePosFlags(sym: Symbol, pos: Position, flags: Long): Symbol = {
+ if (settings.debug.value) log("overwriting " + sym)
+ val lockedFlag = sym.flags & LOCKED
+ sym.reset(NoType)
+ sym setPos pos
+ sym.flags = flags | lockedFlag
+ if (sym.isModule && sym.moduleClass != NoSymbol)
+ updatePosFlags(sym.moduleClass, pos, moduleClassFlags(flags))
+ if (sym.owner.isPackageClass &&
+ (sym.linkedSym.rawInfo.isInstanceOf[loaders.SymbolLoader] ||
+ sym.linkedSym.rawInfo.isComplete && runId(sym.validTo) != currentRunId))
+ // pre-set linked symbol to NoType, in case it is not loaded together with this symbol.
+ sym.linkedSym.setInfo(NoType)
+ sym
+ }
+
+ private def isTemplateContext(context: Context): Boolean = context.tree match {
+ case Template(_, _, _) => true
+ case Import(_, _) => isTemplateContext(context.outer)
+ case _ => false
+ }
+
+ private var innerNamerCache: Namer = null
+ protected def makeConstructorScope(classContext : Context) : Context = {
+ val outerContext = classContext.outer.outer
+ outerContext.makeNewScope(outerContext.tree, outerContext.owner)(Constructor1ScopeKind)
+ }
+
+ def namerOf(sym: Symbol): Namer = {
+
+ def innerNamer: Namer = {
+ if (innerNamerCache eq null)
+ innerNamerCache =
+ if (!isTemplateContext(context)) this
+ else newNamer(context.make(context.tree, context.owner, scopeFor(context.tree, InnerScopeKind)))
+ innerNamerCache
+ }
+
+ def primaryConstructorParamNamer: Namer = { //todo: can we merge this with SCCmode?
+ val classContext = context.enclClass
+ val paramContext = makeConstructorScope(classContext)
+ val unsafeTypeParams = context.owner.unsafeTypeParams
+ unsafeTypeParams foreach(sym => paramContext.scope.enter(sym))
+ newNamer(paramContext)
+ }
+ if (sym.isTerm) {
+ if (sym.hasFlag(PARAM) && sym.owner.isPrimaryConstructor)
+ primaryConstructorParamNamer
+ else if (sym.hasFlag(PARAMACCESSOR) && !inIDE)
+ primaryConstructorParamNamer
+ else innerNamer
+ } else innerNamer
+ }
+
+ protected def conflict(newS : Symbol, oldS : Symbol) : Boolean = {
+ (!oldS.isSourceMethod ||
+ nme.isSetterName(newS.name) ||
+ newS.owner.isPackageClass) &&
+ !((newS.owner.isTypeParameter || newS.owner.isAbstractType) &&
+ newS.name.length==1 && newS.name(0)=='_') //@M: allow repeated use of `_' for higher-order type params
+ }
+
+ // IDE hook
+ protected def setInfo[Sym <: Symbol](sym : Sym)(tpe : LazyType) : Sym = sym.setInfo(tpe)
+
+ private def doubleDefError(pos: Position, sym: Symbol) {
+ context.error(pos,
+ sym.name.toString() + " is already defined as " +
+ (if (sym.hasFlag(SYNTHETIC))
+ "(compiler-generated) "+ (if (sym.isModule) "case class companion " else "")
+ else "") +
+ (if (sym.hasFlag(CASE)) "case class " + sym.name else sym.toString()))
+ }
+
+ private def inCurrentScope(m: Symbol): Boolean = {
+ if (context.owner.isClass) context.owner == m.owner
+ else m.owner.isClass && context.scope == m.owner.info.decls
+ }
+
+ def enterInScope(sym: Symbol): Symbol = enterInScope(sym, context.scope)
+
+ def enterInScope(sym: Symbol, scope: Scope): Symbol = {
+ // allow for overloaded methods
+ if (!(sym.isSourceMethod && sym.owner.isClass && !sym.owner.isPackageClass)) {
+ var prev = scope.lookupEntryWithContext(sym.name)(context.owner);
+ if ((prev ne null) && inIDE) {
+ var guess = prev
+ while ((guess ne null) && (guess.sym ne sym)) guess = scope.lookupNextEntry(guess)
+ if (guess != null) prev = guess
+ while (prev != null && (!prev.sym.hasRawInfo || !prev.sym.rawInfo.isComplete ||
+ (prev.sym.sourceFile == null && sym.getClass == prev.sym.getClass))) {
+ if (!prev.sym.hasRawInfo || prev.sym.rawInfo.isComplete) {
+ Console.println("DITCHING: " + prev.sym)
+ }
+ scope unlink prev.sym
+ prev = scope.lookupNextEntry(prev)
+ }
+ val sym0 = scope enter sym
+ if (sym0 ne sym) {
+ Console.println("WEIRD: " + sym0 + " vs. " + sym + " " + sym0.id + " " + sym.id + " " + sym.sourceFile + " " + sym0.sourceFile)
+ }
+ if (prev != null && (sym0 ne prev.sym) && conflict(sym0,prev.sym)) {
+ doubleDefError(sym0.pos, prev.sym)
+ }
+ sym0
+ } else if ((prev ne null) && prev.owner == scope && conflict(sym, prev.sym)) {
+ doubleDefError(sym.pos, prev.sym)
+ sym setInfo ErrorType // don't do this in IDE for stability
+ scope unlink prev.sym // let them co-exist...
+ scope enter sym
+ } else scope enter sym
+ } else scope enter sym
+ }
+
+ def enterPackageSymbol(pos: Position, name: Name): Symbol = {
+ val (cscope, cowner) =
+ if (context.owner == EmptyPackageClass) (RootClass.info.decls, RootClass)
+ else (context.scope, context.owner)
+ val p: Symbol = cscope.lookupWithContext(name)(context.owner)
+ if (p.isPackage && cscope == p.owner.info.decls) {
+ p
+ } else {
+ val pkg = cowner.newPackage(pos, name)
+ // IDE: newScope should be ok because packages are never destroyed.
+ if (inIDE) assert(!pkg.moduleClass.hasRawInfo || !pkg.moduleClass.rawInfo.isComplete)
+ pkg.moduleClass.setInfo(new PackageClassInfoType(newScope, pkg.moduleClass, null))
+ pkg.setInfo(pkg.moduleClass.tpe)
+ enterInScope(pkg, cscope)
+ }
+ }
+
+ def enterClassSymbol(tree : ClassDef): Symbol = {
+ var c: Symbol = context.scope.lookupWithContext(tree.name)(context.owner);
+ if (!inIDE && c.isType && c.owner.isPackageClass && context.scope == c.owner.info.decls && !currentRun.compiles(c)) {
+ updatePosFlags(c, tree.pos, tree.mods.flags)
+ setPrivateWithin(tree, c, tree.mods)
+ } else {
+ var sym = context.owner.newClass(tree.pos, tree.name)
+ sym = sym.setFlag(tree.mods.flags | inConstructorFlag)
+ sym = setPrivateWithin(tree, sym, tree.mods)
+ c = enterInScope(sym)
+ }
+ if (c.owner.isPackageClass) {
+ val file = context.unit.source.file
+ val clazz = c.asInstanceOf[ClassSymbol]
+ if (settings.debug.value && (clazz.sourceFile ne null) && !clazz.sourceFile.equals(file)) {
+ Console.err.println("SOURCE MISMATCH: " + clazz.sourceFile + " vs. " + file + " SYM=" + c);
+ }
+ clazz.sourceFile = file
+ if (clazz.sourceFile ne null) {
+ assert(inIDE || !currentRun.compiles(clazz) || clazz.sourceFile == currentRun.symSource(c));
+ currentRun.symSource(c) = clazz.sourceFile
+ }
+ }
+ assert(c.name.toString.indexOf('(') == -1)
+ c
+ }
+
+ /** Enter a module symbol. The tree parameter can be either a module definition
+ * or a class definition */
+ def enterModuleSymbol(tree : ModuleDef): Symbol = {
+ // .pos, mods.flags | MODULE | FINAL, name
+ var m: Symbol = context.scope.lookupWithContext(tree.name)(context.owner)
+ val moduleFlags = tree.mods.flags | MODULE | FINAL
+ if (m.isModule && !m.isPackage && inCurrentScope(m) &&
+ ((!inIDE && !currentRun.compiles(m)) || (m hasFlag SYNTHETIC))) {
+ updatePosFlags(m, tree.pos, moduleFlags)
+ setPrivateWithin(tree, m, tree.mods)
+ context.unit.synthetics -= m
+ } else {
+ m = context.owner.newModule(tree.pos, tree.name)
+ m.setFlag(moduleFlags)
+ m = setPrivateWithin(tree, m, tree.mods)
+ m = enterInScope(m)
+
+ m.moduleClass.setFlag(moduleClassFlags(moduleFlags))
+ setPrivateWithin(tree, m.moduleClass, tree.mods)
+ }
+ if (m.owner.isPackageClass) {
+ m.moduleClass.sourceFile = context.unit.source.file
+ currentRun.symSource(m) = m.moduleClass.sourceFile
+ }
+ m
+ }
+
+ def enterSyms(trees: List[Tree]): Namer = {
+ var namer : Namer = this
+ for (tree <- trees) {
+ val txt = namer.enterSym(tree)
+ if (!(txt eq namer.context)) namer = newNamer(txt)
+ }
+ namer
+ }
+
+ def newTypeSkolems(tparams: List[Symbol]): List[Symbol] = {
+ val tskolems = tparams map (_.newTypeSkolem)
+ val ltp = new LazyType {
+ override def complete(sym: Symbol) {
+ sym setInfo sym.deSkolemize.info.substSym(tparams, tskolems) //@M the info of a skolem is the skolemized info of the actual type parameter of the skolem
+ }
+ }
+ tskolems foreach (_.setInfo(ltp))
+ tskolems
+ }
+
+ /** Replace type parameters with their TypeSkolems, which can later be deskolemized to the original type param
+ * (a skolem is a representation of a bound variable when viewed inside its scope)
+ */
+ def skolemize(tparams: List[TypeDef]) {
+ val tskolems = newTypeSkolems(tparams map (_.symbol))
+ for ((tparam, tskolem) <- tparams zip tskolems) tparam.symbol = tskolem
+ }
+
+ def applicableTypeParams(owner: Symbol): List[Symbol] =
+ if (inIDE && (owner eq NoSymbol)) List()
+ else if (owner.isTerm || owner.isPackageClass) List()
+ else applicableTypeParams(owner.owner) ::: owner.typeParams
+
+ def enterSym(tree: Tree): Context = try {
+
+ def finishWith(tparams: List[TypeDef]) {
+ val sym = tree.symbol
+ if (settings.debug.value) log("entered " + sym + " in " + context.owner + ", scope-id = " + context.scope.hashCode());
+ var ltype = namerOf(sym).typeCompleter(tree)
+ if (!tparams.isEmpty) {
+ //@M! TypeDef's type params are handled differently
+ //@M e.g., in [A[x <: B], B], A and B are entered first as both are in scope in the definition of x
+ //@M x is only in scope in `A[x <: B]'
+ if(!sym.isAbstractType) //@M TODO: change to isTypeMember ?
+ newNamer(context.makeNewScope(tree, sym)(FinishWithScopeKind)).enterSyms(tparams)
+ ltype = new PolyTypeCompleter(tparams, ltype, tree, sym, context) //@M
+ if (sym.isTerm) skolemize(tparams)
+ }
+ setInfo(sym)(ltype)
+ }
+ def finish = finishWith(List())
+
+ if (tree.symbol == NoSymbol) {
+ val owner = context.owner
+ tree match {
+ case PackageDef(name, stats) =>
+ tree.symbol = enterPackageSymbol(tree.pos, name)
+ val namer = newNamer(
+ context.make(tree, tree.symbol.moduleClass, tree.symbol.info.decls))
+ namer.enterSyms(stats)
+ case tree @ ClassDef(mods, name, tparams, impl) =>
+ tree.symbol = enterClassSymbol(tree)
+ finishWith(tparams)
+ if ((mods.flags & CASE) != 0) {
+ var m: Symbol = context.scope.lookupWithContext(tree.name.toTermName)(context.owner).filter(! _.isSourceMethod)
+ if (!(m.isModule && inCurrentScope(m) && (inIDE || currentRun.compiles(m)))) {
+ m = enterSyntheticSym(caseModuleDef(tree))
+ }
+ caseClassOfModuleClass(m.moduleClass) = tree
+ }
+ case tree @ ModuleDef(mods, name, _) =>
+ tree.symbol = enterModuleSymbol(tree)
+ tree.symbol.moduleClass.setInfo(namerOf(tree.symbol).moduleClassTypeCompleter((tree)))
+ finish
+
+ case ValDef(mods, name, tp, rhs) =>
+ if ((!context.owner.isClass ||
+ (mods.flags & (PRIVATE | LOCAL)) == (PRIVATE | LOCAL) ||
+ name.endsWith(nme.OUTER, nme.OUTER.length) ||
+ context.unit.isJava) &&
+ (mods.flags & LAZY) == 0) {
+ tree.symbol = enterInScope(owner.newValue(tree.pos, name)
+ .setFlag(mods.flags))
+ finish
+ } else {
+ // add getter and possibly also setter
+ val accflags: Long = ACCESSOR |
+ (if ((mods.flags & MUTABLE) != 0) mods.flags & ~MUTABLE & ~PRESUPER
+ else mods.flags & ~PRESUPER | STABLE)
+ if (nme.isSetterName(name))
+ context.error(tree.pos, "Names of vals or vars may not end in `_='")
+ var getter = owner.newMethod(tree.pos, name).setFlag(accflags)
+ setPrivateWithin(tree, getter, mods)
+ getter = enterInScope(getter).asInstanceOf[TermSymbol]
+ setInfo(getter)(namerOf(getter).getterTypeCompleter(tree))
+ if ((mods.flags & MUTABLE) != 0) {
+ var setter = owner.newMethod(tree.pos, nme.getterToSetter(name))
+ .setFlag(accflags & ~STABLE & ~CASEACCESSOR)
+ setPrivateWithin(tree, setter, mods)
+ setter = enterInScope(setter).asInstanceOf[TermSymbol]
+ setInfo(setter)(namerOf(setter).setterTypeCompleter(tree))
+ }
+ tree.symbol =
+ if ((mods.flags & DEFERRED) == 0) {
+ var vsym =
+ if (!context.owner.isClass) {
+ assert((mods.flags & LAZY) != 0) // if not a field, it has to be a lazy val
+ owner.newValue(tree.pos, name + "$lzy" ).setFlag(mods.flags | MUTABLE)
+ } else {
+ owner.newValue(tree.pos, nme.getterToLocal(name))
+ .setFlag(mods.flags & FieldFlags | PRIVATE | LOCAL | (if ((mods.flags & LAZY) != 0) MUTABLE else 0))
+ }
+ vsym = enterInScope(vsym).asInstanceOf[TermSymbol]
+ setInfo(vsym)(namerOf(vsym).typeCompleter(tree))
+ if ((mods.flags & LAZY) != 0)
+ vsym.setLazyAccessor(getter)
+ vsym
+ } else getter
+ }
+ case DefDef(mods, nme.CONSTRUCTOR, tparams, _, _, _) =>
+ var sym = owner.newConstructor(tree.pos).setFlag(mods.flags | owner.getFlag(ConstrFlags))
+ setPrivateWithin(tree, sym, mods)
+ tree.symbol = enterInScope(sym)
+ finishWith(tparams)
+ case DefDef(mods, name, tparams, _, _, _) =>
+ var sym = (owner.newMethod(tree.pos, name)).setFlag(mods.flags)
+ setPrivateWithin(tree, sym, mods)
+ tree.symbol = enterInScope(sym)
+ finishWith(tparams)
+ case TypeDef(mods, name, tparams, _) =>
+ var flags: Long = mods.flags
+ if ((flags & PARAM) != 0) flags |= DEFERRED
+ var sym = new TypeSymbol(owner, tree.pos, name).setFlag(flags)
+ setPrivateWithin(tree, sym, mods)
+ tree.symbol = enterInScope(sym)
+ finishWith(tparams)
+ case DocDef(_, defn) =>
+ enterSym(defn)
+ case imp @ Import(_, _) =>
+ tree.symbol = NoSymbol.newImport(tree.pos)
+ setInfo(tree.symbol)(namerOf(tree.symbol).typeCompleter(tree))
+ return (context.makeNewImport(imp))
+ case _ =>
+ }
+ }
+ this.context
+ } catch {
+ case ex: TypeError =>
+ //Console.println("caught " + ex + " in enterSym")//DEBUG
+ typer.reportTypeError(tree.pos, ex)
+ this.context
+ }
+
+ def enterSyntheticSym(tree: Tree): Symbol = {
+ enterSym(tree)
+ context.unit.synthetics(tree.symbol) = tree
+ tree.symbol
+ }
+
+// --- Lazy Type Assignment --------------------------------------------------
+
+ def typeCompleter(tree: Tree) = mkTypeCompleter(tree) { sym =>
+ if (settings.debug.value) log("defining " + sym + Flags.flagsToString(sym.flags)+sym.locationString)
+ val tp = typeSig(tree)
+ tp match {
+ case TypeBounds(lo, hi) =>
+ // check that lower bound is not an F-bound
+ for (val t <- lo) {
+ t match {
+ case TypeRef(_, sym, _) => sym.initialize
+ case _ =>
+ }
+ }
+ case _ =>
+ }
+ sym.setInfo(tp)
+ if ((sym.isAliasType || sym.isAbstractType) && !(sym hasFlag PARAM) &&
+ !typer.checkNonCyclic(tree.pos, tp))
+ sym.setInfo(ErrorType) // this early test is there to avoid infinite baseTypes when
+ // adding setters and getters --> bug798
+ if (settings.debug.value) log("defined " + sym);
+ validate(sym)
+ }
+
+ def moduleClassTypeCompleter(tree: Tree) = {
+ mkTypeCompleter(tree) { sym =>
+ val moduleSymbol = tree.symbol
+ assert(moduleSymbol.moduleClass == sym)
+ if (inIDE && moduleSymbol.rawInfo.isComplete) {
+ // reset!
+ }
+ moduleSymbol.info // sets moduleClass info as a side effect.
+ //assert(sym.rawInfo.isComplete)
+ }
+ }
+
+ def getterTypeCompleter(tree: Tree) = mkTypeCompleter(tree) { sym =>
+ if (settings.debug.value) log("defining " + sym)
+ sym.setInfo(PolyType(List(), typeSig(tree)))
+ if (settings.debug.value) log("defined " + sym)
+ validate(sym)
+ }
+
+ def setterTypeCompleter(tree: Tree) = mkTypeCompleter(tree) { sym =>
+ if (settings.debug.value) log("defining " + sym);
+ sym.setInfo(MethodType(List(typeSig(tree)), UnitClass.tpe))
+ if (settings.debug.value) log("defined " + sym);
+ validate(sym)
+ }
+
+ def selfTypeCompleter(tree: Tree) = mkTypeCompleter(tree) { sym =>
+ var selftpe = typer.typedType(tree).tpe
+ if (!(selftpe.typeSymbol isNonBottomSubClass sym.owner))
+ selftpe = intersectionType(List(sym.owner.tpe, selftpe))
+// println("completing self of "+sym.owner+": "+selftpe)
+ sym.setInfo(selftpe)
+ }
+
+ private def widenIfNotFinal(sym: Symbol, tpe: Type, pt: Type): Type = {
+ val getter =
+ if (sym.isValue && sym.owner.isClass && (sym hasFlag PRIVATE))
+ sym.getter(sym.owner)
+ else sym
+ def isHidden(tp: Type): Boolean = tp match {
+ case SingleType(pre, sym) =>
+ (sym isLessAccessibleThan getter) || isHidden(pre)
+ case ThisType(sym) =>
+ sym isLessAccessibleThan getter
+ case p: SimpleTypeProxy =>
+ isHidden(p.underlying)
+ case _ =>
+ false
+ }
+ val tpe1 = tpe.deconst
+ val tpe2 = tpe1.widen
+ if ((sym.isVariable || sym.isMethod && !(sym hasFlag ACCESSOR)))
+ if (tpe2 <:< pt) tpe2 else tpe1
+ else if (isHidden(tpe)) tpe2
+ else if (!(sym hasFlag FINAL)) tpe1
+ else tpe
+ }
+
+ def enterValueParams(owner: Symbol, vparamss: List[List[ValDef]]): List[List[Symbol]] = {
+ def enterValueParam(param: ValDef): Symbol = {
+ if (inIDE) param.symbol = {
+ var sym = owner.newValueParameter(param.pos, param.name).
+ setFlag(param.mods.flags & (BYNAMEPARAM | IMPLICIT))
+ setPrivateWithin(param, sym, param.mods)
+ sym = enterInScope(sym).asInstanceOf[TermSymbol]
+ if (!sym.hasRawInfo || sym.rawInfo.isComplete)
+ setInfo(sym)(typeCompleter(param))
+ sym
+ } else param.symbol = setInfo(
+ enterInScope{
+ val sym = owner.newValueParameter(param.pos, param.name).
+ setFlag(param.mods.flags & (BYNAMEPARAM | IMPLICIT))
+ setPrivateWithin(param, sym, param.mods)
+ })(typeCompleter(param))
+ param.symbol
+ }
+ vparamss.map(_.map(enterValueParam))
+ }
+
+ private def templateSig(templ: Template): Type = {
+ val clazz = context.owner
+ def checkParent(tpt: Tree): Type = {
+ val tp = tpt.tpe
+ if (tp.typeSymbol == context.owner) {
+ context.error(tpt.pos, ""+tp.typeSymbol+" inherits itself")
+ AnyRefClass.tpe
+ } else if (tp.isError) {
+ AnyRefClass.tpe
+ } else {
+ tp
+ }
+ }
+ def enterSelf(self: ValDef) {
+ if (!self.tpt.isEmpty) {
+ clazz.typeOfThis = selfTypeCompleter(self.tpt)
+ self.symbol = clazz.thisSym.setPos(self.pos)
+ } else {
+ self.tpt.tpe = NoType
+ if (self.name != nme.WILDCARD) {
+ clazz.typeOfThis = clazz.tpe
+ self.symbol = clazz.thisSym
+ } else if (self ne emptyValDef) {
+ self.symbol = clazz.newThisSym(self.pos) setInfo clazz.tpe
+ }
+ }
+ if (self.name != nme.WILDCARD) {
+ self.symbol.name = self.name
+ self.symbol = context.scope enter self.symbol
+ }
+ }
+ var parents = typer.parentTypes(templ) map checkParent
+ enterSelf(templ.self)
+ val decls = newClassScope(clazz)
+ val templateNamer = newNamer(context.make(templ, clazz, decls))
+ .enterSyms(templ.body)
+
+ /* add overridden virtuals to parents
+ val overridden = clazz.overriddenVirtuals
+ if (!overridden.isEmpty)
+ parents = parents ::: ( overridden map (
+ sym => TypeRef(clazz.owner.thisType, sym, clazz.typeParams map (_.tpe))))
+ println("Parents of "+clazz+":"+parents)
+
+ // check that virtual classses are only defined as members of templates
+ if (clazz.isVirtualClass && !clazz.owner.isClass)
+ context.error(
+ clazz.pos,
+ "virtual traits and their subclasses must be defined as members of some other class")
+
+ // make subclasses of virtual classes virtual as well; check that
+ // they are defined in same scope.
+ val virtualParents = parents map (_.typeSymbol) filter (_.isVirtualClass)
+ virtualParents find {
+ vp => !(clazz.owner.isClass && (clazz.owner isSubClass vp.owner))
+ } match {
+ case Some(vp) =>
+ context.error(
+ clazz.pos,
+ "subclass of virtual "+vp+
+ " needs to be defined at same level,\nas member of "+vp.owner)
+ case None =>
+ if (!virtualParents.isEmpty) clazz setFlag DEFERRED // make it virtual
+ }
+ */
+
+ // add apply and unapply methods to companion objects of case classes,
+ // unless they exist already
+ Namers.this.caseClassOfModuleClass get clazz match {
+ case Some(cdef) =>
+ val go = if (inIDE) { // garbage collect in the presentaiton compiler.
+ assert(cdef.symbol != null && cdef.symbol != NoSymbol)
+ if (!cdef.symbol.isClass || !cdef.symbol.hasFlag(CASE) || cdef.symbol.rawInfo == NoType) false
+ else true
+ } else true
+ if (go)
+ addApplyUnapply(cdef, templateNamer)
+ if (!go || !inIDE) caseClassOfModuleClass -= clazz
+ if (!go) {
+ val rem = clazz.linkedModuleOfClass
+ assert(rem != NoSymbol)
+ }
+ case None =>
+ }
+ ClassInfoType(parents, decls, clazz)
+ }
+
+ private def classSig(tparams: List[TypeDef], impl: Template): Type =
+ polyType(typer.reenterTypeParams(tparams), templateSig(impl))
+
+ private def methodSig(tparams: List[TypeDef], vparamss: List[List[ValDef]],
+ tpt: Tree, rhs: Tree): Type = {
+ val meth = context.owner
+
+ val tparamSyms = typer.reenterTypeParams(tparams)
+ var vparamSymss =
+ if (inIDE && meth.isPrimaryConstructor) {
+ // @S: because they have already been entered this way....
+
+ enterValueParams(meth.owner.owner, vparamss)
+ } else {
+ enterValueParams(meth, vparamss)
+ }
+ if (tpt.isEmpty && meth.name == nme.CONSTRUCTOR) {
+ tpt.tpe = context.enclClass.owner.tpe
+ tpt setPos meth.pos
+ }
+
+ if (onlyPresentation && methodArgumentNames != null)
+ methodArgumentNames(meth) = vparamss.map(_.map(_.symbol));
+
+ def convertToDeBruijn(vparams: List[Symbol], level: Int): TypeMap = new TypeMap {
+ def debruijnFor(param: Symbol) =
+ DeBruijnIndex(level, vparams indexOf param)
+ def apply(tp: Type) = {
+ tp match {
+ case SingleType(_, sym) =>
+ if (settings.Xexperimental.value && sym.owner == meth && (vparams contains sym)) {
+/*
+ if (sym hasFlag IMPLICIT) {
+ context.error(sym.pos, "illegal type dependence on implicit parameter")
+ ErrorType
+ } else
+*/
+ debruijnFor(sym)
+ } else tp
+ case MethodType(formals, restpe) =>
+ val formals1 = List.mapConserve(formals)(this)
+ val restpe1 = convertToDeBruijn(vparams, level + 1)(restpe)
+ if ((formals1 eq formals) && (restpe1 eq restpe)) tp
+ else copyMethodType(tp, formals1, restpe1)
+ case _ =>
+ mapOver(tp)
+ }
+ }
+
+ object treeTrans extends TypeMapTransformer {
+ override def transform(tree: Tree): Tree =
+ tree match {
+ case Ident(name) if (vparams contains tree.symbol) =>
+ val dtpe = debruijnFor(tree.symbol)
+ val dsym =
+ newLocalDummy(context.owner, tree.symbol.pos)
+ .newValue(tree.symbol.pos, name)
+
+ dsym.setFlag(PARAM)
+ dsym.setInfo(dtpe)
+ Ident(name).setSymbol(dsym).copyAttrs(tree).setType(dtpe)
+ case tree => super.transform(tree)
+ }
+ }
+
+ override def mapOver(arg: Tree) = Some(treeTrans.transform(arg))
+ }
+
+ val checkDependencies: TypeTraverser = new TypeTraverser {
+ def traverse(tp: Type) = {
+ tp match {
+ case SingleType(_, sym) =>
+ if (sym.owner == meth && (vparamSymss exists (_ contains sym)))
+ context.error(
+ sym.pos,
+ "illegal dependent method type"+
+ (if (settings.Xexperimental.value)
+ ": parameter appears in the type of another parameter in the same section or an earlier one"
+ else ""))
+ case _ =>
+ mapOver(tp)
+ }
+ this
+ }
+ }
+
+ def makeMethodType(vparams: List[Symbol], restpe: Type) = {
+ val formals = vparams map (vparam =>
+ if (meth hasFlag JAVA) objToAny(vparam.tpe) else vparam.tpe)
+ val restpe1 = convertToDeBruijn(vparams, 1)(restpe)
+ if (!vparams.isEmpty && vparams.head.hasFlag(IMPLICIT))
+ ImplicitMethodType(formals, restpe1)
+ else if (meth hasFlag JAVA) JavaMethodType(formals, restpe1)
+ else MethodType(formals, restpe1)
+ }
+
+ def thisMethodType(restpe: Type) =
+ polyType(
+ tparamSyms,
+ if (vparamSymss.isEmpty) PolyType(List(), restpe)
+ else checkDependencies((vparamSymss :\ restpe) (makeMethodType)))
+
+ var resultPt = if (tpt.isEmpty) WildcardType else typer.typedType(tpt).tpe
+ val site = meth.owner.thisType
+
+ def overriddenSymbol = intersectionType(meth.owner.info.parents).member(meth.name).filter(sym =>
+ sym != NoSymbol && (site.memberType(sym) matches thisMethodType(resultPt)))
+
+ // fill in result type and parameter types from overridden symbol if there is a unique one.
+ if (meth.owner.isClass && (tpt.isEmpty || vparamss.exists(_.exists(_.tpt.isEmpty)))) {
+ // try to complete from matching definition in base type
+ for (vparams <- vparamss; vparam <- vparams)
+ if (vparam.tpt.isEmpty) vparam.symbol setInfo WildcardType
+ val overridden = overriddenSymbol
+ if (overridden != NoSymbol && !(overridden hasFlag OVERLOADED)) {
+ resultPt = site.memberType(overridden) match {
+ case PolyType(tparams, rt) => rt.substSym(tparams, tparamSyms)
+ case mt => mt
+ }
+
+ for (vparams <- vparamss) {
+ var pfs = resultPt.paramTypes
+ for (vparam <- vparams) {
+ if (vparam.tpt.isEmpty) {
+ vparam.tpt.tpe = pfs.head
+ vparam.tpt setPos vparam.pos
+ vparam.symbol setInfo pfs.head
+ }
+ pfs = pfs.tail
+ }
+ resultPt = resultPt.resultType
+ }
+ resultPt match {
+ case PolyType(List(), rtpe) => resultPt = rtpe
+ case MethodType(List(), rtpe) => resultPt = rtpe
+ case _ =>
+ }
+ if (tpt.isEmpty) {
+ // provisionally assign `meth' a method type with inherited result type
+ // that way, we can leave out the result type even if method is recursive.
+ meth setInfo thisMethodType(resultPt)
+ }
+ }
+ }
+ // Add a () parameter section if this overrides dome method with () parameters.
+ if (meth.owner.isClass && vparamss.isEmpty && overriddenSymbol.alternatives.exists(
+ _.info.isInstanceOf[MethodType])) {
+ vparamSymss = List(List())
+ }
+ for (vparams <- vparamss; vparam <- vparams if vparam.tpt.isEmpty) {
+ context.error(vparam.pos, "missing parameter type")
+ vparam.tpt.tpe = ErrorType
+ }
+
+ thisMethodType(
+ if (tpt.isEmpty) {
+ val pt = resultPt.substSym(tparamSyms, tparams map (_.symbol))
+ tpt.tpe = widenIfNotFinal(meth, typer.computeType(rhs, pt), pt)
+ tpt setPos meth.pos
+ tpt.tpe
+ } else typer.typedType(tpt).tpe)
+ }
+
+ //@M! an abstract type definition (abstract type member/type parameter) may take type parameters, which are in scope in its bounds
+ private def typeDefSig(tpsym: Symbol, tparams: List[TypeDef], rhs: Tree) = {
+ val tparamSyms = typer.reenterTypeParams(tparams) //@M make tparams available in scope (just for this abstypedef)
+ val tp = typer.typedType(rhs).tpe match {
+ case TypeBounds(lt, rt) if (lt.isError || rt.isError) =>
+ TypeBounds(NothingClass.tpe, AnyClass.tpe)
+ case tp @ TypeBounds(lt, rt) if (tpsym hasFlag JAVA) =>
+ TypeBounds(lt, objToAny(rt))
+ case tp =>
+ tp
+ }
+
+ def verifyOverriding(other: Symbol): Boolean = {
+ if(other.unsafeTypeParams.length != tparamSyms.length) {
+ context.error(tpsym.pos,
+ "The kind of "+tpsym.keyString+" "+tpsym.varianceString + tpsym.nameString+
+ " does not conform to the expected kind of " + other.defString + other.locationString + ".")
+ false
+ } else true
+ }
+
+ // @M: make sure overriding in refinements respects rudimentary kinding
+ // have to do this early, as otherwise we might get crashes: (see neg/bug1275.scala)
+ // suppose some parameterized type member is overridden by a type member w/o params,
+ // then appliedType will be called on a type that does not expect type args --> crash
+ if (tpsym.owner.isRefinementClass && // only needed in refinements
+ !tpsym.allOverriddenSymbols.forall{verifyOverriding(_)})
+ ErrorType
+ else polyType(tparamSyms, tp)
+ }
+
+ /** Given a case class
+ *
+ * case class C[Ts] (ps: Us)
+ *
+ * Add the following methods to toScope:
+ *
+ * 1. if case class is not abstract, add
+ *
+ * <synthetic> <case> def apply[Ts](ps: Us): C[Ts] = new C[Ts](ps)
+ *
+ * 2. add a method
+ *
+ * <synthetic> <case> def unapply[Ts](x: C[Ts]) = <ret-val>
+ *
+ * where <ret-val> is the caseClassUnapplyReturnValue of class C (see UnApplies.scala)
+ */
+ def addApplyUnapply(cdef: ClassDef, namer: Namer) {
+ if (!(cdef.symbol hasFlag ABSTRACT))
+ namer.enterSyntheticSym(caseModuleApplyMeth(cdef))
+ namer.enterSyntheticSym(caseModuleUnapplyMeth(cdef))
+ }
+
+ def typeSig(tree: Tree): Type = {
+ val sym: Symbol = tree.symbol
+ tree match {
+ case defn: MemberDef =>
+ val ainfos = for {
+ annot <- defn.mods.annotations
+ val ainfo = typer.typedAnnotation(annot, tree.symbol)
+ if !ainfo.atp.isError && annot != null
+ } yield ainfo
+ if (!ainfos.isEmpty) {
+ val annotated = if (sym.isModule) sym.moduleClass else sym
+ annotated.attributes = ainfos
+ }
+ case _ =>
+ }
+ implicit val scopeKind = TypeSigScopeKind
+ val result =
+ try {
+ tree match {
+ case ClassDef(_, _, tparams, impl) =>
+ newNamer(context.makeNewScope(tree, sym)).classSig(tparams, impl)
+
+ case ModuleDef(_, _, impl) =>
+ val clazz = sym.moduleClass
+ clazz.setInfo(newNamer(context.makeNewScope(tree, clazz)).templateSig(impl))
+ //clazz.typeOfThis = singleType(sym.owner.thisType, sym);
+ clazz.tpe
+
+ case DefDef(_, _, tparams, vparamss, tpt, rhs) =>
+ //val result =
+ newNamer(context.makeNewScope(tree, sym)).methodSig(tparams, vparamss, tpt, rhs)
+
+ case vdef @ ValDef(mods, _, tpt, rhs) =>
+ val typer1 = typer.constrTyperIf(sym.hasFlag(PARAM | PRESUPER) && sym.owner.isConstructor)
+ if (tpt.isEmpty) {
+ if (rhs.isEmpty) {
+ context.error(tpt.pos, "missing parameter type");
+ ErrorType
+ } else {
+ tpt.tpe = widenIfNotFinal(
+ sym,
+ newTyper(typer1.context.make(vdef, sym)).computeType(rhs, WildcardType),
+ WildcardType)
+ tpt setPos vdef.pos
+ tpt.tpe
+ }
+ } else typer1.typedType(tpt).tpe
+
+ case TypeDef(_, _, tparams, rhs) =>
+ newNamer(context.makeNewScope(tree, sym)).typeDefSig(sym, tparams, rhs) //@M!
+
+ case Import(expr, selectors) =>
+ val expr1 = typer.typedQualifier(expr)
+ val base = expr1.tpe
+ typer.checkStable(expr1)
+ if (expr1.symbol.isRootPackage) context.error(tree.pos, "_root_ cannot be imported")
+ def checkNotRedundant(pos: Position, from: Name, to: Name): Boolean = {
+ if (!tree.symbol.hasFlag(SYNTHETIC) &&
+ !((expr1.symbol ne null) && expr1.symbol.isInterpreterWrapper) &&
+ base.member(from) != NoSymbol) {
+ val e = context.scope.lookupEntryWithContext(to)(context.owner)
+ def warnRedundant(sym: Symbol) =
+ context.unit.warning(pos, "imported `"+to+
+ "' is permanently hidden by definition of "+sym+
+ sym.locationString)
+ if ((e ne null) && e.owner == context.scope) {
+ warnRedundant(e.sym); return false
+ } else if (context eq context.enclClass) {
+ val defSym = context.prefix.member(to) filter (
+ sym => sym.exists && context.isAccessible(sym, context.prefix, false))
+ if (defSym != NoSymbol) { warnRedundant(defSym); return false }
+ }
+ }
+ true
+ }
+ def checkSelectors(selectors: List[(Name, Name)]): Unit = selectors match {
+ case (from, to) :: rest =>
+ if (from != nme.WILDCARD && base != ErrorType) {
+ if (base.member(from) == NoSymbol && base.member(from.toTypeName) == NoSymbol)
+ context.error(tree.pos, from.decode + " is not a member of " + expr);
+ if (checkNotRedundant(tree.pos, from, to))
+ checkNotRedundant(tree.pos, from.toTypeName, to.toTypeName)
+ }
+ if (from != nme.WILDCARD && (rest.exists (sel => sel._1 == from)))
+ context.error(tree.pos, from.decode + " is renamed twice");
+ if ((to ne null) && to != nme.WILDCARD && (rest exists (sel => sel._2 == to)))
+ context.error(tree.pos, to.decode + " appears twice as a target of a renaming");
+ checkSelectors(rest)
+ case Nil =>
+ }
+ checkSelectors(selectors)
+ ImportType(expr1)
+ }
+ } catch {
+ case ex: TypeError =>
+ //Console.println("caught " + ex + " in typeSig")//DEBUG
+ typer.reportTypeError(tree.pos, ex)
+ ErrorType
+ }
+ result match {
+ case PolyType(tparams, restpe)
+ if (!tparams.isEmpty && tparams.head.owner.isTerm ||
+ // Adriaan: The added conditon below is quite a hack. It seems that HK type parameters is relying
+ // on a pass that forces all infos in the type to get everything right.
+ // The problem is that the same pass causes cyclic reference errors in
+ // test pos/cyclics.scala. It turned out that deSkolemize is run way more often than necessary,
+ // ruinning it only when needed fixes the cuclic reference errors.
+ // But correcting deSkolemize broke HK types, because we don't do the traversal anymore.
+ // For the moment I made a special hack to do the traversal if we have HK type parameters.
+ // Maybe it's not a hack, then we need to document it better. But ideally, we should find
+ // a way to deal with HK types that's not dependent on accidental side
+ // effects like this.
+ tparams.exists(!_.typeParams.isEmpty)) =>
+ new DeSkolemizeMap(tparams) mapOver result
+ case _ =>
+// println("not skolemizing "+result+" in "+context.owner)
+// new DeSkolemizeMap(List()) mapOver result
+ result
+ }
+ }
+
+ /** Check that symbol's definition is well-formed. This means:
+ * - no conflicting modifiers
+ * - `abstract' modifier only for classes
+ * - `override' modifier never for classes
+ * - `def' modifier never for parameters of case classes
+ * - declarations only in mixins or abstract classes (when not @native)
+ */
+ def validate(sym: Symbol) {
+ def checkNoConflict(flag1: Int, flag2: Int) {
+ if (sym.hasFlag(flag1) && sym.hasFlag(flag2))
+ context.error(sym.pos,
+ if (flag1 == DEFERRED)
+ "abstract member may not have " + Flags.flagsToString(flag2) + " modifier";
+ else
+ "illegal combination of modifiers: " +
+ Flags.flagsToString(flag1) + " and " + Flags.flagsToString(flag2) +
+ " for: " + sym + Flags.flagsToString(sym.rawflags));
+ }
+
+ if (sym.hasFlag(IMPLICIT) && !sym.isTerm)
+ context.error(sym.pos, "`implicit' modifier can be used only for values, variables and methods")
+ if (sym.hasFlag(IMPLICIT) && sym.owner.isPackageClass && !inIDE)
+ context.error(sym.pos, "`implicit' modifier cannot be used for top-level objects")
+ if (sym.hasFlag(ABSTRACT) && !sym.isClass)
+ context.error(sym.pos, "`abstract' modifier can be used only for classes; " +
+ "\nit should be omitted for abstract members")
+ if (sym.hasFlag(OVERRIDE | ABSOVERRIDE) && !sym.hasFlag(TRAIT) && sym.isClass)
+ context.error(sym.pos, "`override' modifier not allowed for classes")
+ if (sym.hasFlag(OVERRIDE | ABSOVERRIDE) && sym.isConstructor)
+ context.error(sym.pos, "`override' modifier not allowed for constructors")
+ if (sym.hasFlag(ABSOVERRIDE) && !sym.owner.isTrait)
+ context.error(sym.pos, "`abstract override' modifier only allowed for members of traits")
+ if (sym.hasFlag(LAZY) && sym.hasFlag(PRESUPER))
+ context.error(sym.pos, "`lazy' definitions may not be initialized early")
+ if (sym.info.typeSymbol == FunctionClass(0) &&
+ sym.isValueParameter && sym.owner.isClass && sym.owner.hasFlag(CASE))
+ context.error(sym.pos, "pass-by-name arguments not allowed for case class parameters");
+ if (sym hasFlag DEFERRED) { // virtual classes count, too
+ if (sym.hasAttribute(definitions.NativeAttr))
+ sym.resetFlag(DEFERRED)
+ else if (!sym.isValueParameter && !sym.isTypeParameterOrSkolem &&
+ !context.tree.isInstanceOf[ExistentialTypeTree] &&
+ (!sym.owner.isClass || sym.owner.isModuleClass || sym.owner.isAnonymousClass)) {
+ context.error(sym.pos,
+ "only classes can have declared but undefined members" + varNotice(sym))
+ sym.resetFlag(DEFERRED)
+ }
+ }
+
+ checkNoConflict(DEFERRED, PRIVATE)
+ checkNoConflict(FINAL, SEALED)
+ checkNoConflict(PRIVATE, PROTECTED)
+ checkNoConflict(PRIVATE, OVERRIDE)
+ /* checkNoConflict(PRIVATE, FINAL) // can't do this because FINAL also means compile-time constant */
+ checkNoConflict(DEFERRED, FINAL)
+ }
+ }
+
+ abstract class TypeCompleter extends LazyType {
+ val tree: Tree
+ }
+
+ def mkTypeCompleter(t: Tree)(c: Symbol => Unit) = new TypeCompleter {
+ val tree = t
+ override def complete(sym: Symbol) = c(sym)
+ }
+
+ /** A class representing a lazy type with known type parameters.
+ */
+ class PolyTypeCompleter(tparams: List[Tree], restp: TypeCompleter, owner: Tree, ownerSym: Symbol, ctx: Context) extends TypeCompleter {
+ override val typeParams: List[Symbol]= tparams map (_.symbol) //@M
+ override val tree = restp.tree
+ override def complete(sym: Symbol) {
+ if(ownerSym.isAbstractType) //@M an abstract type's type parameters are entered -- TODO: change to isTypeMember ?
+ newNamer(ctx.makeNewScope(owner, ownerSym)(PolyTypeCompleterScopeKind)).enterSyms(tparams) //@M
+ restp.complete(sym)
+ }
+ }
+
+ /** The symbol that which this accessor represents (possibly in part).
+ * This is used for error messages, where we want to speak in terms
+ * of the actual declaration or definition, not in terms of the generated setters
+ * and getters */
+ def underlying(member: Symbol): Symbol =
+ if (member hasFlag ACCESSOR) {
+ if (member.isDeferred) {
+ val getter = if (member.isSetter) member.getter(member.owner) else member
+ if (inIDE && getter == NoSymbol) return NoSymbol;
+ val result = getter.owner.newValue(getter.pos, getter.name)
+ .setInfo(getter.tpe.resultType)
+ .setFlag(DEFERRED)
+ if (getter.setter(member.owner) != NoSymbol) result.setFlag(MUTABLE)
+ result
+ } else member.accessed
+ } else member
+
+ /** An explanatory note to be added to error messages
+ * when there's a problem with abstract var defs */
+ def varNotice(sym: Symbol): String =
+ if (underlying(sym).isVariable)
+ "\n(Note that variables need to be initialized to be defined)"
+ else ""
+}
+
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 876431703d..9518f62c37 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -54,6 +54,16 @@ trait Typers { self: Analyzer =>
super.traverse(tree)
}
}
+/* needed for experimental version where eraly types can be type arguments
+ class EarlyMap(clazz: Symbol) extends TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case TypeRef(NoPrefix, sym, List()) if (sym hasFlag PRESUPER) =>
+ TypeRef(ThisType(clazz), sym, List())
+ case _ =>
+ mapOver(tp)
+ }
+ }
+*/
// IDE hooks
def newTyper(context: Context): Typer = new NormalTyper(context)
private class NormalTyper(context : Context) extends Typer(context)
@@ -522,7 +532,8 @@ trait Typers { self: Analyzer =>
(xtypes ||
(pt.isStable ||
(mode & QUALmode) != 0 && !tree.symbol.isConstant ||
- pt.typeSymbol.isAbstractType && pt.bounds.lo.isStable && !(tree.tpe <:< pt)))
+ pt.typeSymbol.isAbstractType && pt.bounds.lo.isStable && !(tree.tpe <:< pt)) ||
+ pt.typeSymbol.isRefinementClass && !(tree.tpe <:< pt))
/** Make symbol accessible. This means:
* If symbol refers to package object, insert `.package` as second to last selector.
@@ -1011,6 +1022,14 @@ trait Typers { self: Analyzer =>
case _ =>
if (!supertparams.isEmpty) error(supertpt.pos, "missing type arguments")
}
+/* experimental: early types as type arguments
+ val hasEarlyTypes = templ.body exists (treeInfo.isEarlyTypeDef)
+ val earlyMap = new EarlyMap(clazz)
+ List.mapConserve(supertpt :: mixins){ tpt =>
+ val tpt1 = checkNoEscaping.privates(clazz, tpt)
+ if (hasEarlyTypes) tpt1 else tpt1 setType earlyMap(tpt1.tpe)
+ }
+*/
//Console.println("parents("+clazz") = "+supertpt :: mixins);//DEBUG
List.mapConserve(supertpt :: mixins)(tpt => checkNoEscaping.privates(clazz, tpt))
@@ -1082,6 +1101,14 @@ trait Typers { self: Analyzer =>
if (!parents.isEmpty && !parents.head.tpe.isError)
for (p <- parents) validateParentClass(p, parents.head.tpe.typeSymbol)
+
+/*
+ if (settings.Xshowcls.value != "" &&
+ settings.Xshowcls.value == context.owner.fullNameString)
+ println("INFO "+context.owner+
+ ", baseclasses = "+(context.owner.info.baseClasses map (_.fullNameString))+
+ ", lin = "+(context.owner.info.baseClasses map (context.owner.thisType.baseType)))
+*/
}
def checkFinitary(classinfo: ClassInfoType) {
@@ -2885,6 +2912,7 @@ trait Typers { self: Analyzer =>
case Select(_, _) => copy.Select(tree, qual, name)
case SelectFromTypeTree(_, _) => copy.SelectFromTypeTree(tree, qual, name)
}
+ //if (name.toString == "Elem") println("typedSelect "+qual+":"+qual.tpe+" "+sym+"/"+tree1+":"+tree1.tpe)
val result = stabilize(makeAccessible(tree1, sym, qual.tpe, qual), qual.tpe, mode, pt)
def isPotentialNullDeference() = {
phase.id <= currentRun.typerPhase.id &&
diff --git a/src/compiler/scala/tools/nsc/util/BitSet.scala b/src/compiler/scala/tools/nsc/util/BitSet.scala
new file mode 100644
index 0000000000..ce83fb8a10
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/util/BitSet.scala
@@ -0,0 +1,155 @@
+package scala.tools.nsc.util
+
+import BitSet._
+
+abstract class BitSet {
+
+ protected def nwords: Int
+ protected def word(idx: Int): Long
+ protected def updateWord(idx: Int, w: Long): BitSet
+
+ def + (elem: Int): BitSet = {
+ require(elem >= 0)
+ if (contains(elem)) this
+ else {
+ val idx = elem >> LogWL
+ updateWord(idx, word(idx) | (1L << elem))
+ }
+ }
+
+ def - (elem: Int): BitSet = {
+ require(elem >= 0)
+ if (contains(elem)) {
+ val idx = elem >> LogWL
+ updateWord(idx, word(idx) & ~(1L << elem))
+ } else this
+ }
+
+ def | (other: BitSet): BitSet = {
+ val len = this.nwords max other.nwords
+ val words = new Array[Long](len)
+ for (idx <- 0 until len)
+ words(idx) = this.word(idx) | other.word(idx)
+ fromArray(words)
+ }
+
+ def & (other: BitSet): BitSet = {
+ val len = this.nwords min other.nwords
+ val words = new Array[Long](len)
+ for (idx <- 0 until len)
+ words(idx) = this.word(idx) & other.word(idx)
+ fromArray(words)
+ }
+
+ def &~ (other: BitSet): BitSet = {
+ val len = this.nwords
+ val words = new Array[Long](len)
+ for (idx <- 0 until len)
+ words(idx) = this.word(idx) & ~other.word(idx)
+ fromArray(words)
+ }
+
+ def ^ (other: BitSet): BitSet = {
+ val len = this.nwords max other.nwords
+ val words = new Array[Long](len)
+ for (idx <- 0 until len)
+ words(idx) = this.word(idx) ^ other.word(idx)
+ fromArray(words)
+ }
+
+ def contains(elem: Int): Boolean =
+ 0 <= elem && (word(elem >> LogWL) & (1L << elem)) != 0
+
+ def subSet(other: BitSet): Boolean =
+ (0 until nwords) forall (idx => (this.word(idx) & ~ other.word(idx)) == 0L)
+
+ override def equals(other: Any) = other match {
+ case that: BitSet =>
+ (0 until (this.nwords max that.nwords)) forall (idx => this.word(idx) == that.word(idx))
+ case _ =>
+ false
+ }
+
+ override def hashCode: Int = {
+ var h = hashSeed
+ for (idx <- 0 until nwords) {
+ val w = word(idx)
+ h = (h * 41 + (w >>> 32).toInt) * 41 + w.toInt
+ }
+ h
+ }
+
+ def addString(sb: StringBuilder, start: String, sep: String, end: String) {
+ sb append start
+ var pre = ""
+ for (i <- 0 until nwords * WordLength)
+ if (contains(i)) {
+ sb append pre append i
+ pre = sep
+ }
+ sb append end
+ }
+
+ def mkString(start: String, sep: String, end: String) = {
+ val sb = new StringBuilder
+ addString(sb, start, sep, end)
+ sb.toString
+ }
+
+ override def toString = mkString("BitSet(", ", ", ")")
+}
+
+object BitSet {
+
+ private final val WordLength = 64
+ private final val LogWL = 6
+ private val hashSeed = "BitSet".hashCode
+
+ val empty: BitSet = new BitSet1(0L)
+
+ def apply(elems: Int*) = (empty /: elems) (_ + _)
+
+ def fromArray(elems: Array[Long]) = {
+ val len = elems.length
+ if (len == 0) empty
+ else if (len == 1) new BitSet1(elems(0))
+ else if (len == 2) new BitSet2(elems(0), elems(1))
+ else new BitSetN(elems)
+ }
+
+ private def updateArray(elems: Array[Long], idx: Int, w: Long): BitSet = {
+ var len = elems.length
+ while (len > 0 && (elems(len - 1) == 0L || w == 0L && idx == len - 1)) len -= 1
+ var newlen = len
+ if (idx >= newlen && w != 0L) newlen = idx + 1
+ val newelems = new Array[Long](newlen)
+ Array.copy(elems, 0, newelems, 0, len)
+ if (idx < newlen) newelems(idx) = w
+ else assert(w == 0L)
+ fromArray(newelems)
+ }
+
+ class BitSet1(val elems: Long) extends BitSet {
+ protected def nwords = 1
+ protected def word(idx: Int) = if (idx == 0) elems else 0L
+ protected def updateWord(idx: Int, w: Long): BitSet =
+ if (idx == 0) new BitSet1(w)
+ else if (idx == 1) new BitSet2(elems, w)
+ else updateArray(Array(elems), idx, w)
+ }
+
+ class BitSet2(val elems0: Long, elems1: Long) extends BitSet {
+ protected def nwords = 2
+ protected def word(idx: Int) = if (idx == 0) elems0 else if (idx == 1) elems1 else 0L
+ protected def updateWord(idx: Int, w: Long): BitSet =
+ if (idx == 0) new BitSet2(w, elems1)
+ else if (idx == 1) new BitSet2(elems0, w)
+ else updateArray(Array(elems0, elems1), idx, w)
+ }
+
+ class BitSetN(val elems: Array[Long]) extends BitSet {
+ protected def nwords = elems.length
+ protected def word(idx: Int) = if (idx < nwords) elems(idx) else 0L
+ protected def updateWord(idx: Int, w: Long): BitSet = updateArray(elems, idx, w)
+ }
+}