diff options
author | Martin Odersky <odersky@gmail.com> | 2005-05-13 14:44:14 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2005-05-13 14:44:14 +0000 |
commit | a636876294747f48cf4e7add5781b270d3f01cb0 (patch) | |
tree | 60e885f7892c66c4a839892a102e546e1a791ea2 /sources/scala/tools/nsc/typechecker/Namers.scala | |
parent | 57d313ef7e246b90e4b39e328da149cf3f9ff9f5 (diff) | |
download | scala-a636876294747f48cf4e7add5781b270d3f01cb0.tar.gz scala-a636876294747f48cf4e7add5781b270d3f01cb0.tar.bz2 scala-a636876294747f48cf4e7add5781b270d3f01cb0.zip |
*** empty log message ***
Diffstat (limited to 'sources/scala/tools/nsc/typechecker/Namers.scala')
-rwxr-xr-x | sources/scala/tools/nsc/typechecker/Namers.scala | 255 |
1 files changed, 238 insertions, 17 deletions
diff --git a/sources/scala/tools/nsc/typechecker/Namers.scala b/sources/scala/tools/nsc/typechecker/Namers.scala index 34cf558385..01dc7cbe90 100755 --- a/sources/scala/tools/nsc/typechecker/Namers.scala +++ b/sources/scala/tools/nsc/typechecker/Namers.scala @@ -6,6 +6,7 @@ package scala.tools.nsc.typechecker; import scala.tools.util.Position; +import symtab.Flags; import symtab.Flags._; /** Methods to create symbols and to enter them into scopes. */ @@ -19,17 +20,20 @@ trait Namers: Analyzer { new Namer(startContext.make(unit)).enterSym(unit.body); } - class Namer(context: Context) { + class Namer(val context: Context) { - val typer = { - def isTemplateContext(context: Context): boolean = context.tree match { - case Template(_, _) => true - case Import(_, _) => isTemplateContext(context.outer) - case _ => false - } - new Typer( - if (isTemplateContext(context)) context.make(context.tree, context.owner, new Scope()) - else context) + private def isTemplateContext(context: Context): boolean = context.tree match { + case Template(_, _) => true + case Import(_, _) => isTemplateContext(context.outer) + case _ => false + } + + private var innerNamerCache: Namer = null; + def innerNamer: Namer = { + if (innerNamerCache == null) + innerNamerCache = if (!isTemplateContext(context)) this + else new Namer(context.make(context.tree, context.owner, new Scope())); + innerNamerCache } private def doubleDefError(pos: int, sym: Symbol): unit = @@ -108,7 +112,7 @@ trait Namers: Analyzer { def finishWith(tparams: List[AbsTypeDef]): unit = { if (settings.debug.value) log("entered " + tree.symbol); - var ltype: LazyType = typer.typeCompleter(tree); + var ltype: LazyType = innerNamer.typeCompleter(tree); if (!tparams.isEmpty) { new Namer(context.makeNewScope(tree, tree.symbol)).enterSyms(tparams); ltype = new LazyPolyType(tparams map (.symbol), ltype); @@ -129,31 +133,31 @@ trait Namers: Analyzer { if ((mods & (CASE | ABSTRACT)) == CASE) { // enter case factory method. tree.symbol = enterCaseFactorySymbol( tree.pos, mods & AccessFlags | CASE, name.toTermName) - setInfo typer.caseFactoryCompleter(tree) + setInfo innerNamer.caseFactoryCompleter(tree) } tree.symbol = enterClassSymbol(tree.pos, mods, name); if (settings.debug.value) System.out.println("entered: " + tree.symbol + flagsToString(tree.symbol.flags));//debug finishWith(tparams) case ModuleDef(mods, name, _) => tree.symbol = enterModuleSymbol(tree.pos, mods | MODULE | FINAL, name); - tree.symbol.moduleClass.setInfo(typer.typeCompleter(tree)); + tree.symbol.moduleClass.setInfo(innerNamer.typeCompleter(tree)); finish case ValDef(mods, name, tp, rhs) => if (context.owner.isClass & (mods & PRIVATE) == 0) { val accmods = ACCESSOR | (if ((mods & MUTABLE) != 0) mods & ~MUTABLE else mods | STABLE); val getter = owner.newMethod(tree.pos, name) - .setFlag(accmods).setInfo(typer.getterTypeCompleter(tree)); + .setFlag(accmods).setInfo(innerNamer.getterTypeCompleter(tree)); enterInScope(getter); if ((mods & MUTABLE) != 0) { val setter = owner.newMethod(tree.pos, nme.SETTER_NAME(name)) - .setFlag(accmods).setInfo(typer.setterTypeCompleter(tree)); + .setFlag(accmods).setInfo(innerNamer.setterTypeCompleter(tree)); enterInScope(setter) } tree.symbol = if ((mods & DEFERRED) == 0) owner.newValue(tree.pos, name) - .setFlag(mods & FieldFlags | PRIVATE | LOCAL).setInfo(typer.typeCompleter(tree)) + .setFlag(mods & FieldFlags | PRIVATE | LOCAL).setInfo(innerNamer.typeCompleter(tree)) else getter; } else { tree.symbol = @@ -178,13 +182,230 @@ trait Namers: Analyzer { case DocDef(_, defn) => enterSym(defn) case imp @ Import(_, _) => - tree.symbol = NoSymbol.newImport(tree.pos).setInfo(typer.typeCompleter(tree)); + tree.symbol = NoSymbol.newImport(tree.pos).setInfo(innerNamer.typeCompleter(tree)); return new Namer(context.makeNewImport(imp)); case _ => } } this } + +// --- Lazy Type Assignment -------------------------------------------------- + + val typer = newTyper(context); + + def typeCompleter(tree: Tree) = new TypeCompleter(tree) { + override def complete(sym: Symbol): unit = { + if (settings.debug.value) log("defining " + sym); + sym.setInfo(typeSig(tree)); + if (settings.debug.value) log("defined " + sym); + validate(sym); + } + } + + def getterTypeCompleter(tree: Tree) = new TypeCompleter(tree) { + override def complete(sym: Symbol): unit = { + 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) = new TypeCompleter(tree) { + override def complete(sym: Symbol): unit = { + if (settings.debug.value) log("defining " + sym); + sym.setInfo(MethodType(List(typeSig(tree)), definitions.UnitClass.tpe)); + if (settings.debug.value) log("defined " + sym); + validate(sym); + } + } + + def selfTypeCompleter(tree: Tree) = new TypeCompleter(tree) { + override def complete(sym: Symbol): unit = { + sym.setInfo(typer.transformType(tree).tpe); + } + } + + def caseFactoryCompleter(tree: Tree) = new TypeCompleter(tree) { + override def complete(sym: Symbol): unit = { + val clazz = tree.symbol; + var tpe = clazz.primaryConstructor.tpe; + val tparams = clazz.unsafeTypeParams; + if (!tparams.isEmpty) tpe = PolyType(tparams, tpe).cloneInfo(sym); + sym.setInfo(tpe); + } + } + + private def deconstIfNotFinal(sym: Symbol, tpe: Type): Type = + if (sym.isVariable || !sym.isFinal) tpe.deconst else tpe; + + def enterValueParams(owner: Symbol, vparamss: List[List[ValDef]]): List[List[Symbol]] = { + def enterValueParam(param: ValDef): Symbol = { + param.symbol = owner.newValueParameter(param.pos, param.name) + .setInfo(typeCompleter(param)).setFlag(param.mods & IMPLICIT); + context.scope enter param.symbol; + param.symbol + } + vparamss.map(.map(enterValueParam)) + } + + /** A creator for polytypes. If tparams is empty, simply returns result type */ + private def makePolyType(tparams: List[Symbol], tpe: Type): Type = + if (tparams.isEmpty) tpe + else + PolyType(tparams, tpe match { + case PolyType(List(), tpe1) => tpe1 + case _ => tpe + }); + + private def templateSig(templ: Template): Type = { + val clazz = context.owner; + val parents = typer.parentTypes(templ) map (.tpe); + val decls = new Scope(); + new Namer(context.make(templ, clazz, decls)).enterSyms(templ.body); + ClassInfoType(parents, decls, clazz) + } + + private def classSig(tparams: List[AbsTypeDef], tpt: Tree, impl: Template): Type = { + val tparamSyms = typer.reenterTypeParams(tparams); + if (!tpt.isEmpty) + context.owner.typeOfThis = selfTypeCompleter(tpt); + else tpt.tpe = NoType; + makePolyType(tparamSyms, templateSig(impl)) + } + + private def methodSig(tparams: List[AbsTypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree): Type = { + def checkContractive: unit = {}; //todo: complete + val meth = context.owner; + val tparamSyms = typer.reenterTypeParams(tparams); + val vparamSymss = enterValueParams(meth, vparamss); + val restype = deconstIfNotFinal(meth, + if (tpt.isEmpty) { + tpt.tpe = if (meth.name == nme.CONSTRUCTOR) context.enclClass.owner.tpe + else typer.transformExpr(rhs).tpe; + tpt.tpe + } else typer.transformType(tpt).tpe); + def mkMethodType(vparams: List[Symbol], restpe: Type) = { + val formals = vparams map (.tpe); + if (!vparams.isEmpty && vparams.head.hasFlag(IMPLICIT)) { + if (settings.debug.value) System.out.println("create implicit");//debug + checkContractive; + new ImplicitMethodType(formals, restpe) + } else MethodType(formals, restpe); + } + makePolyType( + tparamSyms, + if (vparamSymss.isEmpty) PolyType(List(), restype) + else (vparamSymss :\ restype)(mkMethodType)) + } + + private def aliasTypeSig(tpsym: Symbol, tparams: List[AbsTypeDef], rhs: Tree): Type = + makePolyType(typer.reenterTypeParams(tparams), typer.transformType(rhs).tpe); + + private def typeSig(tree: Tree): Type = + try { + val sym: Symbol = tree.symbol; + tree match { + case ClassDef(_, _, tparams, tpt, impl) => + new Namer(context.makeNewScope(tree, sym)).classSig(tparams, tpt, impl) + + case ModuleDef(_, _, impl) => + val clazz = sym.moduleClass; + clazz.setInfo(new Namer(context.make(tree, clazz)).templateSig(impl)); + clazz.tpe; + + case DefDef(_, _, tparams, vparamss, tpt, rhs) => + new Namer(context.makeNewScope(tree, sym)).methodSig(tparams, vparamss, tpt, rhs) + + case ValDef(_, _, tpt, rhs) => + deconstIfNotFinal(sym, + if (tpt.isEmpty) + if (rhs.isEmpty) { + context.error(tpt.pos, "missing parameter type"); + ErrorType + } else { + tpt.tpe = newTyper(context.make(tree, sym)) + .transformExpr(rhs).tpe; + tpt.tpe + } + else typer.transformType(tpt).tpe) + + case AliasTypeDef(_, _, tparams, rhs) => + new Namer(context.makeNewScope(tree, sym)).aliasTypeSig(sym, tparams, rhs) + + case AbsTypeDef(_, _, lo, hi) => + TypeBounds(typer.transformType(lo).tpe, typer.transformType(hi).tpe); + + case Import(expr, selectors) => + val expr1 = typer.transformQualExpr(expr); + val base = expr1.tpe; + typer.checkStable(expr1); + def checkSelectors(selectors: List[Pair[Name, Name]]): unit = selectors match { + case Pair(from, to) :: rest => + if (from != nme.WILDCARD && base != ErrorType && + base.member(from) == NoSymbol && base.member(from.toTypeName) == NoSymbol) + context.error(tree.pos, from.decode + " is not a member of " + expr); + if (from != nme.WILDCARD && (rest.exists (sel => sel._1 == from))) + context.error(tree.pos, from.decode + " is renamed twice"); + if (to != 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 => + } + ImportType(expr1) + } + } catch { + case ex: TypeError => + typer.reportTypeError(tree.pos, ex); + ErrorType + } + + /** 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 traits or abstract classes + */ + def validate(sym: Symbol): unit = { + def checkNoConflict(flag1: int, flag2: int): unit = + 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)); + if (sym.hasFlag(IMPLICIT) && !sym.isTerm) + context.error(sym.pos, "`implicit' modifier can be used only for values, variables and methods"); + 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.isClass) + context.error(sym.pos, "`override' modifier not allowed for classes"); + if (sym.info.symbol == definitions.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.flags & DEFERRED) != 0) { + if (!sym.isValueParameter && !sym.isTypeParameter && + (!sym.owner.isClass || sym.owner.isModuleClass || sym.owner.isAnonymousClass)) { + context.error(sym.pos, + "only classes can have declared but undefined members" + + (if (!sym.isVariable) "" + else "\n(Note that variables need to be initialized to be defined)")); + sym.resetFlag(DEFERRED); + } + } + checkNoConflict(DEFERRED, PRIVATE); + checkNoConflict(FINAL, SEALED); + if (!sym.hasFlag(MODULE)) checkNoConflict(FINAL, PRIVATE); + checkNoConflict(PRIVATE, PROTECTED); + checkNoConflict(PRIVATE, OVERRIDE); + checkNoConflict(DEFERRED, FINAL); + } } + + abstract class TypeCompleter(val tree: Tree) extends LazyType; } |