diff options
author | Martin Odersky <odersky@gmail.com> | 2005-05-17 15:39:54 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2005-05-17 15:39:54 +0000 |
commit | 860077ec57d0ca5412c4448203e5028f3a783193 (patch) | |
tree | 216ee6f7f681247e34d8160c40c32b9c1d18ab69 | |
parent | ea94e149516fcf20b1478f17b8c7d4fd6390f8ac (diff) | |
download | scala-860077ec57d0ca5412c4448203e5028f3a783193.tar.gz scala-860077ec57d0ca5412c4448203e5028f3a783193.tar.bz2 scala-860077ec57d0ca5412c4448203e5028f3a783193.zip |
*** empty log message ***
-rwxr-xr-x | sources/scala/tools/nsc/Global.scala | 3 | ||||
-rwxr-xr-x | sources/scala/tools/nsc/ast/TreeGen.scala | 22 | ||||
-rw-r--r-- | sources/scala/tools/nsc/ast/TreeInfo.scala | 12 | ||||
-rw-r--r-- | sources/scala/tools/nsc/ast/TreePrinters.scala | 3 | ||||
-rw-r--r-- | sources/scala/tools/nsc/ast/Trees.scala | 32 | ||||
-rwxr-xr-x | sources/scala/tools/nsc/ast/parser/Parsers.scala | 30 | ||||
-rwxr-xr-x | sources/scala/tools/nsc/symtab/StdNames.scala | 1 | ||||
-rwxr-xr-x | sources/scala/tools/nsc/symtab/Types.scala | 45 | ||||
-rw-r--r-- | sources/scala/tools/nsc/symtab/classfile/Pickle.scala | 11 | ||||
-rwxr-xr-x | sources/scala/tools/nsc/typechecker/ConstantFolder.scala | 43 | ||||
-rwxr-xr-x | sources/scala/tools/nsc/typechecker/Contexts.scala | 4 | ||||
-rw-r--r-- | sources/scala/tools/nsc/typechecker/EtaExpansion.scala | 12 | ||||
-rwxr-xr-x | sources/scala/tools/nsc/typechecker/Infer.scala | 141 | ||||
-rwxr-xr-x | sources/scala/tools/nsc/typechecker/Namers.scala | 14 | ||||
-rw-r--r-- | sources/scala/tools/nsc/typechecker/TreeCheckers.scala | 60 | ||||
-rwxr-xr-x | sources/scala/tools/nsc/typechecker/Typers.scala | 322 |
16 files changed, 409 insertions, 346 deletions
diff --git a/sources/scala/tools/nsc/Global.scala b/sources/scala/tools/nsc/Global.scala index 318f34b9b0..ca5c913c23 100755 --- a/sources/scala/tools/nsc/Global.scala +++ b/sources/scala/tools/nsc/Global.scala @@ -42,6 +42,8 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable val global: Global.this.type = Global.this } + object typer extends analyzer.Typer(analyzer.NoContext); + object checker extends TreeCheckers { val global: Global.this.type = Global.this } @@ -53,7 +55,6 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable // reporting ------------------------------------------------------- - def error(msg: String) = reporter.error(null, msg); def warning(msg: String) = reporter.warning(null, msg); private def inform(msg: String) = reporter.info(null, msg, true); diff --git a/sources/scala/tools/nsc/ast/TreeGen.scala b/sources/scala/tools/nsc/ast/TreeGen.scala index 82190a13ce..d0b1d6a2f6 100755 --- a/sources/scala/tools/nsc/ast/TreeGen.scala +++ b/sources/scala/tools/nsc/ast/TreeGen.scala @@ -43,10 +43,10 @@ abstract class TreeGen { /** Builds a reference to given symbol. */ def mkRef(sym: Symbol): Tree = mkRef(sym.owner.thisType, sym); - /** Replacecs tree type with a stable type if possible */ + /** Replaces tree type with a stable type if possible */ def stabilize(tree: Tree): Tree = tree match { case Ident(_) => - if (tree.symbol.isStable) tree.setType(singleType(NoPrefix, tree.symbol)) + if (tree.symbol.isStable) tree.setType(singleType(tree.symbol.owner.thisType, tree.symbol)) else tree case Select(qual, _) => if (tree.symbol.isStable && qual.tpe.isStable) tree.setType(singleType(qual.tpe, tree.symbol)) @@ -62,12 +62,12 @@ abstract class TreeGen { def TypeTree(tp: Type) = global.TypeTree() setType tp; def This(sym: Symbol) = - global.This(sym.name) setSymbol sym setType sym.thisType; + typer.transformQualExpr(global.This(sym.name) setSymbol sym); def Ident(sym: Symbol) = { assert(sym.isTerm); sym.setFlag(ACCESSED); - global.Ident(sym.name) setSymbol sym setType sym.tpe; + typer.transformExpr(global.Ident(sym.name) setSymbol sym); } def Select(qual: Tree, sym: Symbol) = { @@ -76,24 +76,16 @@ abstract class TreeGen { global.Select(qual, sym.name) setSymbol sym setType qual.tpe.memberType(sym); } - def Apply(fun: Tree, args: List[Tree]) = fun.tpe match { - case MethodType(formals, restpe) => - global.Apply(fun, args) setType restpe - } - - def Assign(lhs: Tree, rhs: Tree) = - global.Assign(lhs, rhs) setType UnitClass.tpe; - def ValDef(sym: Symbol, rhs: Tree): ValDef = atPos(sym.pos) { global.ValDef(flags2mods(sym.flags), sym.name, TypeTree(sym.tpe), rhs) - setSymbol sym setType UnitClass.tpe + setSymbol sym setType NoType } def ValDef(sym: Symbol): ValDef = ValDef(sym, EmptyTree); def AbsTypeDef(sym: Symbol) = atPos(sym.pos) { global.AbsTypeDef(flags2mods(sym.flags), sym.name, TypeTree(sym.info.bounds.lo), TypeTree(sym.info.bounds.hi)) - setSymbol sym setType UnitClass.tpe + setSymbol sym setType NoType } def DefDef(sym: Symbol, rhs: List[List[Symbol]] => Tree) = atPos(sym.pos) { @@ -113,7 +105,7 @@ abstract class TreeGen { vparamss.map(.map(ValDef)), TypeTree(tpe), rhs(vparamss)) - setSymbol sym setType UnitClass.tpe + setSymbol sym setType NoType } mk(List(), List(), sym.tpe) } diff --git a/sources/scala/tools/nsc/ast/TreeInfo.scala b/sources/scala/tools/nsc/ast/TreeInfo.scala index 8167ef00d7..c0ffe8f4b3 100644 --- a/sources/scala/tools/nsc/ast/TreeInfo.scala +++ b/sources/scala/tools/nsc/ast/TreeInfo.scala @@ -78,9 +78,8 @@ abstract class TreeInfo { /** Is tree a pure constructor? */ def isPureConstr(tree: Tree): boolean = tree match { - case Ident(_) - | Select(_, _) => - tree.symbol != null && tree.symbol.isPrimaryConstructor; + case Ident(_) | Select(_, _) => + tree.symbol.isPrimaryConstructor case TypeApply(fn, _) => isPureConstr(fn) case Apply(fn, List()) => @@ -141,13 +140,6 @@ abstract class TreeInfo { case _ => false } - /** The method symbol of an application node, or NoSymbol, if none exists. - */ - def methSymbol(tree: Tree): Symbol = { - val meth = methPart(tree); - if (meth.hasSymbol) meth.symbol else NoSymbol - } - /** The method part of an application node */ def methPart(tree: Tree): Tree = tree match { diff --git a/sources/scala/tools/nsc/ast/TreePrinters.scala b/sources/scala/tools/nsc/ast/TreePrinters.scala index 8d5d061fcf..96aa8b26dc 100644 --- a/sources/scala/tools/nsc/ast/TreePrinters.scala +++ b/sources/scala/tools/nsc/ast/TreePrinters.scala @@ -74,8 +74,7 @@ abstract class TreePrinters { } def symName(tree: Tree, name: Name): String = - if (tree.symbol != null && tree.symbol != NoSymbol) tree.symbol.nameString - else name.toString(); + if (tree.symbol != NoSymbol) tree.symbol.nameString else name.toString(); def printOpt(prefix: String, tree: Tree): unit = if (!tree.isEmpty) { print(prefix); print(tree) } diff --git a/sources/scala/tools/nsc/ast/Trees.scala b/sources/scala/tools/nsc/ast/Trees.scala index 52b73b5804..d0db368a81 100644 --- a/sources/scala/tools/nsc/ast/Trees.scala +++ b/sources/scala/tools/nsc/ast/Trees.scala @@ -117,11 +117,17 @@ abstract class Trees: Global { /** Attribuetd definition */ case class Attributed(attribute: Tree, definition: Tree) - extends Tree; + extends Tree { + override def symbol: Symbol = definition.symbol; + override def symbol_=(sym: Symbol): unit = { definition.symbol = sym } + } /** Documented definition, eliminated by analyzer */ case class DocDef(comment: String, definition: Tree) - extends Tree; + extends Tree { + override def symbol: Symbol = definition.symbol; + override def symbol_=(sym: Symbol): unit = { definition.symbol = sym } + } /** Instantiation template */ case class Template(parents: List[Tree], body: List[Tree]) @@ -165,7 +171,7 @@ abstract class Trees: Global { /** Return expression */ case class Return(expr: Tree) - extends SymTree with TermTree; + extends TermTree with SymTree; case class Try(block: Tree, catches: List[CaseDef], finalizer: Tree) extends TermTree; @@ -186,11 +192,17 @@ abstract class Trees: Global { /** Type application */ case class TypeApply(fun: Tree, args: List[Tree]) - extends TermTree; + extends TermTree { + override def symbol: Symbol = fun.symbol; + override def symbol_=(sym: Symbol): unit = { fun.symbol = sym } + } /** Value application */ case class Apply(fun: Tree, args: List[Tree]) - extends TermTree; + extends TermTree { + override def symbol: Symbol = fun.symbol; + override def symbol_=(sym: Symbol): unit = { fun.symbol = sym } + } /** Super reference */ case class Super(qual: Name, mixin: Name) @@ -216,7 +228,10 @@ abstract class Trees: Global { /** Literal */ case class Literal(value: Any) - extends TermTree; + extends TermTree { + // todo: change hashcode generation to make this superfluous + override def hashCode(): int = if (value == null) 0 else value.hashCode() * 41 + 17; + } /** General type term, introduced by RefCheck. */ case class TypeTree() extends TypTree { @@ -237,7 +252,10 @@ abstract class Trees: Global { /** Applied type, eliminated by RefCheck */ case class AppliedTypeTree(tpt: Tree, args: List[Tree]) - extends TypTree; + extends TypTree { + override def symbol: Symbol = tpt.symbol; + override def symbol_=(sym: Symbol): unit = { tpt.symbol = sym } + } /* A standard pattern match case EmptyTree => diff --git a/sources/scala/tools/nsc/ast/parser/Parsers.scala b/sources/scala/tools/nsc/ast/parser/Parsers.scala index 8e0ef42c1f..b104a0e819 100755 --- a/sources/scala/tools/nsc/ast/parser/Parsers.scala +++ b/sources/scala/tools/nsc/ast/parser/Parsers.scala @@ -1655,11 +1655,12 @@ abstract class Parsers: ParserPhase { /** Attribute ::= StableId [TypeArgs] [`(' [Exprs] `)'] */ def attribute(): Tree = { + val pos = in.pos; var t: Tree = convertToTypeId(stableId()); if (in.token == LBRACKET) t = atPos(in.pos)(AppliedTypeTree(t, typeArgs())); val args = if (in.token == LPAREN) argumentExprs() else List(); - makeNew(List(t), List(), args) + atPos(pos) { makeNew(List(t), List(), args) } } def joinAttributes(attrs: List[Tree], defs: List[Tree]): List[Tree] = @@ -1724,23 +1725,24 @@ abstract class Parsers: ParserPhase { * | package QualId `{' TopStatSeq `}' * | TopStatSeq */ - def compilationUnit(): Tree = { - if (in.token == PACKAGE) { - val pos = in.skipToken(); - val pkg = qualId(); - if (in.token == SEMI) { + def compilationUnit(): Tree = + atPos(in.pos) { + if (in.token == PACKAGE) { in.nextToken(); - makePackaging(pkg, topStatSeq()) setPos pos; + val pkg = qualId(); + if (in.token == SEMI) { + in.nextToken(); + makePackaging(pkg, topStatSeq()) + } else { + accept(LBRACE); + val t = makePackaging(pkg, topStatSeq()); + accept(RBRACE); + t + } } else { - accept(LBRACE); - val t = makePackaging(pkg, topStatSeq()); - accept(RBRACE); - t + makePackaging(Ident(nme.EMPTY_PACKAGE_NAME), topStatSeq()) } - } else { - makePackaging(Ident(nme.EMPTY_PACKAGE_NAME), topStatSeq()) } - } } } diff --git a/sources/scala/tools/nsc/symtab/StdNames.scala b/sources/scala/tools/nsc/symtab/StdNames.scala index 77e71141c5..45e6ac28dc 100755 --- a/sources/scala/tools/nsc/symtab/StdNames.scala +++ b/sources/scala/tools/nsc/symtab/StdNames.scala @@ -76,6 +76,7 @@ abstract class StdNames: SymbolTable { def TUPLE_FIELD(index: int) = newTermName(TUPLE_FIELD_PREFIX_STRING + index); def SETTER_NAME(name: Name) = encode(name.toString() + "_="); + def LOCAL_NAME(name: Name) = encode(name.toString() + " "); val ERROR = newTermName("<error>"); val ERRORtype = newTypeName("<error>"); diff --git a/sources/scala/tools/nsc/symtab/Types.scala b/sources/scala/tools/nsc/symtab/Types.scala index b921431f4b..56a72ed968 100755 --- a/sources/scala/tools/nsc/symtab/Types.scala +++ b/sources/scala/tools/nsc/symtab/Types.scala @@ -22,7 +22,9 @@ import Flags._; case ClassInfoType(parents, defs, clazz) => case MethodType(paramtypes, result) => case PolyType(tparams, result) => + // the last three types are not used after phase `typer'. case OverloadedType(pre, tparams, alts) => + case AntiPolyType(pre: Type, targs) => case TypeVar(_, _) => */ @@ -706,23 +708,33 @@ abstract class Types: SymbolTable { } } + /** A class containing the alternatives and type prefix of an overloaded symbol. + * Not used after phase `typer'. + */ + case class OverloadedType(pre: Type, alternatives: List[Symbol]) extends Type { + override def prefix: Type = pre; + override def toString() = (alternatives map pre.memberType).mkString("", " <and> ", "") + } + + /** A class remembering a type instantiation for some a set of overloaded polymorphic symbols. + * Not used after phase `typer'. + */ + case class AntiPolyType(pre: Type, targs: List[Type]) extends Type { + override def toString() = pre.toString() + targs.mkString("(with type arguments ", ",", ")"); + override def memberType(sym: Symbol) = pre.memberType(sym) match { + case PolyType(tparams, restp) => restp.subst(tparams, targs) + } + } + /** A class representing a type variable + * Not used after phase `typer'. */ case class TypeVar(origin: Type, constr: TypeConstraint) extends Type { - override def symbol = origin.symbol; - override def toString(): String = if (constr.inst == NoType) "?" + origin else constr.inst.toString(); } - /** A class containing the alternatives and type prefix of an overloaded symbol - */ - case class OverloadedType(pre: Type, alternatives: List[Symbol]) extends Type { - override def prefix: Type = pre; - override def toString() = (alternatives map pre.memberType).mkString("", " <and> ", "") - } - /** A class representing an as-yet unevaluated type. */ abstract class LazyType extends Type { @@ -881,6 +893,11 @@ abstract class Types: SymbolTable { val pre1 = this(pre); if (pre1 eq pre) tp else OverloadedType(pre1, alts) + case AntiPolyType(pre, args) => + val pre1 = this(pre); + val args1 = List.mapConserve(args)(this); + if ((pre1 eq pre) && (args1 eq args)) tp + else AntiPolyType(pre1, args1) case TypeVar(_, constr) => if (constr.inst != NoType) this(constr.inst) else tp @@ -1068,14 +1085,14 @@ abstract class Types: SymbolTable { case Pair(_, WildcardType) => true case Pair(NoType, _) => false - case Pair(NoPrefix, _) => false + case Pair(NoPrefix, _) => tp2.symbol.isPackageClass case Pair(_, NoType) => false - case Pair(_, NoPrefix) => false + case Pair(_, NoPrefix) => tp1.symbol.isPackageClass case Pair(ThisType(sym1), ThisType(sym2)) => sym1 == sym2 case Pair(SingleType(pre1, sym1), SingleType(pre2, sym2)) - if (sym1 == sym2 && pre1 =:= pre2) => + if ((sym1 == sym2) && (pre1 =:= pre2)) => true /* case Pair(SingleType(pre1, sym1), ThisType(sym2)) @@ -1143,9 +1160,9 @@ abstract class Types: SymbolTable { case Pair(_, WildcardType) => true case Pair(NoType, _) => false - case Pair(NoPrefix, _) => false + case Pair(NoPrefix, _) => tp2.symbol.isPackageClass case Pair(_, NoType) => false - case Pair(_, NoPrefix) => false + case Pair(_, NoPrefix) => tp1.symbol.isPackageClass case Pair(ThisType(_), ThisType(_)) => tp1 =:= tp2 case Pair(ThisType(_), SingleType(_, _)) => tp1 =:= tp2 diff --git a/sources/scala/tools/nsc/symtab/classfile/Pickle.scala b/sources/scala/tools/nsc/symtab/classfile/Pickle.scala deleted file mode 100644 index e7f1271761..0000000000 --- a/sources/scala/tools/nsc/symtab/classfile/Pickle.scala +++ /dev/null @@ -1,11 +0,0 @@ -/* NSC -- new scala compiler - * Copyright 2005 LAMP/EPFL - * @author Martin Odersky - */ -// $Id$ -package scala.tools.nsc.symtab.classfile; - -/*************************************************** - * Symbol table attribute format: see EntryTags.java - */ -class Pickle {} diff --git a/sources/scala/tools/nsc/typechecker/ConstantFolder.scala b/sources/scala/tools/nsc/typechecker/ConstantFolder.scala index 83530cdd34..6fa914ea45 100755 --- a/sources/scala/tools/nsc/typechecker/ConstantFolder.scala +++ b/sources/scala/tools/nsc/typechecker/ConstantFolder.scala @@ -14,23 +14,22 @@ abstract class ConstantFolder { private val NoValue = new Object(); /** If tree is a constant operation, replace with result. */ - def apply(tree: Tree): Tree = { - val newvalue = tree match { - case Apply(Select(Literal(x), op), List(Literal(y))) => foldBinop(op, x, y) - case Select(Literal(x), op) => foldUnop(op, x) - case _ => NoValue - } - if (newvalue != NoValue) Literal(newvalue) else tree - } + def apply(tree: Tree): Tree = fold(tree, tree match { + case Apply(Select(Literal(x), op), List(Literal(y))) => foldBinop(op, x, y) + case Select(Literal(x), op) => foldUnop(op, x) + case _ => NoValue + }); /** If tree is a constant value that can be converted to type `pt', perform the conversion */ - def apply(tree: Tree, pt: Type): Tree = { - val newvalue = tree match { - case Literal(value) => foldTyped(value, pt) - case _ => NoValue - } - if (newvalue != NoValue) Literal(newvalue) else tree - } + def apply(tree: Tree, pt: Type): Tree = fold(tree, tree match { + case Literal(value) => foldTyped(value, pt) + case _ => NoValue + }); + + def fold(tree: Tree, value: Any): Tree = + if (value != NoValue) + copy.Literal(tree, value) setType ConstantType(literalType(value), value) + else tree; private def foldUnop(op: Name, value: Any): Any = Pair(op, value) match { case Pair(nme.ZNOT, x: boolean) => !x @@ -182,4 +181,18 @@ abstract class ConstantFolder { NoValue } } + + def literalType(value: Any): Type = + if (value.isInstanceOf[unit]) UnitClass.tpe + else if (value.isInstanceOf[boolean]) BooleanClass.tpe + else if (value.isInstanceOf[byte]) ByteClass.tpe + else if (value.isInstanceOf[short]) ShortClass.tpe + else if (value.isInstanceOf[char]) CharClass.tpe + else if (value.isInstanceOf[int]) IntClass.tpe + else if (value.isInstanceOf[long]) LongClass.tpe + else if (value.isInstanceOf[float]) FloatClass.tpe + else if (value.isInstanceOf[double]) DoubleClass.tpe + else if (value.isInstanceOf[String]) StringClass.tpe + else if (value == null) AllRefClass.tpe + else throw new FatalError("unexpected literal value: " + value); } diff --git a/sources/scala/tools/nsc/typechecker/Contexts.scala b/sources/scala/tools/nsc/typechecker/Contexts.scala index 2ab5457fa9..85bc6e9d74 100755 --- a/sources/scala/tools/nsc/typechecker/Contexts.scala +++ b/sources/scala/tools/nsc/typechecker/Contexts.scala @@ -157,7 +157,7 @@ class Contexts: Analyzer { if (c.outer.enclClass == null) assert(false, "accessWithin(" + owner + ") " + c);//debug c = c.outer.enclClass; } - c != NoContext; + c != NoContext } /** Is `clazz' a subclass of an enclosing class? */ @@ -171,7 +171,7 @@ class Contexts: Analyzer { || (!sym.hasFlag(PRIVATE | PROTECTED)) || - accessWithin(sym.owner) && (!sym.hasFlag(LOCAL) || pre.isInstanceOf[ThisType]) + accessWithin(sym.owner) && (!sym.hasFlag(LOCAL) || pre =:= sym.owner.thisType) || (!sym.hasFlag(PRIVATE) && (superAccess || diff --git a/sources/scala/tools/nsc/typechecker/EtaExpansion.scala b/sources/scala/tools/nsc/typechecker/EtaExpansion.scala index 8ead3de9ae..3403d6f5d1 100644 --- a/sources/scala/tools/nsc/typechecker/EtaExpansion.scala +++ b/sources/scala/tools/nsc/typechecker/EtaExpansion.scala @@ -39,16 +39,16 @@ abstract class EtaExpansion: Analyzer { if (treeInfo.isPureExpr(tree)) tree else { val vname: Name = freshName(); - defs += ValDef(SYNTHETIC, vname, TypeTree(), tree); - Ident(vname) + defs += atPos(tree.pos)(ValDef(SYNTHETIC, vname, TypeTree(), tree)); + Ident(vname) setPos tree.pos } tree match { case Apply(fn, args) => - copy.Apply(tree, liftoutPrefix(fn), List.mapConserve(args)(liftout)); + copy.Apply(tree, liftoutPrefix(fn), List.mapConserve(args)(liftout)) setType null case TypeApply(fn, args) => - copy.TypeApply(tree, liftoutPrefix(fn), args) + copy.TypeApply(tree, liftoutPrefix(fn), args) setType null case Select(qual, name) => - copy.Select(tree, liftout(qual), name) + copy.Select(tree, liftout(qual), name) setSymbol NoSymbol setType null case Ident(name) => tree } @@ -60,7 +60,7 @@ abstract class EtaExpansion: Analyzer { val params = formals map (formal => ValDef(SYNTHETIC | PARAM, freshName(), TypeTree().setType(formal), EmptyTree)); val args = params map (param => Ident(param.name)); - Function(params, expand(Apply(tree, args), restpe)) + atPos(tree.pos)(Function(params, expand(Apply(tree, args), restpe))) case _ => tree } diff --git a/sources/scala/tools/nsc/typechecker/Infer.scala b/sources/scala/tools/nsc/typechecker/Infer.scala index 814d84bd9f..4ce8d7f8d8 100755 --- a/sources/scala/tools/nsc/typechecker/Infer.scala +++ b/sources/scala/tools/nsc/typechecker/Infer.scala @@ -482,35 +482,35 @@ abstract class Infer: Analyzer { * If several alternatives match `pt', take parameterless one. * Error if no or several such alternatives exist. */ - def inferExprAlternative(tree: Tree, pt: Type): unit = tryTwice { - val pre = tree.symbol.info.prefix; - val alts = tree.symbol.alternatives filter (alt => - isCompatible(pre.memberType(alt), pt)); - def improves(sym1: Symbol, sym2: Symbol): boolean = - sym2 == NoSymbol || - ((sym1.owner isSubClass sym2.owner) && - {val tp1 = pre.memberType(sym1); - val tp2 = pre.memberType(sym2); - tp2 == ErrorType || - !global.infer.isCompatible(tp2, pt) && global.infer.isCompatible(tp1, pt) || - (tp2.paramSectionCount > 0) && (tp1.paramSectionCount == 0 || specializes(tp1, tp2)) - }); - val best = ((NoSymbol: Symbol) /: alts) ((best, alt) => - if (improves(alt, best)) alt else best); - val competing = alts dropWhile (alt => best == alt || improves(best, alt)); - if (best == NoSymbol) { - tree match {//debug - case Select(qual, _) => - System.out.println("qual: " + qual + ":" + qual.tpe + " with decls " + qual.tpe.decls + " with members " + qual.tpe.members + " with members " + qual.tpe.member(newTermName("$minus"))); - case _ => + def inferExprAlternative(tree: Tree, pt: Type): unit = tree.tpe match { + case OverloadedType(pre, alts) => tryTwice { + val alts1 = alts filter (alt => isCompatible(pre.memberType(alt), pt)); + def improves(sym1: Symbol, sym2: Symbol): boolean = + sym2 == NoSymbol || + ((sym1.owner isSubClass sym2.owner) && + {val tp1 = pre.memberType(sym1); + val tp2 = pre.memberType(sym2); + tp2 == ErrorType || + !global.infer.isCompatible(tp2, pt) && global.infer.isCompatible(tp1, pt) || + (tp2.paramSectionCount > 0) && (tp1.paramSectionCount == 0 || specializes(tp1, tp2)) + }); + val best = ((NoSymbol: Symbol) /: alts1) ((best, alt) => + if (improves(alt, best)) alt else best); + val competing = alts1 dropWhile (alt => best == alt || improves(best, alt)); + if (best == NoSymbol) { + tree match {//debug + case Select(qual, _) => + System.out.println("qual: " + qual + ":" + qual.tpe + " with decls " + qual.tpe.decls + " with members " + qual.tpe.members + " with members " + qual.tpe.member(newTermName("$minus"))); + case _ => + } + typeErrorTree(tree, tree.symbol.tpe, pt) + } else if (!competing.isEmpty) { + context.ambiguousError(tree.pos, pre, best, competing.head, "expected type " + pt); + setError(tree); + () + } else { + tree.setSymbol(best).setType(pre.memberType(best)) } - typeErrorTree(tree, tree.symbol.tpe, pt) - } else if (!competing.isEmpty) { - context.ambiguousError(tree.pos, pre, best, competing.head, "expected type " + pt); - setError(tree); - () - } else { - tree.setSymbol(best).setType(pre.memberType(best)) } } @@ -522,33 +522,33 @@ abstract class Infer: Analyzer { * with pt = WildcardType. * Otherwise, if there is no best alternative, error. */ - def inferMethodAlternative(tree: Tree, undetparams: List[Symbol], argtpes: List[Type], pt: Type): unit = tryTwice { - val pre = tree.symbol.info.prefix; - if (settings.debug.value) System.out.println("infer method alt " + tree.symbol + " with alternatives " + (tree.symbol.alternatives map pre.memberType) + ", argtpes = " + argtpes + ", pt = " + pt);//debug - val alts = tree.symbol.alternatives filter (alt => - isApplicable(undetparams, pre.memberType(alt), argtpes, pt)); - def improves(sym1: Symbol, sym2: Symbol) = { - sym2 == NoSymbol || - ((sym1.owner isSubClass sym2.owner) && - specializes(pre.memberType(sym1), pre.memberType(sym2))) - } - val best = ((NoSymbol: Symbol) /: alts) ((best, alt) => - if (improves(alt, best)) alt else best); - val competing = alts dropWhile (alt => best == alt || improves(best, alt)); - if (best == NoSymbol) { - if (pt == WildcardType) { - errorTree(tree, applyErrorMsg(tree, " cannot be applied to ", argtpes, pt)) + def inferMethodAlternative(tree: Tree, undetparams: List[Symbol], argtpes: List[Type], pt: Type): unit = tree.tpe match { + case OverloadedType(pre, alts) => tryTwice { + if (settings.debug.value) System.out.println("infer method alt " + tree.symbol + " with alternatives " + (alts map pre.memberType) + ", argtpes = " + argtpes + ", pt = " + pt);//debug + val alts1 = alts filter (alt => isApplicable(undetparams, pre.memberType(alt), argtpes, pt)); + def improves(sym1: Symbol, sym2: Symbol) = { + sym2 == NoSymbol || + ((sym1.owner isSubClass sym2.owner) && + specializes(pre.memberType(sym1), pre.memberType(sym2))) + } + val best = ((NoSymbol: Symbol) /: alts1) ((best, alt) => + if (improves(alt, best)) alt else best); + val competing = alts1 dropWhile (alt => best == alt || improves(best, alt)); + if (best == NoSymbol) { + if (pt == WildcardType) { + errorTree(tree, applyErrorMsg(tree, " cannot be applied to ", argtpes, pt)) + } else { + inferMethodAlternative(tree, undetparams, argtpes, WildcardType) + } + } else if (!competing.isEmpty) { + context.ambiguousError(tree.pos, pre, best, competing.head, + "argument types " + argtpes.mkString("(", ",", ")") + + (if (pt == WildcardType) "" else " and expected result type " + pt)); + setError(tree); + () } else { - inferMethodAlternative(tree, undetparams, argtpes, WildcardType) + tree.setSymbol(best).setType(pre.memberType(best)) } - } else if (!competing.isEmpty) { - context.ambiguousError(tree.pos, pre, best, competing.head, - "argument types " + argtpes.mkString("(", ",", ")") + - (if (pt == WildcardType) "" else " and expected result type " + pt)); - setError(tree); - () - } else { - tree.setSymbol(best).setType(pre.memberType(best)) } } @@ -572,23 +572,24 @@ abstract class Infer: Analyzer { * as the number of type parameters, if it exists. * If several or none such polymorphic alternatives exist, error. */ - def inferPolyAlternative(tree: Tree, nparams: int): unit = { - val pre = tree.symbol.info.prefix; - val alts = tree.symbol.alternatives filter (alt => - alt.typeParams.length == nparams); - if (alts.isEmpty) { - errorTree(tree, - if (tree.symbol.alternatives exists (alt => alt.typeParams.length > 0)) - "wrong number of type parameters for " + treeSymTypeMsg(tree) - else treeSymTypeMsg(tree) + " does not take type parameters") - } else if (!alts.tail.isEmpty) { - context.ambiguousError(tree.pos, pre, alts.head, alts.tail.head, - "polymorphic function with " + nparams + " parameters"); - setError(tree); - () - } else { - tree.setSymbol(alts.head).setType(pre.memberType(alts.head)) - } + def inferPolyAlternatives(tree: Tree, nparams: int): unit = tree.tpe match { + case OverloadedType(pre, alts) => + val sym = tree.symbol filter (alt => alt.typeParams.length == nparams); + if (sym == NoSymbol) { + errorTree(tree, + if (alts exists (alt => alt.typeParams.length > 0)) + "wrong number of type parameters for " + treeSymTypeMsg(tree) + else treeSymTypeMsg(tree) + " does not take type parameters") + } else if (sym.hasFlag(OVERLOADED)) { + val tparams = sym.alternatives.head.typeParams; + val tpe = + PolyType(tparams, + OverloadedType(AntiPolyType(pre, tparams map (.tpe)), sym.alternatives)); + sym.setInfo(tpe); + tree.setSymbol(sym).setType(tpe); + } else { + tree.setSymbol(sym).setType(pre.memberType(sym)) + } } } } diff --git a/sources/scala/tools/nsc/typechecker/Namers.scala b/sources/scala/tools/nsc/typechecker/Namers.scala index 01dc7cbe90..5c26880563 100755 --- a/sources/scala/tools/nsc/typechecker/Namers.scala +++ b/sources/scala/tools/nsc/typechecker/Namers.scala @@ -121,7 +121,7 @@ trait Namers: Analyzer { } def finish = finishWith(List()); - if (tree.symbol == null || tree.symbol == NoSymbol) { + if (tree.symbol == NoSymbol) { val owner = context.owner; tree match { case PackageDef(name, stats) => @@ -151,14 +151,16 @@ trait Namers: Analyzer { enterInScope(getter); if ((mods & MUTABLE) != 0) { val setter = owner.newMethod(tree.pos, nme.SETTER_NAME(name)) - .setFlag(accmods).setInfo(innerNamer.setterTypeCompleter(tree)); + .setFlag(accmods & ~STABLE).setInfo(innerNamer.setterTypeCompleter(tree)); enterInScope(setter) } tree.symbol = - if ((mods & DEFERRED) == 0) - owner.newValue(tree.pos, name) - .setFlag(mods & FieldFlags | PRIVATE | LOCAL).setInfo(innerNamer.typeCompleter(tree)) - else getter; + if ((mods & DEFERRED) == 0) + enterInScope( + owner.newValue(tree.pos, nme.LOCAL_NAME(name)) + .setFlag(mods & FieldFlags | PRIVATE | LOCAL) + .setInfo(innerNamer.typeCompleter(tree))) + else getter; } else { tree.symbol = enterInScope(owner.newValue(tree.pos, name).setFlag(mods)); diff --git a/sources/scala/tools/nsc/typechecker/TreeCheckers.scala b/sources/scala/tools/nsc/typechecker/TreeCheckers.scala index fe56b35ea3..907275bc2d 100644 --- a/sources/scala/tools/nsc/typechecker/TreeCheckers.scala +++ b/sources/scala/tools/nsc/typechecker/TreeCheckers.scala @@ -11,6 +11,8 @@ abstract class TreeCheckers extends Analyzer { import global._; + val tpeOfTree = new scala.collection.mutable.HashMap[Tree, Type]; + def checkTrees: unit = { System.out.println("[consistency check at start of phase " + phase + "]"); for (val unit <- units) check(unit); @@ -21,7 +23,11 @@ abstract class TreeCheckers extends Analyzer { reporter.prompt(true); val context = startContext.make(unit); context.checking = true; - new TreeChecker(context).transformExpr(unit.body); + tpeOfTree.clear; + val checker = new TreeChecker(context); + checker.precheck.traverse(unit.body); + checker.transformExpr(unit.body); + checker.postcheck.traverse(unit.body); reporter.prompt(curPrompt); } @@ -32,23 +38,47 @@ abstract class TreeCheckers extends Analyzer { import infer._; override def transform(tree: Tree, mode: int, pt: Type): Tree = { - System.out.println("**** checking " + tree);//debug - if (tree.pos == Position.NOPOS) - error(tree.pos, "tree without position: " + tree) - else if (phase.id > typeCheckPhase.id) - if (tree.tpe == null) - error(tree.pos, "tree without type: " + tree); - else { - val oldtpe = tree.tpe; - tree.tpe = null; + //System.out.println("**** checking " + tree);//debug + tree match { + case EmptyTree | TypeTree() => + ; + case _ => + if (!tpeOfTree.contains(tree)) { + tpeOfTree.update(tree, tree.tpe); + tree.tpe = null + } val newtree = super.transform(tree, mode, pt); if (newtree ne tree) - error(tree.pos, "trees differ\n old: " + tree + "\n new: " + newtree); - else if (!(oldtpe =:= newtree.tpe)) - error(tree.pos, "types differ\n old: " + oldtpe + "\n new: " + newtree.tpe); - tree.tpe = oldtpe - } + error(tree.pos, "trees differ\n old: " + tree + " [" + tree.getClass() + "]\n new: " + + newtree + " [" + newtree.getClass() + "]"); + } tree } + + object precheck extends Traverser { + override def traverse(tree: Tree): unit = { + if (tree.pos == Position.NOPOS) + error(tree.pos, "tree without position: " + tree) + else if (tree.tpe == null && phase.id >= typeCheckPhase.id) + error(tree.pos, "tree without type: " + tree) + } + } + + object postcheck extends Traverser { + override def traverse(tree: Tree): unit = tree match { + case EmptyTree | TypeTree() => + ; + case _ => + tpeOfTree.get(tree) match { + case Some(oldtpe) => + if (!(oldtpe =:= tree.tpe)) + error(tree.pos, "types differ\n old: " + oldtpe + "\n new: " + tree.tpe + + "\n tree: " + tree); + tree.tpe = oldtpe; + super.traverse(tree) + case None => + } + } + } } } diff --git a/sources/scala/tools/nsc/typechecker/Typers.scala b/sources/scala/tools/nsc/typechecker/Typers.scala index 685e6837f2..c0fa939ba8 100755 --- a/sources/scala/tools/nsc/typechecker/Typers.scala +++ b/sources/scala/tools/nsc/typechecker/Typers.scala @@ -86,6 +86,9 @@ abstract class Typers: Analyzer { // of a type application. When set we do not // decompose PolyTypes. + private val SUPERCONSTRmode = 0x100;// Set for the `super' in a superclass constructor call + // super.<init> + private val stickyModes: int = EXPRmode | PATTERNmode | TYPEmode; /** Report a type error. @@ -182,22 +185,26 @@ abstract class Typers: Analyzer { }) } - private def literalType(value: Any): Type = - if (value.isInstanceOf[unit]) UnitClass.tpe - else if (value.isInstanceOf[boolean]) BooleanClass.tpe - else if (value.isInstanceOf[byte]) ByteClass.tpe - else if (value.isInstanceOf[short]) ShortClass.tpe - else if (value.isInstanceOf[char]) CharClass.tpe - else if (value.isInstanceOf[int]) IntClass.tpe - else if (value.isInstanceOf[long]) LongClass.tpe - else if (value.isInstanceOf[float]) FloatClass.tpe - else if (value.isInstanceOf[double]) DoubleClass.tpe - else if (value.isInstanceOf[String]) StringClass.tpe - else if (value == null) AllRefClass.tpe - else throw new FatalError("unexpected literal value: " + value); + /** Post-process an identifier or selection node, performing the following: + * (1) Check that non-function pattern expressions are stable + * (2) Check that packages and static modules are not used as values + * (3) Turn tree type into stable type if possible and required by context. */ + private def stabilize(tree: Tree, pre: Type, mode: int, pt: Type): Tree = { + if (tree.symbol.hasFlag(OVERLOADED) && (mode & FUNmode) == 0) + inferExprAlternative(tree, pt); + if ((mode & (PATTERNmode | FUNmode)) == PATTERNmode && tree.isTerm) // (1) + checkStable(tree) + else if ((mode & (EXPRmode | QUALmode)) == EXPRmode && !tree.symbol.isValue) // (2) + errorTree(tree, tree.symbol.toString() + " is not a value"); + else if (tree.symbol.isStable && pre.isStable && tree.tpe.symbol != ByNameParamClass && + (pt.isStable || (mode & QUALmode) != 0 || tree.symbol.isModule)) // (3) + tree.setType(singleType(pre, tree.symbol)) + else tree + } /** Perform the following adaptations of expression, pattern or type `tree' wrt to * given mode `mode' and given prototype `pt': + * (0) Convert expressions with constant types to literals * (1) Resolve overloading, unless mode contains FUNmode * (2) Apply parameterless functions * (3) Apply polymorphic types to fresh instances of their type parameters and @@ -226,30 +233,31 @@ abstract class Typers: Analyzer { */ // def adapt(tree: Tree, mode: int, pt: Type): Tree = { private def adapt(tree: Tree, mode: int, pt: Type): Tree = tree.tpe match { + case ConstantType(base, value) if (constfold.fold(tree, value) != tree) => // (0) + adapt(constfold.fold(tree, value), mode, pt) + case PolyType(List(), restp @ ConstantType(base, value)) => // (0) + adapt(constfold.fold(tree, value), mode, pt) case OverloadedType(pre, alts) if ((mode & FUNmode) == 0) => // (1) inferExprAlternative(tree, pt); adapt(tree, mode, pt) case PolyType(List(), restpe) => // (2) - transform(constfold(tree.setType(restpe)), mode, pt); + adapt(tree setType restpe, mode, pt); case TypeRef(_, sym, List(arg)) if ((mode & EXPRmode) != 0 && sym == ByNameParamClass) => // (2) adapt(tree setType arg, mode, pt); case PolyType(tparams, restpe) if ((mode & TAPPmode) == 0) => // (3) - if (tree.symbol != null) { - if (settings.debug.value) System.out.println("adapting " + tree + " " + tree.symbol.tpe + " " + tree.symbol.getClass() + " " + tree.symbol.hasFlag(CASE));//debug - } + if (settings.debug.value && tree.symbol != null) System.out.println("adapting " + tree + " " + tree.symbol.tpe + " " + tree.symbol.getClass() + " " + tree.symbol.hasFlag(CASE));//debug val tparams1 = cloneSymbols(tparams); val tree1 = if (tree.isType) tree else TypeApply(tree, tparams1 map (tparam => - TypeTree() setPos tparam.pos setType tparam.tpe)) setPos tree.pos; + TypeTree() setPos tree.pos setType tparam.tpe)) setPos tree.pos; context.undetparams = context.undetparams ::: tparams1; adapt(tree1 setType restpe.substSym(tparams, tparams1), mode, pt) case mt: ImplicitMethodType if ((mode & (EXPRmode | FUNmode)) == EXPRmode) => // (4.1) transform(applyImplicitArgs(tree), mode, pt) case mt: MethodType if ((mode & (EXPRmode | FUNmode)) == EXPRmode && isCompatible(tree.tpe, pt)) => // (4.2) - val meth = treeInfo.methSymbol(tree); - if (meth.isConstructor) errorTree(tree, "missing arguments for " + meth) + if (tree.symbol.isConstructor) errorTree(tree, "missing arguments for " + tree.symbol) else transform(etaExpand(tree), mode, pt) case _ => if (tree.isType) { @@ -281,7 +289,7 @@ abstract class Typers: Analyzer { } } else if ((mode & FUNmode) != 0) { tree - } else if (tree.symbol != null && !tree.symbol.unsafeTypeParams.isEmpty) { // (7) + } else if (tree.hasSymbol && !tree.symbol.unsafeTypeParams.isEmpty) { // (7) errorTree(tree, "" + clazz + " takes type parameters"); } else tree match { // (6) case TypeTree() => tree @@ -289,25 +297,24 @@ abstract class Typers: Analyzer { } } else if ((mode & (EXPRmode | FUNmode)) == (EXPRmode | FUNmode) && ((mode & TAPPmode) == 0 || tree.tpe.typeParams.isEmpty) && - tree.tpe.member(nme.apply).filter(m => m.tpe.paramSectionCount > 0) - != NoSymbol) { // (8) - transform(Select(tree, nme.apply), mode, pt) + tree.tpe.member(nme.apply).filter(m => m.tpe.paramSectionCount > 0) != NoSymbol) { // (8) + transform(Select(tree, nme.apply) setPos tree.pos, mode, pt) } else if (!context.undetparams.isEmpty & (mode & POLYmode) == 0) { // (9) val tparams = context.undetparams; context.undetparams = List(); inferExprInstance(tree, tparams, pt); tree } else if (tree.tpe <:< pt) { - tree + tree } else { val tree1 = constfold(tree, pt); // (10) (11) - if (tree1 != tree) transform(tree1, mode, pt); + if (tree1 != tree) adapt(tree1, mode, pt); else { if ((mode & (EXPRmode | FUNmode)) == EXPRmode) { assert(pt != null); assert(tree1.tpe != null, tree1); if (pt.symbol == UnitClass && tree1.tpe <:< AnyClass.tpe) // (12) - return transform(Block(List(tree), Literal(())), mode, pt) + return transform(atPos(tree.pos)(Block(List(tree), Literal(()))), mode, pt) else if (context.reportGeneralErrors) { // (13); the condition prevents chains of views val coercion = inferView(tree.pos, tree.tpe, pt, true); if (coercion != EmptyTree) @@ -337,10 +344,10 @@ abstract class Typers: Analyzer { var mixins = templ.parents.tail map transformType; // If first parent is trait, make it first mixin and add its superclass as first parent if (supertpt.tpe.symbol != null && supertpt.tpe.symbol.initialize.isTrait) { - mixins = supertpt :: mixins; - supertpt = gen.TypeTree(supertpt.tpe.parents(0)) setPos supertpt.pos; + mixins = transformType(supertpt) :: mixins; + supertpt = gen.TypeTree(supertpt.tpe.parents.head) setPos supertpt.pos; } - if (supertpt.symbol != null) { + if (supertpt.hasSymbol) { val tparams = supertpt.symbol.typeParams; if (!tparams.isEmpty) { val constr @ DefDef(_, _, _, vparamss, _, Apply(_, superargs)) = @@ -428,27 +435,39 @@ abstract class Typers: Analyzer { } def addGetterSetter(stat: Tree): List[Tree] = stat match { - case vd @ ValDef(mods, _, _, _) if (mods & PRIVATE) == 0 => - def setter: DefDef = { - val sym = vd.symbol; - val setter = sym.owner.info.decls.lookup(nme.SETTER_NAME(sym.name)).suchThat(.hasFlag(ACCESSOR)); - atPos(vd.pos)(gen.DefDef( - setter, vparamss => gen.Assign(gen.mkRef(vparamss.head.head), gen.mkRef(sym)))); - } - def getter: DefDef = { - val sym = vd.symbol; - val getter = sym.owner.info.decls.lookup(sym.name).suchThat(.hasFlag(ACCESSOR)); - val result = atPos(vd.pos)(gen.DefDef(getter, vparamss => gen.mkRef(sym))); + case ValDef(mods, name, tpe, rhs) if (mods & PRIVATE) == 0 => + val vdef = copy.ValDef(stat, mods | PRIVATE | LOCAL, nme.LOCAL_NAME(name), tpe, rhs); + val getter: DefDef = { + val sym = vdef.symbol; + val getter = sym.owner.info.decls.lookup(name).suchThat(.hasFlag(ACCESSOR)); + val result = atPos(vdef.pos)( + gen.DefDef(getter, vparamss => + if ((mods & DEFERRED) != 0) EmptyTree + else stabilize(gen.mkRef(sym), sym.owner.thisType, EXPRmode, sym.tpe.deconst))); checkNoEscaping.privates(result.symbol, result.tpt); result } - if ((mods & MUTABLE) != 0) List(stat, getter, setter) else List(stat, getter) + def setter: DefDef = { + val sym = vdef.symbol; + val setter = sym.owner.info.decls.lookup(nme.SETTER_NAME(name)).suchThat(.hasFlag(ACCESSOR)); + atPos(vdef.pos)( + gen.DefDef(setter, vparamss => + if ((mods & DEFERRED) != 0) EmptyTree + else transformExpr(Assign(gen.mkRef(getter.symbol), gen.mkRef(vparamss.head.head))))) + } + val gs = if ((mods & MUTABLE) != 0) List(getter, setter) else List(getter); + if ((mods & DEFERRED) != 0) gs else vdef :: gs + case DocDef(comment, defn) => + addGetterSetter(defn) map (stat => DocDef(comment, stat)) + case Attributed(attr, defn) => + addGetterSetter(defn) map (stat => Attributed(attr.duplicate, stat)) case _ => List(stat) } def transformTemplate(templ: Template): Template = { - templ setSymbol context.owner.newLocalDummy(templ.pos); + if (templ.symbol == NoSymbol) + templ setSymbol context.owner.newLocalDummy(templ.pos); val parents1 = parentTypes(templ); val selfType = if (context.owner.isAnonymousClass) @@ -465,7 +484,8 @@ abstract class Typers: Analyzer { var tpt1 = checkNoEscaping.privates(sym, transformType(vdef.tpt)); val rhs1 = if (vdef.rhs.isEmpty) vdef.rhs - else newTyper(context.make(vdef, sym)).transform(vdef.rhs, EXPRmode, tpt1.tpe.deconst); + else constfold( + newTyper(context.make(vdef, sym)).transform(vdef.rhs, EXPRmode, tpt1.tpe.deconst)); copy.ValDef(vdef, vdef.mods, vdef.name, tpt1, rhs1) setType NoType } @@ -581,7 +601,7 @@ abstract class Typers: Analyzer { context = context.makeNewImport(imp); EmptyTree case _ => - (if (!stat.isDef && exprOwner != context.owner) + (if (exprOwner != context.owner && (!stat.isDef || stat.isInstanceOf[LabelDef])) newTyper(context.make(stat, exprOwner)) else this).transformExpr(stat) } } @@ -597,7 +617,7 @@ abstract class Typers: Analyzer { def transformTypeApply(fun: Tree, args: List[Tree]): Tree = fun.tpe match { case OverloadedType(pre, alts) => - inferPolyAlternative(fun, args.length); + inferPolyAlternatives(fun, args.length); transformTypeApply(fun, args) case PolyType(tparams, restpe) if (tparams.length != 0) => if (tparams.length == args.length) { @@ -636,9 +656,7 @@ abstract class Typers: Analyzer { case MethodType(_, rtp) if ((mode & PATTERNmode) != 0) => rtp case _ => tp } - val tree1 = copy.Apply(tree, fun, args1).setType(ifPatternSkipFormals(restpe)); - val tree2 = constfold(tree1); - if (tree1 == tree2) tree2 else transform(tree2, mode, pt) + constfold(copy.Apply(tree, fun, args1).setType(ifPatternSkipFormals(restpe))) } else { assert((mode & PATTERNmode) == 0); // this case cannot arise for patterns val lenientTargs = protoTypeArgs(tparams, formals, restpe, pt); @@ -694,7 +712,15 @@ abstract class Typers: Analyzer { * `qual' is already attributed. */ def transformSelect(qual: Tree, name: Name): Tree = { - val sym = qual.tpe.member(name); + val sym = + if (tree.symbol != NoSymbol) { + val alts = qual.tpe.member(name).alternatives; + if (alts.filter(tree.symbol.==).isEmpty) + assert(false, "symbol " + tree.symbol + " not in " + alts); + tree.symbol; + } else { + qual.tpe.member(name) + } if (sym == NoSymbol && qual.isTerm && (qual.symbol == null || qual.symbol.isValue)) { val coercion = inferView(qual.pos, qual.tpe, name, true); if (coercion != EmptyTree) @@ -711,7 +737,7 @@ abstract class Typers: Analyzer { case Select(_, _) => copy.Select(tree, qual, name) case SelectFromTypeTree(_, _) => copy.SelectFromTypeTree(tree, qual, name); } - stabilize(checkAccessible(tree1, sym, qual.tpe, qual), qual.tpe) + stabilize(checkAccessible(tree1, sym, qual.tpe, qual), qual.tpe, mode, pt); } } @@ -725,104 +751,84 @@ abstract class Typers: Analyzer { def ambiguousError(msg: String) = error(tree.pos, "reference to " + name + " is ambiguous;\n" + msg); - var defSym: Symbol = NoSymbol; // the directly found symbol - var defEntry: ScopeEntry = null; // the scope entry of defSym, if defined in a local scope + var defSym: Symbol = tree.symbol; // the directly found symbol var pre: Type = NoPrefix; // the prefix type of defSym, if a class member + var qual: Tree = EmptyTree; // the qualififier tree if transformed tree is a select - var cx = context; - while (defSym == NoSymbol && cx != NoContext) { - pre = cx.enclClass.owner.thisType; - defEntry = cx.scope.lookupEntry(name); - if (defEntry != null) - defSym = defEntry.sym - else { - cx = cx.enclClass; - defSym = pre.member(name) filter (sym => context.isAccessible(sym, pre, false)); - if (defSym == NoSymbol) cx = cx.outer; + if (defSym == NoSymbol) { + var defEntry: ScopeEntry = null; // the scope entry of defSym, if defined in a local scope + + var cx = context; + while (defSym == NoSymbol && cx != NoContext) { + pre = cx.enclClass.owner.thisType; + defEntry = cx.scope.lookupEntry(name); + if (defEntry != null) + defSym = defEntry.sym + else { + cx = cx.enclClass; + defSym = pre.member(name) filter (sym => context.isAccessible(sym, pre, false)); + if (defSym == NoSymbol) cx = cx.outer; + } + } + val symDepth = if (defEntry == null) cx.depth + else cx.depth - (cx.scope.nestingLevel - defEntry.owner.nestingLevel); + var impSym: Symbol = NoSymbol; // the imported symbol + var imports = context.imports; // impSym != NoSymbol => it is imported from imports.head + while (impSym == NoSymbol && !imports.isEmpty && imports.head.depth > symDepth) { + impSym = imports.head.importedSymbol(name); + if (impSym == NoSymbol) imports = imports.tail; } - } - val symDepth = if (defEntry == null) cx.depth - else cx.depth - (cx.scope.nestingLevel - defEntry.owner.nestingLevel); - var impSym: Symbol = NoSymbol; // the imported symbol - var imports = context.imports; // impSym != NoSymbol => it is imported from imports.head - while (impSym == NoSymbol && !imports.isEmpty && imports.head.depth > symDepth) { - impSym = imports.head.importedSymbol(name); - if (impSym == NoSymbol) imports = imports.tail; - } - - // detect ambiguous definition/import, - // update `defSym' to be the final resolved symbol, - // update `pre' to be `sym's prefix type in case it is an imported member, - // and compute value of: - var qual: Tree = EmptyTree; // the qualififier tree if transformed tree is a select - // imported symbols take precedence over external package-owned symbols (hack?) - if (defSym.tpe != NoType && impSym.tpe != NoType && defSym.isExternal && defSym.owner.isPackageClass) - defSym = NoSymbol; - - if (defSym.tpe != NoType) { - if (impSym.tpe != NoType) - ambiguousError( - "it is both defined in " + defSym.owner + - " and imported subsequently by \n" + imports.head); - else if (defSym.owner.isClass && !defSym.owner.isPackageClass && !defSym.isTypeParameter) - qual = atPos(tree.pos)(gen.mkQualifier(pre)); - else - pre = NoPrefix; - } else { - if (impSym.tpe != NoType) { - var impSym1 = NoSymbol; - var imports1 = imports.tail; - def ambiguousImportError = ambiguousError( - "it is imported twice in the same scope by\n" + imports.head + "\nand " + imports1.head); - while (!imports1.isEmpty && imports1.head.depth == imports.head.depth) { - var impSym1 = imports1.head.importedSymbol(name); - if (impSym1 != NoSymbol) { - if (imports1.head.isExplicitImport(name)) { - if (imports.head.isExplicitImport(name)) ambiguousImportError; - impSym = impSym1; - imports = imports1; - } else if (!imports.head.isExplicitImport(name)) ambiguousImportError + // detect ambiguous definition/import, + // update `defSym' to be the final resolved symbol, + // update `pre' to be `sym's prefix type in case it is an imported member, + // and compute value of: + + // imported symbols take precedence over external package-owned symbols (hack?) + if (defSym.tpe != NoType && impSym.tpe != NoType && defSym.isExternal && defSym.owner.isPackageClass) + defSym = NoSymbol; + + if (defSym.tpe != NoType) { + if (impSym.tpe != NoType) + ambiguousError( + "it is both defined in " + defSym.owner + + " and imported subsequently by \n" + imports.head); + else if (defSym.owner.isClass && !defSym.owner.isPackageClass && !defSym.isTypeParameter) + qual = atPos(tree.pos)(gen.mkQualifier(pre)); + else + pre = NoPrefix; + } else { + if (impSym.tpe != NoType) { + var impSym1 = NoSymbol; + var imports1 = imports.tail; + def ambiguousImportError = ambiguousError( + "it is imported twice in the same scope by\n" + imports.head + "\nand " + imports1.head); + while (!imports1.isEmpty && imports1.head.depth == imports.head.depth) { + var impSym1 = imports1.head.importedSymbol(name); + if (impSym1 != NoSymbol) { + if (imports1.head.isExplicitImport(name)) { + if (imports.head.isExplicitImport(name)) ambiguousImportError; + impSym = impSym1; + imports = imports1; + } else if (!imports.head.isExplicitImport(name)) ambiguousImportError + } + imports1 = imports1.tail; } - imports1 = imports1.tail; + defSym = impSym; + qual = imports.head.qual; + pre = qual.tpe; + } else { + System.out.println(context);//debug + System.out.println(context.imports);//debug + error(tree.pos, "not found: " + decode(name)); + defSym = context.owner.newErrorSymbol(name); } - defSym = impSym; - qual = imports.head.qual; - pre = qual.tpe; - } else { - System.out.println(context);//debug - System.out.println(context.imports);//debug - error(tree.pos, "not found: " + decode(name)); - defSym = context.owner.newErrorSymbol(name); } } - val tree1 = if (qual == EmptyTree) tree else Select(qual, name) setPos tree.pos; - stabilize(checkAccessible(tree1, defSym, pre, qual), pre); - } - - /** Post-process an identifier or selection node, performing the following: - * (1) Turn trees of constant type into literals - * (2) Check that non-function pattern expressions are stable - * (3) Check that packages and static modules are not used as values - * (4) Turn tree type into stable type if possible and required by context. */ - def stabilize(tree: Tree, pre: Type): Tree = tree.tpe match { - case ConstantType(base, value) => // (1) - Literal(value) setPos tree.pos setType tree.tpe - case PolyType(List(), restp @ ConstantType(base, value)) => // (1) - Literal(value) setPos tree.pos setType restp - case _ => - if (tree.symbol.hasFlag(OVERLOADED) && (mode & FUNmode) == 0) { - inferExprAlternative(tree, pt) - } - if ((mode & (PATTERNmode | FUNmode)) == PATTERNmode && tree.isTerm) // (2) - checkStable(tree) - else if ((mode & (EXPRmode | QUALmode)) == EXPRmode && !tree.symbol.isValue) // (3) - errorTree(tree, tree.symbol.toString() + " is not a value"); - else if (tree.symbol.isStable && pre.isStable && tree.tpe.symbol != ByNameParamClass && - (pt.isStable || (mode & QUALmode) != 0 || tree.symbol.isModule)) // (4) - tree.setType(singleType(pre, tree.symbol)) - else - tree + val tree1 = if (qual == EmptyTree) tree + else atPos(tree.pos)(Select(qual, name)); + // atPos necessary because qualifier might come from startContext + stabilize(checkAccessible(tree1, defSym, pre, qual), pre, mode, pt) } // begin transform1 @@ -906,7 +912,7 @@ abstract class Typers: Analyzer { transform( Apply( Select(qual, nme.SETTER_NAME(name)) setPos lhs.pos, - List(rhs)), mode, pt) setPos tree.pos + List(rhs)) setPos tree.pos, mode, pt) } } else if (varsym != null && varsym.isVariable) { val rhs1 = transform(rhs, EXPRmode, lhs1.tpe); @@ -934,7 +940,7 @@ abstract class Typers: Analyzer { copy.Match(tree, selector1, cases1) setType lub(cases1 map (.tpe)) case Return(expr) => - val enclFun = context.owner.enclMethod; + val enclFun = if (tree.symbol != NoSymbol) tree.symbol else context.owner.enclMethod; if (!enclFun.isMethod || enclFun.isConstructor) errorTree(tree, "return outside method definition") else if (!context.owner.hasFlag(INITIALIZED)) @@ -958,7 +964,7 @@ abstract class Typers: Analyzer { case New(tpt: Tree) => var tpt1 = transform(tpt, TYPEmode | FUNmode, WildcardType); - if (tpt1.symbol != null && !tpt1.symbol.typeParams.isEmpty) { + if (tpt1.hasSymbol && !tpt1.symbol.typeParams.isEmpty) { context.undetparams = cloneSymbols(tpt1.symbol.unsafeTypeParams); tpt1 = TypeTree() setPos tpt1.pos @@ -989,7 +995,7 @@ abstract class Typers: Analyzer { var fun1 = transform(fun, funmode, funpt); // if function is overloaded, filter all alternatives that match // number of arguments and expected result type. - if (settings.debug.value) System.out.println("trans app " + fun1 + ":" + fun1.symbol + ":" + fun1.tpe + " " + args);//debug + // if (settings.debug.value) System.out.println("trans app " + fun1 + ":" + fun1.symbol + ":" + fun1.tpe + " " + args);//DEBUG if (fun1.hasSymbol && fun1.symbol.hasFlag(OVERLOADED)) { val argtypes = args map (arg => AllClass.tpe); val pre = fun1.symbol.tpe.prefix; @@ -1002,11 +1008,13 @@ abstract class Typers: Analyzer { transformApply(fun1, args) case Super(qual, mix) => - val clazz = qualifyingClass(qual); + val clazz = if (tree.symbol != NoSymbol) tree.symbol else qualifyingClass(qual); if (clazz == NoSymbol) setError(tree) else { val owntype = - if (mix == nme.EMPTY.toTypeName) intersectionType(clazz.info.parents) + if (mix == nme.EMPTY.toTypeName) + if ((mode & SUPERCONSTRmode) != 0) clazz.info.parents.head + else intersectionType(clazz.info.parents) else { val ps = clazz.info.parents dropWhile (p => p.symbol.name != mix); if (ps.isEmpty) { @@ -1019,7 +1027,7 @@ abstract class Typers: Analyzer { } case This(qual) => - val clazz = qualifyingClass(qual); + val clazz = if (tree.symbol != NoSymbol) tree.symbol else qualifyingClass(qual); if (clazz == NoSymbol) setError(tree) else { val owntype = if (pt.isStable || (mode & QUALmode) != 0) clazz.thisType @@ -1028,12 +1036,8 @@ abstract class Typers: Analyzer { } case Select(qual @ Super(_, _), nme.CONSTRUCTOR) => - val qual1 = transform(qual, EXPRmode | QUALmode | POLYmode, WildcardType); + val qual1 = transform(qual, EXPRmode | QUALmode | POLYmode | SUPERCONSTRmode, WildcardType); // the qualifier type of a supercall constructor is its first parent class - qual1.tpe match { - case RefinedType(parents, _) => qual1.tpe = parents.head; - case _ => - } transformSelect(qual1, nme.CONSTRUCTOR); case Select(qual, name) => @@ -1051,7 +1055,7 @@ abstract class Typers: Analyzer { transformIdent(name); case Literal(value) => - tree setType ConstantType(literalType(value), value) + tree setType ConstantType(constfold.literalType(value), value) case SingletonTypeTree(ref) => val ref1 = checkStable(transform(ref, EXPRmode | QUALmode, AnyRefClass.tpe)); @@ -1079,7 +1083,7 @@ abstract class Typers: Analyzer { if (tpt1.tpe.isError) setError(tree) else if (tparams.length == args1.length) - tree setType appliedType(tpt1.tpe, args1 map (.tpe)) + TypeTree() setPos tree.pos setType appliedType(tpt1.tpe, args1 map (.tpe)) else if (tparams.length == 0) errorTree(tree, "" + tpt1.tpe + " does not take type parameters") else @@ -1089,8 +1093,10 @@ abstract class Typers: Analyzer { def transform(tree: Tree, mode: int, pt: Type): Tree = try { - if (settings.debug.value) assert(pt != null, tree);//debug - if (settings.debug.value) System.out.println("transforming " + tree);//debug + if (settings.debug.value) { + assert(pt != null, tree);//debug + //System.out.println("transforming " + tree);//DEBUG + } val tree1 = if (tree.tpe != null) tree else transform1(tree, mode, pt); if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt) } catch { @@ -1099,7 +1105,7 @@ abstract class Typers: Analyzer { setError(tree) case ex: Throwable => if (true || settings.debug.value)//!!! - System.out.println("exception when tranforming " + tree + ", pt = " + pt); + System.out.println("exception when transforming " + tree + ", pt = " + pt); throw(ex) } |