summaryrefslogtreecommitdiff
path: root/sources/scala/tools/nsc/typechecker/Namers.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2005-05-13 14:44:14 +0000
committerMartin Odersky <odersky@gmail.com>2005-05-13 14:44:14 +0000
commita636876294747f48cf4e7add5781b270d3f01cb0 (patch)
tree60e885f7892c66c4a839892a102e546e1a791ea2 /sources/scala/tools/nsc/typechecker/Namers.scala
parent57d313ef7e246b90e4b39e328da149cf3f9ff9f5 (diff)
downloadscala-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-xsources/scala/tools/nsc/typechecker/Namers.scala255
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;
}