diff options
18 files changed, 2508 insertions, 44 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) + } +} diff --git a/src/library/scala/Tuple2.scala.notyet b/src/library/scala/Tuple2.scala.notyet new file mode 100644 index 0000000000..bed6bd3a9a --- /dev/null +++ b/src/library/scala/Tuple2.scala.notyet @@ -0,0 +1,83 @@ + +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2002-2008, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +// $Id: Tuple2.scala 14794 2008-04-23 08:15:17Z washburn $ + +// generated by genprod on Wed Apr 23 10:06:16 CEST 2008 (with extra methods) + +package scala + +object Tuple2 { + class IterableOps[CC[+B] <: Iterable[B], A1, A2](tuple: (CC[A1], Iterable[A2])) { + def zip: CC[(A1, A2)] = { + val elems1 = tuple._1.elements + val elems2 = tuple._2.elements + val b = tuple._1.newBuilder[B] + while (elems1.hasNext && elems2.hasNext) + b += ((elems1.next, elems2.next)) + b.result + } + def map[B](f: (A1, A2) => B): CC[B] = { + val elems1 = tuple._1.elements + val elems2 = tuple._2.elements + val b = tuple._1.newBuilder[B] + while (elems1.hasNext && elems2.hasNext) + b += f(elems1.next, elems2.next) + b.result + } + def flatMap[B](f: (A1, A2) => CC[B]) CC[B] = { + val elems1 = tuple._1.elements + val elems2 = tuple._2.elements + val b = tuple._1.newBuilder[B] + while (elems1.hasNext && elems2.hasNext) + b ++= f(elems1.next, elems2.next) + b.result + } + def foreach(f: (A1, A2) => Unit) { + val elems1 = tuple._1.elements + val elems2 = tuple._2.elements + while (elems1.hasNext && elems2.hasNext) + f(elems1.next, elems2.next) + } + def forall(p: (A1, A2) => Boolean): Boolean = { + val elems1 = tuple._1.elements + val elems2 = tuple._2.elements + while (elems1.hasNext && elems2.hasNext) + if (!p(elems1.next, elems2.next)) return false + true + } + def exists(p: (A1, A2) => Boolean): Boolean = { + val elems1 = tuple._1.elements + val elems2 = tuple._2.elements + while (elems1.hasNext && elems2.hasNext) + if (p(elems1.next, elems2.next)) return true + false + } + } + + implicit def tupleOfIterableWrapper[CC[+B] <: Iterable[B], A1, A2](tuple: (CC[A1], Iterable[A2])) = + new IterableOps(tuple) +} + +/** Tuple2 is the canonical representation of a @see Product2 + * + */ +case class Tuple2[+T1, +T2](_1:T1, _2:T2) + extends Product2[T1, T2] { + + override def toString() = { + val sb = new StringBuilder + sb.append('(').append(_1).append(',').append(_2).append(')') + sb.toString + } + + /** Swap the elements of the tuple */ + def swap: Tuple2[T2,T1] = Tuple2(_2, _1) + +} diff --git a/test/files/neg/cyclics.check b/test/files/neg/cyclics.check new file mode 100644 index 0000000000..c240387d2f --- /dev/null +++ b/test/files/neg/cyclics.check @@ -0,0 +1,10 @@ +cyclics.scala:2: error: illegal cyclic reference involving type A + type A = List[A] + ^ +cyclics.scala:3: error: illegal cyclic reference involving type B + type B[T] = List[B[B[T]]] + ^ +cyclics.scala:5: error: illegal cyclic reference involving type E + type C = I { type E = C } + ^ +three errors found diff --git a/test/files/neg/cyclics.scala b/test/files/neg/cyclics.scala new file mode 100644 index 0000000000..adfc94e4e5 --- /dev/null +++ b/test/files/neg/cyclics.scala @@ -0,0 +1,6 @@ +object test { + type A = List[A] + type B[T] = List[B[B[T]]] + trait I { type E } + type C = I { type E = C } +} diff --git a/test/files/neg/t0015.check b/test/files/neg/t0015.check index 2979237c0a..eb25fc46c8 100644 --- a/test/files/neg/t0015.check +++ b/test/files/neg/t0015.check @@ -3,9 +3,4 @@ t0015.scala:5: error: type mismatch; required: (Nothing) => ? Nil.map(f _) ^ -t0015.scala:21: error: type mismatch; - found : M - required: M.this.selfType - f[Int](self: selfType) - ^ -two errors found +one error found diff --git a/test/files/neg/t0015.scala b/test/files/neg/t0015.scala index 35a6cd11fc..225197f950 100644 --- a/test/files/neg/t0015.scala +++ b/test/files/neg/t0015.scala @@ -18,7 +18,7 @@ abstract class M // compiles successfully //f[Int](self: actualSelfType) - f[Int](self: selfType) + f[Int](self: selfType) // compiles Ok now was well, because we narrow to singletonType in this situation //def g(x: Any) = {} //g(self: selfType) diff --git a/test/files/neg/bug1279a.scala b/test/files/pos/bug1279a.scala index 7568d3afcd..7568d3afcd 100644 --- a/test/files/neg/bug1279a.scala +++ b/test/files/pos/bug1279a.scala diff --git a/test/files/pos/t0674.scala b/test/files/pos/t0674.scala index 2bd9d9a9db..c3d2cc7476 100644 --- a/test/files/pos/t0674.scala +++ b/test/files/pos/t0674.scala @@ -41,7 +41,8 @@ for(a <- Some(1); n <- Some(14); o <- Some(15); p <- Some(16); - q <- Some(17); - r <- Some(18); - s <- Some(19)) yield a) + q <- Some(17) +// r <- Some(18); +// s <- Some(19) + ) yield a) } |