summaryrefslogtreecommitdiff
path: root/sources
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
parent57d313ef7e246b90e4b39e328da149cf3f9ff9f5 (diff)
downloadscala-a636876294747f48cf4e7add5781b270d3f01cb0.tar.gz
scala-a636876294747f48cf4e7add5781b270d3f01cb0.tar.bz2
scala-a636876294747f48cf4e7add5781b270d3f01cb0.zip
*** empty log message ***
Diffstat (limited to 'sources')
-rw-r--r--sources/scala/tools/nsc/Settings.scala4
-rw-r--r--sources/scala/tools/nsc/typechecker/Analyzer.scala1
-rwxr-xr-xsources/scala/tools/nsc/typechecker/Namers.scala255
-rwxr-xr-xsources/scala/tools/nsc/typechecker/TypeCheckers.scala1176
-rwxr-xr-xsources/scala/tools/nsc/typechecker/Typers.scala1313
5 files changed, 1371 insertions, 1378 deletions
diff --git a/sources/scala/tools/nsc/Settings.scala b/sources/scala/tools/nsc/Settings.scala
index 2b57cc3ebd..af39d7b6ad 100644
--- a/sources/scala/tools/nsc/Settings.scala
+++ b/sources/scala/tools/nsc/Settings.scala
@@ -35,7 +35,7 @@ class Settings(error: String => unit) {
val nopredefs = BooleanSetting("-nopredefs", "Compile without any implicit predefined values");
val skip = PhasesSetting ("-skip", "Skip");
val check = PhasesSetting ("-check", "Check the tree after");
- val print = PhasesSetting ("-print", "Print out program after");
+ val print = PhasesSetting ("-print", "Print out program after");
val printer = ChoiceSetting ("-printer", "Printer to use", List("text", "html"), "text");
val printfile = StringSetting ("-printfile", "file", "Specify file in which to print trees", "-");
val graph = PhasesSetting ("-graph", "Graph the program after");
@@ -152,7 +152,7 @@ class Settings(error: String => unit) {
case _ => args
}
- override def helpSyntax = name + ":<phases>";
+ override def helpSyntax = name + ":<phase>";
def contains(phasename: String): boolean =
value exists (str => phasename startsWith str)
diff --git a/sources/scala/tools/nsc/typechecker/Analyzer.scala b/sources/scala/tools/nsc/typechecker/Analyzer.scala
index 58f3aee4ba..e5797fc377 100644
--- a/sources/scala/tools/nsc/typechecker/Analyzer.scala
+++ b/sources/scala/tools/nsc/typechecker/Analyzer.scala
@@ -13,7 +13,6 @@ abstract class Analyzer
extends Contexts
with Namers
with Typers
- with TypeCheckers
with Infer
with Variances
with EtaExpansion {
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;
}
diff --git a/sources/scala/tools/nsc/typechecker/TypeCheckers.scala b/sources/scala/tools/nsc/typechecker/TypeCheckers.scala
deleted file mode 100755
index e6085ce1c1..0000000000
--- a/sources/scala/tools/nsc/typechecker/TypeCheckers.scala
+++ /dev/null
@@ -1,1176 +0,0 @@
-/* NSC -- new scala compiler
- * Copyright 2005 LAMP/EPFL
- * @author Martin Odersky
- */
-// $Id$
-package scala.tools.nsc.typechecker;
-
-import nsc.util.ListBuffer;
-import symtab.Flags._;
-import scala.tools.util.Position;
-
-/** Methods to create symbols and to enter them into scopes. */
-abstract class TypeCheckers: Analyzer {
- import global._;
- import definitions._;
- import posAssigner.atPos;
-
- var appcnt = 0;
- var idcnt = 0;
- var selcnt = 0;
- var implcnt = 0;
-
- class TypeCheckPhase(prev: Phase) extends StdPhase(prev) {
- def name = "typechecker";
- val global: TypeCheckers.this.global.type = TypeCheckers.this.global;
- def apply(unit: CompilationUnit): unit =
- unit.body = new TypeChecker(startContext.make(unit)).transformExpr(unit.body)
- }
-
- class TypeChecker(context0: Context) {
- import context0.unit;
-
- val infer = new Inferencer(context0) {
- override def isCoercible(tp: Type, pt: Type): boolean =
- context0.reportGeneralErrors && // this condition prevents chains of views
- inferView(Position.NOPOS, tp, pt, false) != EmptyTree
- }
-
- private def inferView(pos: int, from: Type, to: Type, reportAmbiguous: boolean): Tree = {
- if (settings.debug.value) System.out.println("infer view from " + from + " to " + to);//debug
- val res = inferImplicit(pos, functionType(List(from), to), true, reportAmbiguous);
- res
- }
-
- private def inferView(pos: int, from: Type, name: Name, reportAmbiguous: boolean): Tree = {
- val to = refinedType(List(WildcardType), NoSymbol);
- val psym = (if (name.isTypeName) to.symbol.newAbstractType(pos, name)
- else to.symbol.newValue(pos, name)) setInfo WildcardType;
- to.decls.enter(psym);
- inferView(pos, from, to, reportAmbiguous)
- }
-
- import infer._;
-
- object namer extends Namer(context0);
-
- var context = context0;
-
- /** Mode constants
- */
- private val NOmode = 0x000;
- private val EXPRmode = 0x001; // these 3 modes are mutually exclusive.
- private val PATTERNmode = 0x002;
- private val TYPEmode = 0x004;
-
- private val INCONSTRmode = 0x008; // orthogonal to above. When set we are
- // in the body of a constructor
-
- private val FUNmode = 0x10; // orthogonal to above. When set
- // we are looking for a method or constructor
-
- private val POLYmode = 0x020; // orthogonal to above. When set
- // expression types can be polymorphic.
-
- private val QUALmode = 0x040; // orthogonal to above. When set
- // expressions may be packages and
- // Java statics modules.
-
- private val TAPPmode = 0x080; // Set for the function/type constructor part
- // of a type application. When set we do not
- // decompose PolyTypes.
-
- private val stickyModes: int = EXPRmode | PATTERNmode | TYPEmode;
-
- /** Report a type error.
- * @param pos The position where to report the error
- * @param ex The exception that caused the error */
- def reportTypeError(pos: int, ex: TypeError): unit = {
- if (settings.debug.value) ex.printStackTrace();
- ex match {
- case CyclicReference(sym, info: TypeCompleter) =>
- info.tree match {
- case ValDef(_, _, tpt, _) if (tpt.tpe == null) =>
- error(pos, "recursive " + sym + " needs type")
- case DefDef(_, _, _, _, tpt, _) if (tpt.tpe == null) =>
- error(pos, "recursive " + sym + " needs result type")
- case _ =>
- error(pos, ex.getMessage())
- }
- case _ =>
- error(pos, ex.getMessage())
- }
- }
-
- /** Check that tree is a stable expression.
- */
- def checkStable(tree: Tree): Tree =
- if (treeInfo.isPureExpr(tree) || tree.tpe.isError) tree;
- else errorTree(tree, "stable identifier required, but " + tree + " found.");
-
- /** Check that type of given tree does not contain local or private components
- */
- object checkNoEscaping extends TypeMap {
- private var owner: Symbol = _;
- private var scope: Scope = _;
- private var badSymbol: Symbol = _;
-
- /** Check that type `tree' does not refer to private components unless itself is wrapped
- * in something private (`owner' tells where the type occurs). */
- def privates[T <: Tree](owner: Symbol, tree: T): T = {
- check(owner, EmptyScope, tree);
- }
-
- /** Check that type `tree' does not refer to entities defined in scope `scope'. */
- def locals[T <: Tree](scope: Scope, tree: T): T = check(NoSymbol, scope, tree);
-
- def check[T <: Tree](owner: Symbol, scope: Scope, tree: T): T = {
- this.owner = owner;
- this.scope = scope;
- badSymbol = NoSymbol;
- assert(tree.tpe != null, tree);//debug
- apply(tree.tpe);
- if (badSymbol == NoSymbol) tree
- else {
- error(tree.pos,
- (if (badSymbol.hasFlag(PRIVATE)) "private " else "") + badSymbol +
- " escapes its defining scope as part of type " + tree.tpe);
- setError(tree)
- }
- }
- override def apply(t: Type): Type = {
- def checkNoEscape(sym: Symbol): unit = {
- if (sym.hasFlag(PRIVATE)) {
- var o = owner;
- while (o != NoSymbol && o != sym.owner && !o.isLocal && !o.hasFlag(PRIVATE))
- o = o.owner;
- if (o == sym.owner) badSymbol = sym
- } else if (sym.owner.isTerm) {
- val e = scope.lookupEntry(sym.name);
- if (e != null && e.sym == sym && e.owner == scope) badSymbol = e.sym
- }
- }
- if (badSymbol == NoSymbol)
- t match {
- case TypeRef(_, sym, _) => checkNoEscape(sym)
- case SingleType(_, sym) => checkNoEscape(sym)
- case _ =>
- }
- mapOver(t)
- }
- }
-
- def reenterValueParams(vparamss: List[List[ValDef]]): unit =
- for (val vparams <- vparamss; val vparam <- vparams) context.scope enter vparam.symbol;
-
- def reenterTypeParams(tparams: List[AbsTypeDef]): List[Symbol] =
- for (val tparam <- tparams) yield { context.scope enter tparam.symbol; tparam.symbol }
-
- def attrInfo(attr: Tree): AttrInfo = attr match {
- case Apply(Select(New(tpt), nme.CONSTRUCTOR), args) =>
- Pair(tpt.tpe, args map {
- case Literal(value) =>
- value
- case arg =>
- error(arg.pos, "attribute argument needs to be a constant; found: " + arg);
- })
- }
-
- 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);
-
- /** Perform the following adaptations of expression, pattern or type `tree' wrt to
- * given mode `mode' and given prototype `pt':
- * (1) Resolve overloading, unless mode contains FUNmode
- * (2) Apply parameterless functions
- * (3) Apply polymorphic types to fresh instances of their type parameters and
- * store these instances in context.undetparams,
- * unless followed by explicit type application.
- * (4) Do the following to unapplied methods used as values:
- * (4.1) If the method has only implicit parameters pass implicit arguments
- * (4.2) otherwise, convert to function by eta-expansion,
- * except if the method is a constructor, in which case we issue an error.
- * (5) Convert a class type that serves as a constructor in a pattern as follows:
- * (5.1) If this type refers to a case class, set tree's type to the unique
- * instance of its primary constructor that is a subtype of the expected type.
- * (5.2) Otherwise, if this type is a subtype of scala.Seq[A], set trees' type
- * to a method type from a repeated parameter sequence type A* to the expected type.
- * (6) Convert all other types to TypeTree nodes.
- * (7) When in TYPEmode nut not FUNmode, check that types are fully parameterized
- * (8) When in both EXPRmode and FUNmode, add apply method calls to values of object type.
- * (9) If there are undetermined type variables and not POLYmode, infer expression instance
- * Then, if tree's type is not a subtype of expected type, try the following adaptations:
- * (10) If the expected type is byte, short or char, and the expression
- * is an integer fitting in the range of that type, convert it to that type.
- * (11) Widen numeric literals to their expected type, if necessary
- * (12) When in mode EXPRmode, convert E to { E; () } if expected type is Scala.unit.
- * (13) When in mode EXPRmode, apply a view
- * If all this fails, error
- */
-// def adapt(tree: Tree, mode: int, pt: Type): Tree = {
- private def adapt(tree: Tree, mode: int, pt: Type): Tree = tree.tpe match {
- 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);
- 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
- }
- 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;
- 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)
- else transform(etaExpand(tree), mode, pt)
- case _ =>
- if (tree.isType) {
- val clazz = tree.tpe.symbol;
- if ((mode & PATTERNmode) != 0) { // (5)
- if (tree.tpe.isInstanceOf[MethodType]) {
- tree // everything done already
- } else {
- clazz.initialize;
- if (clazz.hasFlag(CASE)) { // (5.1)
- val tree1 = TypeTree() setPos tree.pos
- setType
- clazz.primaryConstructor.tpe.asSeenFrom(tree.tpe.prefix, clazz.owner);
- // tree.tpe.prefix.memberType(clazz.primaryConstructor); //!!!
- inferConstructorInstance(tree1, clazz.unsafeTypeParams, pt);
- tree1
- } else if (clazz.isSubClass(SeqClass)) { // (5.2)
- pt.baseType(clazz).baseType(SeqClass) match {
- case TypeRef(pre, seqClass, args) =>
- tree.setType(MethodType(List(typeRef(pre, RepeatedParamClass, args)), pt))
- case NoType =>
- errorTree(tree, "expected pattern type " + pt +
- " does not conform to sequence " + clazz)
- }
- } else {
- System.out.println("bad: " + clazz + ":" + tree.tpe + " " + flagsToString(clazz.flags) + clazz.hasFlag(CASE));//debug
- errorTree(tree, clazz.toString() + " is neither a case class nor a sequence class")
- }
- }
- } else if ((mode & FUNmode) != 0) {
- tree
- } else if (tree.symbol != null && !tree.symbol.unsafeTypeParams.isEmpty) { // (7)
- errorTree(tree, "" + clazz + " takes type parameters");
- } else tree match { // (6)
- case TypeTree() => tree
- case _ => TypeTree() setPos tree.pos setType tree.tpe
- }
- } 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)
- } 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
- } else {
- val tree1 = constfold(tree, pt); // (10) (11)
- if (tree1 != tree) transform(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)
- else if (context.reportGeneralErrors) { // (13); the condition prevents chains of views
- val coercion = inferView(tree.pos, tree.tpe, pt, true);
- if (coercion != EmptyTree)
- return transform(Apply(coercion, List(tree)) setPos tree.pos, mode, pt);
- }
- }
- typeErrorTree(tree, tree.tpe, pt)
- }
- }
- }
-// System.out.println("adapt " + tree + ":" + tree.tpe + ", mode = " + mode + ", pt = " + pt);
-// adapt(tree, mode, pt)
-// }
-
- private def completeSuperType(supertpt: Tree, tparams: List[Symbol], vparamss: List[List[ValDef]], superargs: List[Tree]): Type = {
- tparams foreach context.scope.enter;
- new Typer(context).enterValueParams(context.owner, vparamss);
- val newTree = New(supertpt) setType
- PolyType(tparams, appliedType(supertpt.tpe, tparams map (.tpe)));
- val tree = transformExpr(atPos(supertpt.pos)(Apply(Select(newTree, nme.CONSTRUCTOR), superargs)));
- if (settings.debug.value) System.out.println("superconstr " + tree + " co = " + context.owner);//debug
- tree.tpe
- }
-
- def parentTypes(templ: Template): List[Tree] = {
- var supertpt = transform(templ.parents.head, TYPEmode | FUNmode, WildcardType);
- 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;
- }
- if (supertpt.symbol != null) {
- val tparams = supertpt.symbol.typeParams;
- if (!tparams.isEmpty) {
- val constr @ DefDef(_, _, _, vparamss, _, Apply(_, superargs)) =
- treeInfo.firstConstructor(templ.body);
- val outercontext = context.outer.outer;
- supertpt = gen.TypeTree(
- new TypeChecker(context.outer.outer.makeNewScope(constr, context.outer.outer.owner))
- .completeSuperType(
- supertpt,
- tparams,
- vparamss map (.map(.duplicate.asInstanceOf[ValDef])),
- superargs map (.duplicate))) setPos supertpt.pos;
- }
- }
- List.mapConserve(supertpt :: mixins)(tpt => checkNoEscaping.privates(context.owner, tpt))
- }
-
- /** Check that
- * - all parents are class types,
- * - first parent cluss is not a trait; following classes are traits,
- * - final classes are not inherited,
- * - sealed classes are only inherited by classes which are
- * nested within definition of base class, or that occur within same
- * statement sequence,
- * - self-type of current class is a subtype of self-type of each parent class.
- * - no two parents define same symbol.
- */
- def validateParentClasses(parents: List[Tree], selfType: Type): unit = {
- var c = context;
- do { c = c.outer } while (c.owner == context.owner);
- val defscope = c.scope;
-
- def validateParentClass(parent: Tree, isFirst: boolean): unit =
- if (!parent.tpe.isError) {
- val psym = parent.tpe.symbol.initialize;
- if (!psym.isClass)
- error(parent.pos, "class type expected");
- else if (!isFirst && !psym.isTrait)
- error(parent.pos, "" + psym + " is not a trait; cannot be used as mixin");
- else if (psym.hasFlag(FINAL))
- error(parent.pos, "illegal inheritance from final class");
- else if (psym.isSealed) {
- // are we in same scope as base type definition?
- val e = defscope.lookupEntry(psym.name);
- if (!(e.sym == psym && e.owner == defscope)) {
- // we are not within same statement sequence
- var c = context;
- while (c != NoContext && c.owner != psym) c = c.outer.enclClass;
- if (c == NoContext) error(parent.pos, "illegal inheritance from sealed class")
- }
- }
- if (!(selfType <:< parent.tpe.typeOfThis)) {
- System.out.println(context.owner);//debug
- System.out.println(context.owner.thisSym);//debug
- error(parent.pos, "illegal inheritance;\n self-type " +
- selfType + " does not conform to " + parent +
- "'s selftype " + parent.tpe.typeOfThis);
- if (settings.explaintypes.value) explainTypes(selfType, parent.tpe.typeOfThis);
- }
- if (parents exists (p => p != parent && p.tpe.symbol == psym && !psym.isError))
- error(parent.pos, "" + psym + " is inherited twice")
- }
-
- if (!parents.isEmpty) {
- validateParentClass(parents.head, true);
- for (val p <- parents.tail) validateParentClass(p, false);
- }
- }
-
- def transformClassDef(cdef: ClassDef): Tree = {
- val clazz = cdef.symbol;
- reenterTypeParams(cdef.tparams);
- val tparams1 = List.mapConserve(cdef.tparams)(transformAbsTypeDef);
- val tpt1 = checkNoEscaping.privates(clazz.thisSym, transformType(cdef.tpt));
- val impl1 = new TypeChecker(context.make(cdef.impl, clazz, new Scope()))
- .transformTemplate(cdef.impl);
- copy.ClassDef(cdef, cdef.mods, cdef.name, tparams1, tpt1, impl1) setType NoType
- }
-
- def transformModuleDef(mdef: ModuleDef): Tree = {
- val clazz = mdef.symbol.moduleClass;
- val impl1 = new TypeChecker(context.make(mdef.impl, clazz, new Scope()))
- .transformTemplate(mdef.impl);
- copy.ModuleDef(mdef, mdef.mods, mdef.name, impl1) setType NoType
- }
-
- 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)));
- checkNoEscaping.privates(result.symbol, result.tpt);
- result
- }
- if ((mods & MUTABLE) != 0) List(stat, getter, setter) else List(stat, getter)
- case _ =>
- List(stat)
- }
-
- def transformTemplate(templ: Template): Template = {
- templ setSymbol context.owner.newLocalDummy(templ.pos);
- val parents1 = parentTypes(templ);
- val selfType =
- if (context.owner.isAnonymousClass)
- refinedType(context.owner.info.parents, context.owner.owner)
- else context.owner.typeOfThis;
- validateParentClasses(parents1, selfType);
- val body1 = templ.body flatMap addGetterSetter;
- val body2 = transformStats(body1, templ.symbol);
- copy.Template(templ, parents1, body2) setType context.owner.tpe
- }
-
- def transformValDef(vdef: ValDef): ValDef = {
- val sym = vdef.symbol;
- var tpt1 = checkNoEscaping.privates(sym, transformType(vdef.tpt));
- val rhs1 =
- if (vdef.rhs.isEmpty) vdef.rhs
- else new TypeChecker(context.make(vdef, sym)).transform(vdef.rhs, EXPRmode, tpt1.tpe.deconst);
- copy.ValDef(vdef, vdef.mods, vdef.name, tpt1, rhs1) setType NoType
- }
-
- def transformDefDef(ddef: DefDef): DefDef = {
- val meth = ddef.symbol;
- reenterTypeParams(ddef.tparams);
- reenterValueParams(ddef.vparamss);
- val tparams1 = List.mapConserve(ddef.tparams)(transformAbsTypeDef);
- val vparamss1 = List.mapConserve(ddef.vparamss)(vparams1 =>
- List.mapConserve(vparams1)(transformValDef));
- var tpt1 = checkNoEscaping.privates(meth, transformType(ddef.tpt));
- val rhs1 =
- if (ddef.name == nme.CONSTRUCTOR) {
- if (!meth.hasFlag(SYNTHETIC) &&
- !(meth.owner.isClass ||
- meth.owner.isModuleClass ||
- meth.owner.isAnonymousClass ||
- meth.owner.isRefinementClass))
- error(ddef.pos, "constructor definition not allowed here " + meth.owner);//debug
- context.enclClass.owner.setFlag(INCONSTRUCTOR);
- val result = transform(ddef.rhs, EXPRmode | INCONSTRmode, UnitClass.tpe);
- context.enclClass.owner.resetFlag(INCONSTRUCTOR);
- result
- } else {
- transform(ddef.rhs, EXPRmode, tpt1.tpe);
- }
- copy.DefDef(ddef, ddef.mods, ddef.name, tparams1, vparamss1, tpt1, rhs1) setType NoType
- }
-
- def transformAbsTypeDef(tdef: AbsTypeDef): AbsTypeDef = {
- val lo1 = checkNoEscaping.privates(tdef.symbol, transformType(tdef.lo));
- val hi1 = checkNoEscaping.privates(tdef.symbol, transformType(tdef.hi));
- copy.AbsTypeDef(tdef, tdef.mods, tdef.name, lo1, hi1) setType NoType
- }
-
- def transformAliasTypeDef(tdef: AliasTypeDef): AliasTypeDef = {
- reenterTypeParams(tdef.tparams);
- val tparams1 = List.mapConserve(tdef.tparams)(transformAbsTypeDef);
- val rhs1 = checkNoEscaping.privates(tdef.symbol, transformType(tdef.rhs));
- copy.AliasTypeDef(tdef, tdef.mods, tdef.name, tparams1, rhs1) setType NoType
- }
-
- def transformLabelDef(ldef: LabelDef): LabelDef = {
- val lsym = namer.enterInScope(
- context.owner.newLabel(ldef.pos, ldef.name) setInfo MethodType(List(), UnitClass.tpe));
- val rhs1 = transform(ldef.rhs, EXPRmode, UnitClass.tpe);
- copy.LabelDef(ldef, ldef.name, ldef.params, rhs1) setType UnitClass.tpe
- }
-
- def transformBlock(block: Block, mode: int, pt: Type): Block = {
- namer.enterSyms(block.stats);
- val stats1 =
- if ((mode & INCONSTRmode) != 0) {
- val constrCall = transform(block.stats.head, mode, WildcardType);
- context.enclClass.owner.resetFlag(INCONSTRUCTOR);
- constrCall :: transformStats(block.stats.tail, context.owner);
- } else {
- transformStats(block.stats, context.owner)
- }
- val expr1 = transform(block.expr, mode & ~(FUNmode | QUALmode), pt);
- val block1 = copy.Block(block, stats1, expr1) setType expr1.tpe.deconst;
- if (block1.tpe.symbol.isAnonymousClass)
- block1 setType refinedType(block1.tpe.parents, block1.tpe.symbol.owner);
- if (isFullyDefined(pt)) block1 else checkNoEscaping.locals(context.scope, block1)
- }
-
- def transformCase(cdef: CaseDef, pattpe: Type, pt: Type): CaseDef = {
- val pat1: Tree = transform(cdef.pat, PATTERNmode, pattpe);
- val guard1: Tree = if (cdef.guard == EmptyTree) EmptyTree
- else transform(cdef.guard, EXPRmode, BooleanClass.tpe);
- val body1: Tree = transform(cdef.body, EXPRmode, pt);
- copy.CaseDef(cdef, pat1, guard1, body1) setType body1.tpe
- }
-
- def transformFunction(fun: Function, mode: int, pt: Type): Function = {
- val Triple(clazz, argpts, respt) = pt match {
- case TypeRef(_, sym, argtps)
- if (fun.vparams.length <= MaxFunctionArity && sym == FunctionClass(fun.vparams.length) ||
- sym == PartialFunctionClass && fun.vparams.length == 1 && fun.body.isInstanceOf[Match]) =>
- Triple(sym, argtps.init, argtps.last)
- case _ =>
- Triple(FunctionClass(fun.vparams.length), fun.vparams map (x => NoType), WildcardType)
- }
- val vparamSyms = List.map2(fun.vparams, argpts) { (vparam, argpt) =>
- vparam match {
- case ValDef(_, _, tpt, _) =>
- if (tpt.isEmpty)
- tpt.tpe =
- if (argpt == NoType) { error(vparam.pos, "missing parameter type"); ErrorType }
- else argpt
- }
- namer.enterSym(vparam);
- vparam.symbol
- }
- val vparams1 = List.mapConserve(fun.vparams)(transformValDef);
- val body1 = transform(fun.body, EXPRmode, respt);
- copy.Function(fun, vparams1, body1)
- setType typeRef(clazz.tpe.prefix, clazz, (vparamSyms map (.tpe)) ::: List(body1.tpe))
- }
-
- def transformRefinement(stats: List[Tree]): List[Tree] = {
- namer.enterSyms(stats);
- for (val stat <- stats) stat.symbol setFlag OVERRIDE;
- transformStats(stats, NoSymbol);
- }
-
- def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] =
- List.mapConserve(stats) { stat =>
- if (context.owner.isRefinementClass && !treeInfo.isDeclaration(stat))
- errorTree(stat, "only declarations allowed here");
- stat match {
- case imp @ Import(_, _) =>
- context = context.makeNewImport(imp);
- EmptyTree
- case _ =>
- (if (!stat.isDef && exprOwner != context.owner)
- new TypeChecker(context.make(stat, exprOwner)) else this).transformExpr(stat)
- }
- }
-
- private def transform1(tree: Tree, mode: int, pt: Type): Tree = {
-
- def funmode = mode & stickyModes | FUNmode | POLYmode;
-
- def transformCases(cases: List[CaseDef], pattp: Type): List[CaseDef] = {
- List.mapConserve(cases)(cdef =>
- new TypeChecker(context.makeNewScope(tree, context.owner)).transformCase(cdef, pattp, pt))
- }
-
- def transformTypeApply(fun: Tree, args: List[Tree]): Tree = fun.tpe match {
- case OverloadedType(pre, alts) =>
- inferPolyAlternative(fun, args.length);
- transformTypeApply(fun, args)
- case PolyType(tparams, restpe) if (tparams.length != 0) =>
- if (tparams.length == args.length) {
- val targs = args map (.tpe);
- checkBounds(tree.pos, tparams, targs, "");
- if (settings.debug.value) System.out.println("type app " + tparams + " => " + targs + " = " + restpe.subst(tparams, targs));//debug
- copy.TypeApply(tree, fun, args) setType restpe.subst(tparams, targs);
- } else {
- errorTree(tree, "wrong number of type parameters for " + treeSymTypeMsg(fun))
- }
- case ErrorType =>
- setError(tree)
- case _ =>
- System.out.println(fun.toString() + " " + args);//debug
- errorTree(tree, treeSymTypeMsg(fun) + " does not take type parameters.");
- }
-
- def transformApply(fun: Tree, args: List[Tree]): Tree = fun.tpe match {
- case OverloadedType(pre, alts) =>
- val args1 = List.mapConserve(args)(arg =>
- transform(arg, mode & stickyModes, WildcardType));
- inferMethodAlternative(fun, context.undetparams, args1 map (.tpe.deconst), pt);
- transformApply(adapt(fun, funmode, WildcardType), args1);
- case MethodType(formals0, restpe) =>
- val formals = formalTypes(formals0, args.length);
- if (formals.length != args.length) {
- System.out.println("" + formals.length + " " + args.length);
- errorTree(tree, "wrong number of arguments for " + treeSymTypeMsg(fun))
- } else {
- val tparams = context.undetparams;
- context.undetparams = List();
- if (tparams.isEmpty) {
- val args1 = List.map2(args, formals) ((arg, formal) =>
- transform(arg, mode & stickyModes, formal));
- def ifPatternSkipFormals(tp: Type) = tp match {
- 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)
- } else {
- assert((mode & PATTERNmode) == 0); // this case cannot arise for patterns
- val lenientTargs = protoTypeArgs(tparams, formals, restpe, pt);
- val strictTargs = List.map2(lenientTargs, tparams)((targ, tparam) =>
- if (targ == WildcardType) tparam.tpe else targ);
- def transformArg(tree: Tree, formal: Type): Tree = {
- val lenientPt = formal.subst(tparams, lenientTargs);
- val tree1 = transform(tree, mode & stickyModes | POLYmode, lenientPt);
- val argtparams = context.undetparams;
- context.undetparams = List();
- if (!argtparams.isEmpty) {
- val strictPt = formal.subst(tparams, strictTargs);
- inferArgumentInstance(tree1, argtparams, strictPt, lenientPt);
- }
- tree1
- }
- val args1 = List.map2(args, formals)(transformArg);
- if (args1 exists (.tpe.isError)) setError(tree)
- else {
- if (settings.debug.value) System.out.println("infer method inst " + fun + ", tparams = " + tparams + ", args = " + args1.map(.tpe) + ", pt = " + pt + ", lobounds = " + tparams.map(.tpe.bounds.lo));//debug
- val undetparams = inferMethodInstance(fun, tparams, args1, pt);
- val result = transformApply(fun, args1);
- context.undetparams = undetparams;
- result
- }
- }
- }
- case ErrorType =>
- setError(tree)
- }
-
- /** The qualifying class of a this or super with prefix `qual' */
- def qualifyingClass(qual: Name): Symbol = {
- if (qual == nme.EMPTY.toTypeName) {
- val clazz = context.enclClass.owner;
- if (!clazz.isPackageClass) clazz
- else {
- error(tree.pos, "" + tree + " can be used only in a class, object, or template");
- NoSymbol
- }
- } else {
- var c = context.enclClass;
- while (c != NoContext && c.owner.name != qual) c = c.outer.enclClass;
- if (c != NoContext) c.owner
- else {
- error(tree.pos, "" + qual + " is not an enclosing class");
- NoSymbol
- }
- }
- }
-
- /** Attribute a selection where `tree' is `qual.name'.
- * `qual' is already attributed.
- */
- def transformSelect(qual: Tree, name: Name): Tree = {
- val sym = 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)
- return transform(
- copy.Select(tree, Apply(coercion, List(qual)) setPos qual.pos, name), mode, pt)
- }
- if (sym.info == NoType) {
- System.out.println(qual);
- System.out.println(qual.tpe.members);//debug
- System.out.println(qual.tpe.member(name));//debug
- errorTree(tree, decode(name) + " is not a member of " + qual.tpe.widen)
- } else {
- val tree1 = tree match {
- case Select(_, _) => copy.Select(tree, qual, name)
- case SelectFromTypeTree(_, _) => copy.SelectFromTypeTree(tree, qual, name);
- }
- stabilize(checkAccessible(tree1, sym, qual.tpe, qual), qual.tpe)
- }
- }
-
- /** Attribute an identifier consisting of a simple name or an outer reference.
- * @param tree The tree representing the identifier.
- * @param name The name of the identifier.
- * Transformations: (1) Prefix class members with this.
- * (2) Change imported symbols to selections
- */
- def transformIdent(name: Name): Tree = {
- 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 pre: Type = NoPrefix; // the prefix type of defSym, if a class member
-
- 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;
- }
-
- // 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
- }
- 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);
- }
- }
- 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
- }
-
- // begin transform1
- val sym: Symbol = tree.symbol;
- if (sym != null) sym.initialize;
- //if (settings.debug.value && tree.isDef) global.log("transforming definition of " + sym);//DEBUG
- tree match {
- case PackageDef(name, stats) =>
- val stats1 = new TypeChecker(context.make(tree, sym.moduleClass, sym.info.decls))
- .transformStats(stats, NoSymbol);
- copy.PackageDef(tree, name, stats1) setType NoType
-
- case cdef @ ClassDef(_, _, _, _, _) =>
- new TypeChecker(context.makeNewScope(tree, sym)).transformClassDef(cdef)
-
- case mdef @ ModuleDef(_, _, _) =>
- transformModuleDef(mdef)
-
- case vdef @ ValDef(_, _, _, _) =>
- transformValDef(vdef)
-
- case ddef @ DefDef(_, _, _, _, _, _) =>
- new TypeChecker(context.makeNewScope(tree, sym)).transformDefDef(ddef)
-
- case tdef @ AbsTypeDef(_, _, _, _) =>
- transformAbsTypeDef(tdef)
-
- case tdef @ AliasTypeDef(_, _, _, _) =>
- new TypeChecker(context.makeNewScope(tree, sym)).transformAliasTypeDef(tdef)
-
- case ldef @ LabelDef(_, List(), _) =>
- new TypeChecker(context.makeNewScope(tree, context.owner)).transformLabelDef(ldef)
-
- case Attributed(attr, defn) =>
- val attr1 = transform(attr, EXPRmode, AttributeClass.tpe);
- val defn1 = transform(defn, mode, pt);
- val existing = attributes.get(defn1.symbol) match {
- case None => List()
- case Some(attrs) => attrs
- }
- attributes(defn1.symbol) = attrInfo(attr1) :: existing;
- defn1
-
- case DocDef(comment, defn) =>
- transform(defn, mode, pt);
-
- case block @ Block(_, _) =>
- new TypeChecker(context.makeNewScope(tree, context.owner))
- .transformBlock(block, mode, pt)
-
- case Sequence(elems) =>
- val elems1 = List.mapConserve(elems)(elem => transform(elem, mode, pt));
- copy.Sequence(tree, elems1) setType pt
-
- case Alternative(alts) =>
- val alts1 = List.mapConserve(alts)(alt => transform(alt, mode, pt));
- copy.Alternative(tree, alts1) setType pt
-
- case Bind(name, body) =>
- val body1 = transform(body, mode, pt);
- val vble = context.owner.newValue(tree.pos, name).setInfo(
- if (treeInfo.isSequenceValued(body)) seqType(pt) else body1.tpe);
- //todo: check whether we can always use body1.tpe
- namer.enterInScope(vble);
- copy.Bind(tree, name, body1) setSymbol vble setType pt
-
- case fun @ Function(_, _) =>
- new TypeChecker(context.makeNewScope(tree, context.owner))
- .transformFunction(fun, mode, pt)
-
- case Assign(lhs, rhs) =>
- def isGetter(sym: Symbol) = sym.info match {
- case PolyType(List(), _) => sym.owner.isClass && !sym.isStable
- case _ => false
- }
- val lhs1 = transformExpr(lhs);
- val varsym = lhs1.symbol;
- if (varsym != null && isGetter(varsym)) {
- lhs1 match {
- case Select(qual, name) =>
- transform(
- Apply(
- Select(qual, nme.SETTER_NAME(name)) setPos lhs.pos,
- List(rhs)), mode, pt) setPos tree.pos
- }
- } else if (varsym != null && varsym.isVariable) {
- val rhs1 = transform(rhs, EXPRmode, lhs1.tpe);
- copy.Assign(tree, lhs1, rhs1) setType UnitClass.tpe;
- } else {
- System.out.println("" + lhs1 + " " + varsym + " " + flagsToString(varsym.flags));//debug
- if (!lhs1.tpe.isError) error(tree.pos, "assignment to non-variable ");
- setError(tree)
- }
-
- case If(cond, thenp, elsep) =>
- val cond1 = transform(cond, EXPRmode, BooleanClass.tpe);
- if (elsep.isEmpty) {
- val thenp1 = transform(thenp, EXPRmode, UnitClass.tpe);
- copy.If(tree, cond1, thenp1, elsep) setType UnitClass.tpe
- } else {
- val thenp1 = transform(thenp, EXPRmode, pt);
- val elsep1 = transform(elsep, EXPRmode, pt);
- copy.If(tree, cond1, thenp1, elsep1) setType lub(List(thenp1.tpe, elsep1.tpe));
- }
-
- case Match(selector, cases) =>
- val selector1 = transformExpr(selector);
- val cases1 = transformCases(cases, selector1.tpe);
- copy.Match(tree, selector1, cases1) setType lub(cases1 map (.tpe))
-
- case Return(expr) =>
- val enclFun = context.owner.enclMethod;
- if (!enclFun.isMethod || enclFun.isConstructor)
- errorTree(tree, "return outside method definition")
- else if (!context.owner.hasFlag(INITIALIZED))
- errorTree(tree, "method " + context.owner + " has return statement; needs result type")
- else {
- val expr1: Tree = transform(expr, EXPRmode, enclFun.tpe.resultType);
- copy.Return(tree, expr1) setSymbol enclFun setType AllClass.tpe;
- }
-
- case Try(block, catches, finalizer) =>
- val block1 = transform(block, EXPRmode, pt);
- val catches1 = transformCases(catches, ThrowableClass.tpe);
- val finalizer1 = if (finalizer.isEmpty) finalizer
- else transform(finalizer, EXPRmode, UnitClass.tpe);
- copy.Try(tree, block1, catches1, finalizer1)
- setType lub(block1.tpe :: (catches1 map (.tpe)))
-
- case Throw(expr) =>
- val expr1 = transform(expr, EXPRmode, ThrowableClass.tpe);
- copy.Throw(tree, expr1) setType AllClass.tpe
-
- case New(tpt: Tree) =>
- var tpt1 = transform(tpt, TYPEmode | FUNmode, WildcardType);
- if (tpt1.symbol != null && !tpt1.symbol.typeParams.isEmpty) {
- context.undetparams = cloneSymbols(tpt1.symbol.unsafeTypeParams);
- tpt1 = TypeTree()
- setPos tpt1.pos
- setType appliedType(tpt1.tpe, context.undetparams map (.tpe));
- }
- copy.New(tree, tpt1).setType(tpt1.tpe)
-
- case Typed(expr, tpt @ Ident(name)) if (name == nme.WILDCARD_STAR.toTypeName) =>
- val expr1 = transform(expr, mode & stickyModes, seqType(pt));
- expr1.tpe.baseType(SeqClass) match {
- case TypeRef(_, _, List(elemtp)) =>
- copy.Typed(tree, expr1, tpt setType elemtp) setType elemtp
- case _ =>
- setError(tree)
- }
- case Typed(expr, tpt) =>
- val tpt1 = transformType(tpt);
- val expr1 = transform(expr, mode & stickyModes, tpt1.tpe);
- copy.Typed(tree, expr1, tpt1) setType tpt1.tpe
-
- case TypeApply(fun, args) =>
- val args1 = List.mapConserve(args)(transformType);
- // do args first in order to maintain conext.undetparams on the function side.
- transformTypeApply(transform(fun, funmode | TAPPmode, WildcardType), args1)
-
- case Apply(fun, args) =>
- val funpt = if ((mode & PATTERNmode) != 0) pt else WildcardType;
- 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 (fun1.hasSymbol && fun1.symbol.hasFlag(OVERLOADED)) {
- val argtypes = args map (arg => AllClass.tpe);
- val pre = fun1.symbol.tpe.prefix;
- val sym = fun1.symbol filter (alt =>
- isApplicable(context.undetparams, pre.memberType(alt), argtypes, pt));
- if (sym != NoSymbol)
- fun1 = adapt(fun1 setSymbol sym setType pre.memberType(sym), funmode, WildcardType)
- }
- appcnt = appcnt + 1;
- transformApply(fun1, args)
-
- case Super(qual, mix) =>
- val clazz = qualifyingClass(qual);
- if (clazz == NoSymbol) setError(tree)
- else {
- val owntype =
- if (mix == nme.EMPTY.toTypeName) intersectionType(clazz.info.parents)
- else {
- val ps = clazz.info.parents dropWhile (p => p.symbol.name != mix);
- if (ps.isEmpty) {
- System.out.println(clazz.info.parents map (.symbol.name));//debug
- error(tree.pos, "" + mix + " does not name a base class of " + clazz);
- ErrorType
- } else ps.head
- }
- tree setSymbol clazz setType owntype
- }
-
- case This(qual) =>
- val clazz = qualifyingClass(qual);
- if (clazz == NoSymbol) setError(tree)
- else {
- val owntype = if (pt.isStable || (mode & QUALmode) != 0) clazz.thisType
- else clazz.typeOfThis;
- tree setSymbol clazz setType owntype
- }
-
- case Select(qual @ Super(_, _), nme.CONSTRUCTOR) =>
- val qual1 = transform(qual, EXPRmode | QUALmode | POLYmode, 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) =>
- selcnt = selcnt + 1;
- assert (name != nme.CONSTRUCTOR || !qual.isInstanceOf[Super], tree);//debug
- var qual1 = transform(qual, EXPRmode | QUALmode | POLYmode, WildcardType);
- if (name.isTypeName) qual1 = checkStable(qual1);
- transformSelect(qual1, name);
-
- case Ident(name) =>
- idcnt = idcnt + 1;
- if (name == nme.WILDCARD && (mode & (PATTERNmode | FUNmode)) == PATTERNmode)
- tree setType pt
- else
- transformIdent(name);
-
- case Literal(value) =>
- tree setType ConstantType(literalType(value), value)
-
- case SingletonTypeTree(ref) =>
- val ref1 = checkStable(transform(ref, EXPRmode | QUALmode, AnyRefClass.tpe));
- tree setType ref1.tpe.resultType;
-
- case SelectFromTypeTree(qual, selector) =>
- tree setType transformSelect(transformType(qual), selector).tpe
-
- case CompoundTypeTree(templ: Template) =>
- tree setType {
- val parents1 = List.mapConserve(templ.parents)(transformType);
- if (parents1 exists (.tpe.isError)) ErrorType
- else {
- val decls = new Scope();
- val self = refinedType(parents1 map (.tpe), context.enclClass.owner, decls);
- new TypeChecker(context.make(tree, self.symbol, new Scope())).transformRefinement(templ.body);
- self
- }
- }
-
- case AppliedTypeTree(tpt, args) =>
- val tpt1 = transform(tpt, mode | FUNmode | TAPPmode, WildcardType);
- val tparams = tpt1.tpe.symbol.typeParams;
- val args1 = List.mapConserve(args)(transformType);
- if (tpt1.tpe.isError)
- setError(tree)
- else if (tparams.length == args1.length)
- tree setType appliedType(tpt1.tpe, args1 map (.tpe))
- else if (tparams.length == 0)
- errorTree(tree, "" + tpt1.tpe + " does not take type parameters")
- else
- errorTree(tree, "wrong number of type arguments for " + tpt1.tpe)
- }
- }
-
- 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
- val tree1 = if (tree.tpe != null) tree else transform1(tree, mode, pt);
- if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt)
- } catch {
- case ex: TypeError =>
- reportTypeError(tree.pos, ex);
- setError(tree)
- case ex: Throwable =>
- if (true || settings.debug.value)//!!!
- System.out.println("exception when tranforming " + tree + ", pt = " + pt);
- throw(ex)
- }
-
- def transformExpr(tree: Tree): Tree = transform(tree, EXPRmode, WildcardType);
- def transformQualExpr(tree: Tree): Tree = transform(tree, EXPRmode | QUALmode, WildcardType);
- def transformType(tree: Tree) = transform(tree, TYPEmode, WildcardType);
-
- /* -- Views --------------------------------------------------------------- */
-
- private def transformImplicit(pos: int, info: ImplicitInfo, pt: Type): Tree =
- if (isCompatible(info.tpe, pt)) {
- implcnt = implcnt + 1;
- var tree: Tree = EmptyTree;
- try {
- tree = transform1(Ident(info.name) setPos pos, EXPRmode, pt);
- if (settings.debug.value) System.out.println("transformed implicit " + tree + ":" + tree.tpe + ", pt = " + pt);//debug
- if (settings.debug.value) assert(isCompatible(tree.tpe, pt), "bad impl " + info.tpe + " " + tree.tpe + " " + pt);//debug
- val tree1 = adapt(tree, EXPRmode, pt);
- if (settings.debug.value) System.out.println("adapted implicit " + tree.symbol + ":" + info.sym);//debug
- if (info.sym == tree.symbol) tree1 else EmptyTree
- } catch {
- case ex: TypeError =>
- if (settings.debug.value)
- System.out.println(tree.toString() + " is not a valid implicit value because:\n" + ex.getMessage());
- EmptyTree
- }
- } else EmptyTree;
-
- private def inferImplicit(pos: int, pt: Type, isView: boolean, reportAmbiguous: boolean): Tree = {
- def isBetter(sym1: Symbol, tpe1: Type, sym2: Symbol, tpe2: Type): boolean =
- (sym1.owner != sym2.owner) && (sym1.owner isSubClass sym2.owner) && (tpe1 matches tpe2);
- val tc = new TypeChecker(context.makeImplicit(reportAmbiguous));
- var iss = context.implicitss;
- var tree: Tree = EmptyTree;
- while (tree == EmptyTree && !iss.isEmpty) {
- var is = iss.head;
- if (settings.debug.value) System.out.println("testing " + is.head.sym + ":" + is.head.tpe);//debug
- iss = iss.tail;
- while (!is.isEmpty) {
- tree = tc.transformImplicit(pos, is.head, pt);
- val is0 = is;
- is = is.tail;
- if (tree != EmptyTree) {
- while (!is.isEmpty) {
- val tree1 = tc.transformImplicit(pos, is.head, pt);
- if (tree1 != EmptyTree) {
- if (isBetter(is.head.sym, tree1.tpe, is0.head.sym, tree.tpe))
- tree = tree1
- else if (!isBetter(is0.head.sym, tree.tpe, is.head.sym, tree1.tpe))
- error(
- pos,
- "ambiguous implicit value:\n" +
- " both " + is0.head.sym + is0.head.sym.locationString + " of type " + tree.tpe +
- "\n and" + is.head.sym + is.head.sym.locationString + " of type " + tree1.tpe +
- (if (isView)
- "\n are possible conversion functions from " +
- pt.typeArgs(0) + " to " + pt.typeArgs(1)
- else
- "\n match expected type " + pt));
- }
- is = is.tail
- }
- }
- }
- }
- tree
- }
-
- def applyImplicitArgs(tree: Tree): Tree = tree.tpe match {
- case MethodType(formals, _) =>
- def implicitArg(pt: Type) = {
- val arg = inferImplicit(tree.pos, pt, false, true);
- if (arg != EmptyTree) arg
- else errorTree(tree, "no implicit argument matching parameter type " + pt + " was found.")
- }
- Apply(tree, formals map implicitArg) setPos tree.pos
- }
- }
-}
-
diff --git a/sources/scala/tools/nsc/typechecker/Typers.scala b/sources/scala/tools/nsc/typechecker/Typers.scala
index 7f574b06f8..5cd6d9b473 100755
--- a/sources/scala/tools/nsc/typechecker/Typers.scala
+++ b/sources/scala/tools/nsc/typechecker/Typers.scala
@@ -5,229 +5,1178 @@
// $Id$
package scala.tools.nsc.typechecker;
+import nsc.util.ListBuffer;
+import symtab.Flags._;
import scala.tools.util.Position;
/** Methods to create symbols and to enter them into scopes. */
-trait Typers: Analyzer {
- import symtab.Flags;
- import symtab.Flags._;
+abstract class Typers: Analyzer {
import global._;
+ import definitions._;
+ import posAssigner.atPos;
- abstract class TypeCompleter(val tree: Tree) extends LazyType;
+ var appcnt = 0;
+ var idcnt = 0;
+ var selcnt = 0;
+ var implcnt = 0;
- class Typer(context: Context) {
+ class TypeCheckPhase(prev: Phase) extends StdPhase(prev) {
+ def name = "typer";
+ val global: Typers.this.global.type = Typers.this.global;
+ def apply(unit: CompilationUnit): unit =
+ unit.body = newTyper(startContext.make(unit)).transformExpr(unit.body)
+ }
- val typechecker = new TypeChecker(context);
+ def newTyper(context: Context) = new Typer(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);
- }
+ class Typer(context0: Context) {
+ import context0.unit;
+
+ val infer = new Inferencer(context0) {
+ override def isCoercible(tp: Type, pt: Type): boolean =
+ context0.reportGeneralErrors && // this condition prevents chains of views
+ inferView(Position.NOPOS, tp, pt, false) != EmptyTree
}
- 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);
- }
+ private def inferView(pos: int, from: Type, to: Type, reportAmbiguous: boolean): Tree = {
+ if (settings.debug.value) System.out.println("infer view from " + from + " to " + to);//debug
+ val res = inferImplicit(pos, functionType(List(from), to), true, reportAmbiguous);
+ res
+ }
+
+ private def inferView(pos: int, from: Type, name: Name, reportAmbiguous: boolean): Tree = {
+ val to = refinedType(List(WildcardType), NoSymbol);
+ val psym = (if (name.isTypeName) to.symbol.newAbstractType(pos, name)
+ else to.symbol.newValue(pos, name)) setInfo WildcardType;
+ to.decls.enter(psym);
+ inferView(pos, from, to, reportAmbiguous)
}
- 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);
+ import infer._;
+
+ private var namerCache: Namer = null;
+ def namer = {
+ if (namerCache == null || namerCache.context != context) namerCache = new Namer(context);
+ namerCache
+ }
+
+ var context = context0;
+
+ /** Mode constants
+ */
+ private val NOmode = 0x000;
+ private val EXPRmode = 0x001; // these 3 modes are mutually exclusive.
+ private val PATTERNmode = 0x002;
+ private val TYPEmode = 0x004;
+
+ private val INCONSTRmode = 0x008; // orthogonal to above. When set we are
+ // in the body of a constructor
+
+ private val FUNmode = 0x10; // orthogonal to above. When set
+ // we are looking for a method or constructor
+
+ private val POLYmode = 0x020; // orthogonal to above. When set
+ // expression types can be polymorphic.
+
+ private val QUALmode = 0x040; // orthogonal to above. When set
+ // expressions may be packages and
+ // Java statics modules.
+
+ private val TAPPmode = 0x080; // Set for the function/type constructor part
+ // of a type application. When set we do not
+ // decompose PolyTypes.
+
+ private val stickyModes: int = EXPRmode | PATTERNmode | TYPEmode;
+
+ /** Report a type error.
+ * @param pos The position where to report the error
+ * @param ex The exception that caused the error */
+ def reportTypeError(pos: int, ex: TypeError): unit = {
+ if (settings.debug.value) ex.printStackTrace();
+ ex match {
+ case CyclicReference(sym, info: TypeCompleter) =>
+ info.tree match {
+ case ValDef(_, _, tpt, _) if (tpt.tpe == null) =>
+ error(pos, "recursive " + sym + " needs type")
+ case DefDef(_, _, _, _, tpt, _) if (tpt.tpe == null) =>
+ error(pos, "recursive " + sym + " needs result type")
+ case _ =>
+ error(pos, ex.getMessage())
+ }
+ case _ =>
+ error(pos, ex.getMessage())
}
}
- def selfTypeCompleter(tree: Tree) = new TypeCompleter(tree) {
- override def complete(sym: Symbol): unit = {
- sym.setInfo(typechecker.transformType(tree).tpe);
+ /** Check that tree is a stable expression.
+ */
+ def checkStable(tree: Tree): Tree =
+ if (treeInfo.isPureExpr(tree) || tree.tpe.isError) tree;
+ else errorTree(tree, "stable identifier required, but " + tree + " found.");
+
+ /** Check that type of given tree does not contain local or private components
+ */
+ object checkNoEscaping extends TypeMap {
+ private var owner: Symbol = _;
+ private var scope: Scope = _;
+ private var badSymbol: Symbol = _;
+
+ /** Check that type `tree' does not refer to private components unless itself is wrapped
+ * in something private (`owner' tells where the type occurs). */
+ def privates[T <: Tree](owner: Symbol, tree: T): T = {
+ check(owner, EmptyScope, tree);
+ }
+
+ /** Check that type `tree' does not refer to entities defined in scope `scope'. */
+ def locals[T <: Tree](scope: Scope, tree: T): T = check(NoSymbol, scope, tree);
+
+ def check[T <: Tree](owner: Symbol, scope: Scope, tree: T): T = {
+ this.owner = owner;
+ this.scope = scope;
+ badSymbol = NoSymbol;
+ assert(tree.tpe != null, tree);//debug
+ apply(tree.tpe);
+ if (badSymbol == NoSymbol) tree
+ else {
+ error(tree.pos,
+ (if (badSymbol.hasFlag(PRIVATE)) "private " else "") + badSymbol +
+ " escapes its defining scope as part of type " + tree.tpe);
+ setError(tree)
+ }
+ }
+ override def apply(t: Type): Type = {
+ def checkNoEscape(sym: Symbol): unit = {
+ if (sym.hasFlag(PRIVATE)) {
+ var o = owner;
+ while (o != NoSymbol && o != sym.owner && !o.isLocal && !o.hasFlag(PRIVATE))
+ o = o.owner;
+ if (o == sym.owner) badSymbol = sym
+ } else if (sym.owner.isTerm) {
+ val e = scope.lookupEntry(sym.name);
+ if (e != null && e.sym == sym && e.owner == scope) badSymbol = e.sym
+ }
+ }
+ if (badSymbol == NoSymbol)
+ t match {
+ case TypeRef(_, sym, _) => checkNoEscape(sym)
+ case SingleType(_, sym) => checkNoEscape(sym)
+ case _ =>
+ }
+ mapOver(t)
}
}
- 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);
+ def reenterValueParams(vparamss: List[List[ValDef]]): unit =
+ for (val vparams <- vparamss; val vparam <- vparams) context.scope enter vparam.symbol;
+
+ def reenterTypeParams(tparams: List[AbsTypeDef]): List[Symbol] =
+ for (val tparam <- tparams) yield { context.scope enter tparam.symbol; tparam.symbol }
+
+ def attrInfo(attr: Tree): AttrInfo = attr match {
+ case Apply(Select(New(tpt), nme.CONSTRUCTOR), args) =>
+ Pair(tpt.tpe, args map {
+ case Literal(value) =>
+ value
+ case arg =>
+ error(arg.pos, "attribute argument needs to be a constant; found: " + arg);
+ })
+ }
+
+ 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);
+
+ /** Perform the following adaptations of expression, pattern or type `tree' wrt to
+ * given mode `mode' and given prototype `pt':
+ * (1) Resolve overloading, unless mode contains FUNmode
+ * (2) Apply parameterless functions
+ * (3) Apply polymorphic types to fresh instances of their type parameters and
+ * store these instances in context.undetparams,
+ * unless followed by explicit type application.
+ * (4) Do the following to unapplied methods used as values:
+ * (4.1) If the method has only implicit parameters pass implicit arguments
+ * (4.2) otherwise, convert to function by eta-expansion,
+ * except if the method is a constructor, in which case we issue an error.
+ * (5) Convert a class type that serves as a constructor in a pattern as follows:
+ * (5.1) If this type refers to a case class, set tree's type to the unique
+ * instance of its primary constructor that is a subtype of the expected type.
+ * (5.2) Otherwise, if this type is a subtype of scala.Seq[A], set trees' type
+ * to a method type from a repeated parameter sequence type A* to the expected type.
+ * (6) Convert all other types to TypeTree nodes.
+ * (7) When in TYPEmode nut not FUNmode, check that types are fully parameterized
+ * (8) When in both EXPRmode and FUNmode, add apply method calls to values of object type.
+ * (9) If there are undetermined type variables and not POLYmode, infer expression instance
+ * Then, if tree's type is not a subtype of expected type, try the following adaptations:
+ * (10) If the expected type is byte, short or char, and the expression
+ * is an integer fitting in the range of that type, convert it to that type.
+ * (11) Widen numeric literals to their expected type, if necessary
+ * (12) When in mode EXPRmode, convert E to { E; () } if expected type is Scala.unit.
+ * (13) When in mode EXPRmode, apply a view
+ * If all this fails, error
+ */
+// def adapt(tree: Tree, mode: int, pt: Type): Tree = {
+ private def adapt(tree: Tree, mode: int, pt: Type): Tree = tree.tpe match {
+ 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);
+ 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
+ }
+ 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;
+ 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)
+ else transform(etaExpand(tree), mode, pt)
+ case _ =>
+ if (tree.isType) {
+ val clazz = tree.tpe.symbol;
+ if ((mode & PATTERNmode) != 0) { // (5)
+ if (tree.tpe.isInstanceOf[MethodType]) {
+ tree // everything done already
+ } else {
+ clazz.initialize;
+ if (clazz.hasFlag(CASE)) { // (5.1)
+ val tree1 = TypeTree() setPos tree.pos
+ setType
+ clazz.primaryConstructor.tpe.asSeenFrom(tree.tpe.prefix, clazz.owner);
+ // tree.tpe.prefix.memberType(clazz.primaryConstructor); //!!!
+ inferConstructorInstance(tree1, clazz.unsafeTypeParams, pt);
+ tree1
+ } else if (clazz.isSubClass(SeqClass)) { // (5.2)
+ pt.baseType(clazz).baseType(SeqClass) match {
+ case TypeRef(pre, seqClass, args) =>
+ tree.setType(MethodType(List(typeRef(pre, RepeatedParamClass, args)), pt))
+ case NoType =>
+ errorTree(tree, "expected pattern type " + pt +
+ " does not conform to sequence " + clazz)
+ }
+ } else {
+ System.out.println("bad: " + clazz + ":" + tree.tpe + " " + flagsToString(clazz.flags) + clazz.hasFlag(CASE));//debug
+ errorTree(tree, clazz.toString() + " is neither a case class nor a sequence class")
+ }
+ }
+ } else if ((mode & FUNmode) != 0) {
+ tree
+ } else if (tree.symbol != null && !tree.symbol.unsafeTypeParams.isEmpty) { // (7)
+ errorTree(tree, "" + clazz + " takes type parameters");
+ } else tree match { // (6)
+ case TypeTree() => tree
+ case _ => TypeTree() setPos tree.pos setType tree.tpe
+ }
+ } 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)
+ } 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
+ } else {
+ val tree1 = constfold(tree, pt); // (10) (11)
+ if (tree1 != tree) transform(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)
+ else if (context.reportGeneralErrors) { // (13); the condition prevents chains of views
+ val coercion = inferView(tree.pos, tree.tpe, pt, true);
+ if (coercion != EmptyTree)
+ return transform(Apply(coercion, List(tree)) setPos tree.pos, mode, pt);
+ }
+ }
+ typeErrorTree(tree, tree.tpe, pt)
+ }
+ }
+ }
+// System.out.println("adapt " + tree + ":" + tree.tpe + ", mode = " + mode + ", pt = " + pt);
+// adapt(tree, mode, pt)
+// }
+
+ private def completeSuperType(supertpt: Tree, tparams: List[Symbol], vparamss: List[List[ValDef]], superargs: List[Tree]): Type = {
+ tparams foreach context.scope.enter;
+ namer.enterValueParams(context.owner, vparamss);
+ val newTree = New(supertpt) setType
+ PolyType(tparams, appliedType(supertpt.tpe, tparams map (.tpe)));
+ val tree = transformExpr(atPos(supertpt.pos)(Apply(Select(newTree, nme.CONSTRUCTOR), superargs)));
+ if (settings.debug.value) System.out.println("superconstr " + tree + " co = " + context.owner);//debug
+ tree.tpe
+ }
+
+ def parentTypes(templ: Template): List[Tree] = {
+ var supertpt = transform(templ.parents.head, TYPEmode | FUNmode, WildcardType);
+ 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;
}
+ if (supertpt.symbol != null) {
+ val tparams = supertpt.symbol.typeParams;
+ if (!tparams.isEmpty) {
+ val constr @ DefDef(_, _, _, vparamss, _, Apply(_, superargs)) =
+ treeInfo.firstConstructor(templ.body);
+ val outercontext = context.outer.outer;
+ supertpt = gen.TypeTree(
+ newTyper(context.outer.outer.makeNewScope(constr, context.outer.outer.owner))
+ .completeSuperType(
+ supertpt,
+ tparams,
+ vparamss map (.map(.duplicate.asInstanceOf[ValDef])),
+ superargs map (.duplicate))) setPos supertpt.pos;
+ }
+ }
+ List.mapConserve(supertpt :: mixins)(tpt => checkNoEscaping.privates(context.owner, tpt))
}
- private def deconstIfNotFinal(sym: Symbol, tpe: Type): Type =
- if (sym.isVariable || !sym.isFinal) tpe.deconst else tpe;
+ /** Check that
+ * - all parents are class types,
+ * - first parent cluss is not a trait; following classes are traits,
+ * - final classes are not inherited,
+ * - sealed classes are only inherited by classes which are
+ * nested within definition of base class, or that occur within same
+ * statement sequence,
+ * - self-type of current class is a subtype of self-type of each parent class.
+ * - no two parents define same symbol.
+ */
+ def validateParentClasses(parents: List[Tree], selfType: Type): unit = {
+ var c = context;
+ do { c = c.outer } while (c.owner == context.owner);
+ val defscope = c.scope;
+
+ def validateParentClass(parent: Tree, isFirst: boolean): unit =
+ if (!parent.tpe.isError) {
+ val psym = parent.tpe.symbol.initialize;
+ if (!psym.isClass)
+ error(parent.pos, "class type expected");
+ else if (!isFirst && !psym.isTrait)
+ error(parent.pos, "" + psym + " is not a trait; cannot be used as mixin");
+ else if (psym.hasFlag(FINAL))
+ error(parent.pos, "illegal inheritance from final class");
+ else if (psym.isSealed) {
+ // are we in same scope as base type definition?
+ val e = defscope.lookupEntry(psym.name);
+ if (!(e.sym == psym && e.owner == defscope)) {
+ // we are not within same statement sequence
+ var c = context;
+ while (c != NoContext && c.owner != psym) c = c.outer.enclClass;
+ if (c == NoContext) error(parent.pos, "illegal inheritance from sealed class")
+ }
+ }
+ if (!(selfType <:< parent.tpe.typeOfThis)) {
+ System.out.println(context.owner);//debug
+ System.out.println(context.owner.thisSym);//debug
+ error(parent.pos, "illegal inheritance;\n self-type " +
+ selfType + " does not conform to " + parent +
+ "'s selftype " + parent.tpe.typeOfThis);
+ if (settings.explaintypes.value) explainTypes(selfType, parent.tpe.typeOfThis);
+ }
+ if (parents exists (p => p != parent && p.tpe.symbol == psym && !psym.isError))
+ error(parent.pos, "" + psym + " is inherited twice")
+ }
- 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
+ if (!parents.isEmpty) {
+ validateParentClass(parents.head, true);
+ for (val p <- parents.tail) validateParentClass(p, false);
}
- 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
- });
+ def transformClassDef(cdef: ClassDef): Tree = {
+ val clazz = cdef.symbol;
+ reenterTypeParams(cdef.tparams);
+ val tparams1 = List.mapConserve(cdef.tparams)(transformAbsTypeDef);
+ val tpt1 = checkNoEscaping.privates(clazz.thisSym, transformType(cdef.tpt));
+ val impl1 = newTyper(context.make(cdef.impl, clazz, new Scope()))
+ .transformTemplate(cdef.impl);
+ copy.ClassDef(cdef, cdef.mods, cdef.name, tparams1, tpt1, impl1) setType NoType
+ }
+
+ def transformModuleDef(mdef: ModuleDef): Tree = {
+ val clazz = mdef.symbol.moduleClass;
+ val impl1 = newTyper(context.make(mdef.impl, clazz, new Scope()))
+ .transformTemplate(mdef.impl);
+ copy.ModuleDef(mdef, mdef.mods, mdef.name, impl1) setType NoType
+ }
+
+ 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)));
+ checkNoEscaping.privates(result.symbol, result.tpt);
+ result
+ }
+ if ((mods & MUTABLE) != 0) List(stat, getter, setter) else List(stat, getter)
+ case _ =>
+ List(stat)
+ }
+
+ def transformTemplate(templ: Template): Template = {
+ templ setSymbol context.owner.newLocalDummy(templ.pos);
+ val parents1 = parentTypes(templ);
+ val selfType =
+ if (context.owner.isAnonymousClass)
+ refinedType(context.owner.info.parents, context.owner.owner)
+ else context.owner.typeOfThis;
+ validateParentClasses(parents1, selfType);
+ val body1 = templ.body flatMap addGetterSetter;
+ val body2 = transformStats(body1, templ.symbol);
+ copy.Template(templ, parents1, body2) setType context.owner.tpe
+ }
+
+ def transformValDef(vdef: ValDef): ValDef = {
+ val sym = vdef.symbol;
+ 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);
+ copy.ValDef(vdef, vdef.mods, vdef.name, tpt1, rhs1) setType NoType
+ }
+
+ def transformDefDef(ddef: DefDef): DefDef = {
+ val meth = ddef.symbol;
+ reenterTypeParams(ddef.tparams);
+ reenterValueParams(ddef.vparamss);
+ val tparams1 = List.mapConserve(ddef.tparams)(transformAbsTypeDef);
+ val vparamss1 = List.mapConserve(ddef.vparamss)(vparams1 =>
+ List.mapConserve(vparams1)(transformValDef));
+ var tpt1 = checkNoEscaping.privates(meth, transformType(ddef.tpt));
+ val rhs1 =
+ if (ddef.name == nme.CONSTRUCTOR) {
+ if (!meth.hasFlag(SYNTHETIC) &&
+ !(meth.owner.isClass ||
+ meth.owner.isModuleClass ||
+ meth.owner.isAnonymousClass ||
+ meth.owner.isRefinementClass))
+ error(ddef.pos, "constructor definition not allowed here " + meth.owner);//debug
+ context.enclClass.owner.setFlag(INCONSTRUCTOR);
+ val result = transform(ddef.rhs, EXPRmode | INCONSTRmode, UnitClass.tpe);
+ context.enclClass.owner.resetFlag(INCONSTRUCTOR);
+ result
+ } else {
+ transform(ddef.rhs, EXPRmode, tpt1.tpe);
+ }
+ copy.DefDef(ddef, ddef.mods, ddef.name, tparams1, vparamss1, tpt1, rhs1) setType NoType
+ }
+
+ def transformAbsTypeDef(tdef: AbsTypeDef): AbsTypeDef = {
+ val lo1 = checkNoEscaping.privates(tdef.symbol, transformType(tdef.lo));
+ val hi1 = checkNoEscaping.privates(tdef.symbol, transformType(tdef.hi));
+ copy.AbsTypeDef(tdef, tdef.mods, tdef.name, lo1, hi1) setType NoType
+ }
+
+ def transformAliasTypeDef(tdef: AliasTypeDef): AliasTypeDef = {
+ reenterTypeParams(tdef.tparams);
+ val tparams1 = List.mapConserve(tdef.tparams)(transformAbsTypeDef);
+ val rhs1 = checkNoEscaping.privates(tdef.symbol, transformType(tdef.rhs));
+ copy.AliasTypeDef(tdef, tdef.mods, tdef.name, tparams1, rhs1) setType NoType
+ }
- private def templateSig(templ: Template): Type = {
- val clazz = context.owner;
- val parents = typechecker.parentTypes(templ) map (.tpe);
- val decls = new Scope();
- new Namer(context.make(templ, clazz, decls)).enterSyms(templ.body);
- ClassInfoType(parents, decls, clazz)
+ def transformLabelDef(ldef: LabelDef): LabelDef = {
+ val lsym = namer.enterInScope(
+ context.owner.newLabel(ldef.pos, ldef.name) setInfo MethodType(List(), UnitClass.tpe));
+ val rhs1 = transform(ldef.rhs, EXPRmode, UnitClass.tpe);
+ copy.LabelDef(ldef, ldef.name, ldef.params, rhs1) setType UnitClass.tpe
+ }
+
+ def transformBlock(block: Block, mode: int, pt: Type): Block = {
+ namer.enterSyms(block.stats);
+ val stats1 =
+ if ((mode & INCONSTRmode) != 0) {
+ val constrCall = transform(block.stats.head, mode, WildcardType);
+ context.enclClass.owner.resetFlag(INCONSTRUCTOR);
+ constrCall :: transformStats(block.stats.tail, context.owner);
+ } else {
+ transformStats(block.stats, context.owner)
+ }
+ val expr1 = transform(block.expr, mode & ~(FUNmode | QUALmode), pt);
+ val block1 = copy.Block(block, stats1, expr1) setType expr1.tpe.deconst;
+ if (block1.tpe.symbol.isAnonymousClass)
+ block1 setType refinedType(block1.tpe.parents, block1.tpe.symbol.owner);
+ if (isFullyDefined(pt)) block1 else checkNoEscaping.locals(context.scope, block1)
}
- private def classSig(tparams: List[AbsTypeDef], tpt: Tree, impl: Template): Type = {
- val tparamSyms = typechecker.reenterTypeParams(tparams);
- if (!tpt.isEmpty)
- context.owner.typeOfThis = selfTypeCompleter(tpt);
- else tpt.tpe = NoType;
- makePolyType(tparamSyms, templateSig(impl))
+ def transformCase(cdef: CaseDef, pattpe: Type, pt: Type): CaseDef = {
+ val pat1: Tree = transform(cdef.pat, PATTERNmode, pattpe);
+ val guard1: Tree = if (cdef.guard == EmptyTree) EmptyTree
+ else transform(cdef.guard, EXPRmode, BooleanClass.tpe);
+ val body1: Tree = transform(cdef.body, EXPRmode, pt);
+ copy.CaseDef(cdef, pat1, guard1, body1) setType body1.tpe
}
- 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 = typechecker.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 typechecker.transformExpr(rhs).tpe;
- tpt.tpe
- } else typechecker.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);
+ def transformFunction(fun: Function, mode: int, pt: Type): Function = {
+ val Triple(clazz, argpts, respt) = pt match {
+ case TypeRef(_, sym, argtps)
+ if (fun.vparams.length <= MaxFunctionArity && sym == FunctionClass(fun.vparams.length) ||
+ sym == PartialFunctionClass && fun.vparams.length == 1 && fun.body.isInstanceOf[Match]) =>
+ Triple(sym, argtps.init, argtps.last)
+ case _ =>
+ Triple(FunctionClass(fun.vparams.length), fun.vparams map (x => NoType), WildcardType)
}
- makePolyType(
- tparamSyms,
- if (vparamSymss.isEmpty) PolyType(List(), restype)
- else (vparamSymss :\ restype)(mkMethodType))
+ val vparamSyms = List.map2(fun.vparams, argpts) { (vparam, argpt) =>
+ vparam match {
+ case ValDef(_, _, tpt, _) =>
+ if (tpt.isEmpty)
+ tpt.tpe =
+ if (argpt == NoType) { error(vparam.pos, "missing parameter type"); ErrorType }
+ else argpt
+ }
+ namer.enterSym(vparam);
+ vparam.symbol
+ }
+ val vparams1 = List.mapConserve(fun.vparams)(transformValDef);
+ val body1 = transform(fun.body, EXPRmode, respt);
+ copy.Function(fun, vparams1, body1)
+ setType typeRef(clazz.tpe.prefix, clazz, (vparamSyms map (.tpe)) ::: List(body1.tpe))
}
- private def aliasTypeSig(tpsym: Symbol, tparams: List[AbsTypeDef], rhs: Tree): Type =
- makePolyType(typechecker.reenterTypeParams(tparams), typechecker.transformType(rhs).tpe);
+ def transformRefinement(stats: List[Tree]): List[Tree] = {
+ namer.enterSyms(stats);
+ for (val stat <- stats) stat.symbol setFlag OVERRIDE;
+ transformStats(stats, NoSymbol);
+ }
- private def typeSig(tree: Tree): Type =
- try {
- val sym: Symbol = tree.symbol;
- tree match {
- case ClassDef(_, _, tparams, tpt, impl) =>
- new Typer(context.makeNewScope(tree, sym)).classSig(tparams, tpt, impl)
-
- case ModuleDef(_, _, impl) =>
- val clazz = sym.moduleClass;
- clazz.setInfo(new Typer(context.make(tree, clazz)).templateSig(impl));
- clazz.tpe;
-
- case DefDef(_, _, tparams, vparamss, tpt, rhs) =>
- new Typer(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 = new TypeChecker(context.make(tree, sym))
- .transformExpr(rhs).tpe;
- tpt.tpe
- }
- else typechecker.transformType(tpt).tpe)
-
- case AliasTypeDef(_, _, tparams, rhs) =>
- new Typer(context.makeNewScope(tree, sym)).aliasTypeSig(sym, tparams, rhs)
-
- case AbsTypeDef(_, _, lo, hi) =>
- TypeBounds(typechecker.transformType(lo).tpe, typechecker.transformType(hi).tpe);
-
- case Import(expr, selectors) =>
- val expr1 = typechecker.transformQualExpr(expr);
- val base = expr1.tpe;
- typechecker.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)
+ def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] =
+ List.mapConserve(stats) { stat =>
+ if (context.owner.isRefinementClass && !treeInfo.isDeclaration(stat))
+ errorTree(stat, "only declarations allowed here");
+ stat match {
+ case imp @ Import(_, _) =>
+ context = context.makeNewImport(imp);
+ EmptyTree
+ case _ =>
+ (if (!stat.isDef && exprOwner != context.owner)
+ newTyper(context.make(stat, exprOwner)) else this).transformExpr(stat)
+ }
+ }
+
+ private def transform1(tree: Tree, mode: int, pt: Type): Tree = {
+
+ def funmode = mode & stickyModes | FUNmode | POLYmode;
+
+ def transformCases(cases: List[CaseDef], pattp: Type): List[CaseDef] = {
+ List.mapConserve(cases)(cdef =>
+ newTyper(context.makeNewScope(tree, context.owner)).transformCase(cdef, pattp, pt))
+ }
+
+ def transformTypeApply(fun: Tree, args: List[Tree]): Tree = fun.tpe match {
+ case OverloadedType(pre, alts) =>
+ inferPolyAlternative(fun, args.length);
+ transformTypeApply(fun, args)
+ case PolyType(tparams, restpe) if (tparams.length != 0) =>
+ if (tparams.length == args.length) {
+ val targs = args map (.tpe);
+ checkBounds(tree.pos, tparams, targs, "");
+ if (settings.debug.value) System.out.println("type app " + tparams + " => " + targs + " = " + restpe.subst(tparams, targs));//debug
+ copy.TypeApply(tree, fun, args) setType restpe.subst(tparams, targs);
+ } else {
+ errorTree(tree, "wrong number of type parameters for " + treeSymTypeMsg(fun))
+ }
+ case ErrorType =>
+ setError(tree)
+ case _ =>
+ System.out.println(fun.toString() + " " + args);//debug
+ errorTree(tree, treeSymTypeMsg(fun) + " does not take type parameters.");
+ }
+
+ def transformApply(fun: Tree, args: List[Tree]): Tree = fun.tpe match {
+ case OverloadedType(pre, alts) =>
+ val args1 = List.mapConserve(args)(arg =>
+ transform(arg, mode & stickyModes, WildcardType));
+ inferMethodAlternative(fun, context.undetparams, args1 map (.tpe.deconst), pt);
+ transformApply(adapt(fun, funmode, WildcardType), args1);
+ case MethodType(formals0, restpe) =>
+ val formals = formalTypes(formals0, args.length);
+ if (formals.length != args.length) {
+ System.out.println("" + formals.length + " " + args.length);
+ errorTree(tree, "wrong number of arguments for " + treeSymTypeMsg(fun))
+ } else {
+ val tparams = context.undetparams;
+ context.undetparams = List();
+ if (tparams.isEmpty) {
+ val args1 = List.map2(args, formals) ((arg, formal) =>
+ transform(arg, mode & stickyModes, formal));
+ def ifPatternSkipFormals(tp: Type) = tp match {
+ 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)
+ } else {
+ assert((mode & PATTERNmode) == 0); // this case cannot arise for patterns
+ val lenientTargs = protoTypeArgs(tparams, formals, restpe, pt);
+ val strictTargs = List.map2(lenientTargs, tparams)((targ, tparam) =>
+ if (targ == WildcardType) tparam.tpe else targ);
+ def transformArg(tree: Tree, formal: Type): Tree = {
+ val lenientPt = formal.subst(tparams, lenientTargs);
+ val tree1 = transform(tree, mode & stickyModes | POLYmode, lenientPt);
+ val argtparams = context.undetparams;
+ context.undetparams = List();
+ if (!argtparams.isEmpty) {
+ val strictPt = formal.subst(tparams, strictTargs);
+ inferArgumentInstance(tree1, argtparams, strictPt, lenientPt);
+ }
+ tree1
+ }
+ val args1 = List.map2(args, formals)(transformArg);
+ if (args1 exists (.tpe.isError)) setError(tree)
+ else {
+ if (settings.debug.value) System.out.println("infer method inst " + fun + ", tparams = " + tparams + ", args = " + args1.map(.tpe) + ", pt = " + pt + ", lobounds = " + tparams.map(.tpe.bounds.lo));//debug
+ val undetparams = inferMethodInstance(fun, tparams, args1, pt);
+ val result = transformApply(fun, args1);
+ context.undetparams = undetparams;
+ result
+ }
+ }
+ }
+ case ErrorType =>
+ setError(tree)
+ }
+
+ /** The qualifying class of a this or super with prefix `qual' */
+ def qualifyingClass(qual: Name): Symbol = {
+ if (qual == nme.EMPTY.toTypeName) {
+ val clazz = context.enclClass.owner;
+ if (!clazz.isPackageClass) clazz
+ else {
+ error(tree.pos, "" + tree + " can be used only in a class, object, or template");
+ NoSymbol
+ }
+ } else {
+ var c = context.enclClass;
+ while (c != NoContext && c.owner.name != qual) c = c.outer.enclClass;
+ if (c != NoContext) c.owner
+ else {
+ error(tree.pos, "" + qual + " is not an enclosing class");
+ NoSymbol
+ }
}
+ }
+
+ /** Attribute a selection where `tree' is `qual.name'.
+ * `qual' is already attributed.
+ */
+ def transformSelect(qual: Tree, name: Name): Tree = {
+ val sym = 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)
+ return transform(
+ copy.Select(tree, Apply(coercion, List(qual)) setPos qual.pos, name), mode, pt)
+ }
+ if (sym.info == NoType) {
+ System.out.println(qual);
+ System.out.println(qual.tpe.members);//debug
+ System.out.println(qual.tpe.member(name));//debug
+ errorTree(tree, decode(name) + " is not a member of " + qual.tpe.widen)
+ } else {
+ val tree1 = tree match {
+ case Select(_, _) => copy.Select(tree, qual, name)
+ case SelectFromTypeTree(_, _) => copy.SelectFromTypeTree(tree, qual, name);
+ }
+ stabilize(checkAccessible(tree1, sym, qual.tpe, qual), qual.tpe)
+ }
+ }
+
+ /** Attribute an identifier consisting of a simple name or an outer reference.
+ * @param tree The tree representing the identifier.
+ * @param name The name of the identifier.
+ * Transformations: (1) Prefix class members with this.
+ * (2) Change imported symbols to selections
+ */
+ def transformIdent(name: Name): Tree = {
+ 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 pre: Type = NoPrefix; // the prefix type of defSym, if a class member
+
+ 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;
+ }
+
+ // 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
+ }
+ 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);
+ }
+ }
+ 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
+ }
+
+ // begin transform1
+ val sym: Symbol = tree.symbol;
+ if (sym != null) sym.initialize;
+ //if (settings.debug.value && tree.isDef) global.log("transforming definition of " + sym);//DEBUG
+ tree match {
+ case PackageDef(name, stats) =>
+ val stats1 = newTyper(context.make(tree, sym.moduleClass, sym.info.decls))
+ .transformStats(stats, NoSymbol);
+ copy.PackageDef(tree, name, stats1) setType NoType
+
+ case cdef @ ClassDef(_, _, _, _, _) =>
+ newTyper(context.makeNewScope(tree, sym)).transformClassDef(cdef)
+
+ case mdef @ ModuleDef(_, _, _) =>
+ transformModuleDef(mdef)
+
+ case vdef @ ValDef(_, _, _, _) =>
+ transformValDef(vdef)
+
+ case ddef @ DefDef(_, _, _, _, _, _) =>
+ newTyper(context.makeNewScope(tree, sym)).transformDefDef(ddef)
+
+ case tdef @ AbsTypeDef(_, _, _, _) =>
+ transformAbsTypeDef(tdef)
+
+ case tdef @ AliasTypeDef(_, _, _, _) =>
+ newTyper(context.makeNewScope(tree, sym)).transformAliasTypeDef(tdef)
+
+ case ldef @ LabelDef(_, List(), _) =>
+ newTyper(context.makeNewScope(tree, context.owner)).transformLabelDef(ldef)
+
+ case Attributed(attr, defn) =>
+ val attr1 = transform(attr, EXPRmode, AttributeClass.tpe);
+ val defn1 = transform(defn, mode, pt);
+ val existing = attributes.get(defn1.symbol) match {
+ case None => List()
+ case Some(attrs) => attrs
+ }
+ attributes(defn1.symbol) = attrInfo(attr1) :: existing;
+ defn1
+
+ case DocDef(comment, defn) =>
+ transform(defn, mode, pt);
+
+ case block @ Block(_, _) =>
+ newTyper(context.makeNewScope(tree, context.owner))
+ .transformBlock(block, mode, pt)
+
+ case Sequence(elems) =>
+ val elems1 = List.mapConserve(elems)(elem => transform(elem, mode, pt));
+ copy.Sequence(tree, elems1) setType pt
+
+ case Alternative(alts) =>
+ val alts1 = List.mapConserve(alts)(alt => transform(alt, mode, pt));
+ copy.Alternative(tree, alts1) setType pt
+
+ case Bind(name, body) =>
+ val body1 = transform(body, mode, pt);
+ val vble = context.owner.newValue(tree.pos, name).setInfo(
+ if (treeInfo.isSequenceValued(body)) seqType(pt) else body1.tpe);
+ //todo: check whether we can always use body1.tpe
+ namer.enterInScope(vble);
+ copy.Bind(tree, name, body1) setSymbol vble setType pt
+
+ case fun @ Function(_, _) =>
+ newTyper(context.makeNewScope(tree, context.owner))
+ .transformFunction(fun, mode, pt)
+
+ case Assign(lhs, rhs) =>
+ def isGetter(sym: Symbol) = sym.info match {
+ case PolyType(List(), _) => sym.owner.isClass && !sym.isStable
+ case _ => false
+ }
+ val lhs1 = transformExpr(lhs);
+ val varsym = lhs1.symbol;
+ if (varsym != null && isGetter(varsym)) {
+ lhs1 match {
+ case Select(qual, name) =>
+ transform(
+ Apply(
+ Select(qual, nme.SETTER_NAME(name)) setPos lhs.pos,
+ List(rhs)), mode, pt) setPos tree.pos
+ }
+ } else if (varsym != null && varsym.isVariable) {
+ val rhs1 = transform(rhs, EXPRmode, lhs1.tpe);
+ copy.Assign(tree, lhs1, rhs1) setType UnitClass.tpe;
+ } else {
+ System.out.println("" + lhs1 + " " + varsym + " " + flagsToString(varsym.flags));//debug
+ if (!lhs1.tpe.isError) error(tree.pos, "assignment to non-variable ");
+ setError(tree)
+ }
+
+ case If(cond, thenp, elsep) =>
+ val cond1 = transform(cond, EXPRmode, BooleanClass.tpe);
+ if (elsep.isEmpty) {
+ val thenp1 = transform(thenp, EXPRmode, UnitClass.tpe);
+ copy.If(tree, cond1, thenp1, elsep) setType UnitClass.tpe
+ } else {
+ val thenp1 = transform(thenp, EXPRmode, pt);
+ val elsep1 = transform(elsep, EXPRmode, pt);
+ copy.If(tree, cond1, thenp1, elsep1) setType lub(List(thenp1.tpe, elsep1.tpe));
+ }
+
+ case Match(selector, cases) =>
+ val selector1 = transformExpr(selector);
+ val cases1 = transformCases(cases, selector1.tpe);
+ copy.Match(tree, selector1, cases1) setType lub(cases1 map (.tpe))
+
+ case Return(expr) =>
+ val enclFun = context.owner.enclMethod;
+ if (!enclFun.isMethod || enclFun.isConstructor)
+ errorTree(tree, "return outside method definition")
+ else if (!context.owner.hasFlag(INITIALIZED))
+ errorTree(tree, "method " + context.owner + " has return statement; needs result type")
+ else {
+ val expr1: Tree = transform(expr, EXPRmode, enclFun.tpe.resultType);
+ copy.Return(tree, expr1) setSymbol enclFun setType AllClass.tpe;
+ }
+
+ case Try(block, catches, finalizer) =>
+ val block1 = transform(block, EXPRmode, pt);
+ val catches1 = transformCases(catches, ThrowableClass.tpe);
+ val finalizer1 = if (finalizer.isEmpty) finalizer
+ else transform(finalizer, EXPRmode, UnitClass.tpe);
+ copy.Try(tree, block1, catches1, finalizer1)
+ setType lub(block1.tpe :: (catches1 map (.tpe)))
+
+ case Throw(expr) =>
+ val expr1 = transform(expr, EXPRmode, ThrowableClass.tpe);
+ copy.Throw(tree, expr1) setType AllClass.tpe
+
+ case New(tpt: Tree) =>
+ var tpt1 = transform(tpt, TYPEmode | FUNmode, WildcardType);
+ if (tpt1.symbol != null && !tpt1.symbol.typeParams.isEmpty) {
+ context.undetparams = cloneSymbols(tpt1.symbol.unsafeTypeParams);
+ tpt1 = TypeTree()
+ setPos tpt1.pos
+ setType appliedType(tpt1.tpe, context.undetparams map (.tpe));
+ }
+ copy.New(tree, tpt1).setType(tpt1.tpe)
+
+ case Typed(expr, tpt @ Ident(name)) if (name == nme.WILDCARD_STAR.toTypeName) =>
+ val expr1 = transform(expr, mode & stickyModes, seqType(pt));
+ expr1.tpe.baseType(SeqClass) match {
+ case TypeRef(_, _, List(elemtp)) =>
+ copy.Typed(tree, expr1, tpt setType elemtp) setType elemtp
+ case _ =>
+ setError(tree)
+ }
+ case Typed(expr, tpt) =>
+ val tpt1 = transformType(tpt);
+ val expr1 = transform(expr, mode & stickyModes, tpt1.tpe);
+ copy.Typed(tree, expr1, tpt1) setType tpt1.tpe
+
+ case TypeApply(fun, args) =>
+ val args1 = List.mapConserve(args)(transformType);
+ // do args first in order to maintain conext.undetparams on the function side.
+ transformTypeApply(transform(fun, funmode | TAPPmode, WildcardType), args1)
+
+ case Apply(fun, args) =>
+ val funpt = if ((mode & PATTERNmode) != 0) pt else WildcardType;
+ 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 (fun1.hasSymbol && fun1.symbol.hasFlag(OVERLOADED)) {
+ val argtypes = args map (arg => AllClass.tpe);
+ val pre = fun1.symbol.tpe.prefix;
+ val sym = fun1.symbol filter (alt =>
+ isApplicable(context.undetparams, pre.memberType(alt), argtypes, pt));
+ if (sym != NoSymbol)
+ fun1 = adapt(fun1 setSymbol sym setType pre.memberType(sym), funmode, WildcardType)
+ }
+ appcnt = appcnt + 1;
+ transformApply(fun1, args)
+
+ case Super(qual, mix) =>
+ val clazz = qualifyingClass(qual);
+ if (clazz == NoSymbol) setError(tree)
+ else {
+ val owntype =
+ if (mix == nme.EMPTY.toTypeName) intersectionType(clazz.info.parents)
+ else {
+ val ps = clazz.info.parents dropWhile (p => p.symbol.name != mix);
+ if (ps.isEmpty) {
+ System.out.println(clazz.info.parents map (.symbol.name));//debug
+ error(tree.pos, "" + mix + " does not name a base class of " + clazz);
+ ErrorType
+ } else ps.head
+ }
+ tree setSymbol clazz setType owntype
+ }
+
+ case This(qual) =>
+ val clazz = qualifyingClass(qual);
+ if (clazz == NoSymbol) setError(tree)
+ else {
+ val owntype = if (pt.isStable || (mode & QUALmode) != 0) clazz.thisType
+ else clazz.typeOfThis;
+ tree setSymbol clazz setType owntype
+ }
+
+ case Select(qual @ Super(_, _), nme.CONSTRUCTOR) =>
+ val qual1 = transform(qual, EXPRmode | QUALmode | POLYmode, 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) =>
+ selcnt = selcnt + 1;
+ assert (name != nme.CONSTRUCTOR || !qual.isInstanceOf[Super], tree);//debug
+ var qual1 = transform(qual, EXPRmode | QUALmode | POLYmode, WildcardType);
+ if (name.isTypeName) qual1 = checkStable(qual1);
+ transformSelect(qual1, name);
+
+ case Ident(name) =>
+ idcnt = idcnt + 1;
+ if (name == nme.WILDCARD && (mode & (PATTERNmode | FUNmode)) == PATTERNmode)
+ tree setType pt
+ else
+ transformIdent(name);
+
+ case Literal(value) =>
+ tree setType ConstantType(literalType(value), value)
+
+ case SingletonTypeTree(ref) =>
+ val ref1 = checkStable(transform(ref, EXPRmode | QUALmode, AnyRefClass.tpe));
+ tree setType ref1.tpe.resultType;
+
+ case SelectFromTypeTree(qual, selector) =>
+ tree setType transformSelect(transformType(qual), selector).tpe
+
+ case CompoundTypeTree(templ: Template) =>
+ tree setType {
+ val parents1 = List.mapConserve(templ.parents)(transformType);
+ if (parents1 exists (.tpe.isError)) ErrorType
+ else {
+ val decls = new Scope();
+ val self = refinedType(parents1 map (.tpe), context.enclClass.owner, decls);
+ newTyper(context.make(tree, self.symbol, new Scope())).transformRefinement(templ.body);
+ self
+ }
+ }
+
+ case AppliedTypeTree(tpt, args) =>
+ val tpt1 = transform(tpt, mode | FUNmode | TAPPmode, WildcardType);
+ val tparams = tpt1.tpe.symbol.typeParams;
+ val args1 = List.mapConserve(args)(transformType);
+ if (tpt1.tpe.isError)
+ setError(tree)
+ else if (tparams.length == args1.length)
+ tree setType appliedType(tpt1.tpe, args1 map (.tpe))
+ else if (tparams.length == 0)
+ errorTree(tree, "" + tpt1.tpe + " does not take type parameters")
+ else
+ errorTree(tree, "wrong number of type arguments for " + tpt1.tpe)
+ }
+ }
+
+ 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
+ val tree1 = if (tree.tpe != null) tree else transform1(tree, mode, pt);
+ if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt)
} catch {
case ex: TypeError =>
- typechecker.reportTypeError(tree.pos, ex);
- ErrorType
+ reportTypeError(tree.pos, ex);
+ setError(tree)
+ case ex: Throwable =>
+ if (true || settings.debug.value)//!!!
+ System.out.println("exception when tranforming " + tree + ", pt = " + pt);
+ throw(ex)
}
- /** 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);
+ def transformExpr(tree: Tree): Tree = transform(tree, EXPRmode, WildcardType);
+ def transformQualExpr(tree: Tree): Tree = transform(tree, EXPRmode | QUALmode, WildcardType);
+ def transformType(tree: Tree) = transform(tree, TYPEmode, WildcardType);
+
+ /* -- Views --------------------------------------------------------------- */
+
+ private def transformImplicit(pos: int, info: ImplicitInfo, pt: Type): Tree =
+ if (isCompatible(info.tpe, pt)) {
+ implcnt = implcnt + 1;
+ var tree: Tree = EmptyTree;
+ try {
+ tree = transform1(Ident(info.name) setPos pos, EXPRmode, pt);
+ if (settings.debug.value) System.out.println("transformed implicit " + tree + ":" + tree.tpe + ", pt = " + pt);//debug
+ if (settings.debug.value) assert(isCompatible(tree.tpe, pt), "bad impl " + info.tpe + " " + tree.tpe + " " + pt);//debug
+ val tree1 = adapt(tree, EXPRmode, pt);
+ if (settings.debug.value) System.out.println("adapted implicit " + tree.symbol + ":" + info.sym);//debug
+ if (info.sym == tree.symbol) tree1 else EmptyTree
+ } catch {
+ case ex: TypeError =>
+ if (settings.debug.value)
+ System.out.println(tree.toString() + " is not a valid implicit value because:\n" + ex.getMessage());
+ EmptyTree
+ }
+ } else EmptyTree;
+
+ private def inferImplicit(pos: int, pt: Type, isView: boolean, reportAmbiguous: boolean): Tree = {
+ def isBetter(sym1: Symbol, tpe1: Type, sym2: Symbol, tpe2: Type): boolean =
+ (sym1.owner != sym2.owner) && (sym1.owner isSubClass sym2.owner) && (tpe1 matches tpe2);
+ val tc = newTyper(context.makeImplicit(reportAmbiguous));
+ var iss = context.implicitss;
+ var tree: Tree = EmptyTree;
+ while (tree == EmptyTree && !iss.isEmpty) {
+ var is = iss.head;
+ if (settings.debug.value) System.out.println("testing " + is.head.sym + ":" + is.head.tpe);//debug
+ iss = iss.tail;
+ while (!is.isEmpty) {
+ tree = tc.transformImplicit(pos, is.head, pt);
+ val is0 = is;
+ is = is.tail;
+ if (tree != EmptyTree) {
+ while (!is.isEmpty) {
+ val tree1 = tc.transformImplicit(pos, is.head, pt);
+ if (tree1 != EmptyTree) {
+ if (isBetter(is.head.sym, tree1.tpe, is0.head.sym, tree.tpe))
+ tree = tree1
+ else if (!isBetter(is0.head.sym, tree.tpe, is.head.sym, tree1.tpe))
+ error(
+ pos,
+ "ambiguous implicit value:\n" +
+ " both " + is0.head.sym + is0.head.sym.locationString + " of type " + tree.tpe +
+ "\n and" + is.head.sym + is.head.sym.locationString + " of type " + tree1.tpe +
+ (if (isView)
+ "\n are possible conversion functions from " +
+ pt.typeArgs(0) + " to " + pt.typeArgs(1)
+ else
+ "\n match expected type " + pt));
+ }
+ is = is.tail
+ }
+ }
}
}
- checkNoConflict(DEFERRED, PRIVATE);
- checkNoConflict(FINAL, SEALED);
- if (!sym.hasFlag(MODULE)) checkNoConflict(FINAL, PRIVATE);
- checkNoConflict(PRIVATE, PROTECTED);
- checkNoConflict(PRIVATE, OVERRIDE);
- checkNoConflict(DEFERRED, FINAL);
+ tree
+ }
+
+ def applyImplicitArgs(tree: Tree): Tree = tree.tpe match {
+ case MethodType(formals, _) =>
+ def implicitArg(pt: Type) = {
+ val arg = inferImplicit(tree.pos, pt, false, true);
+ if (arg != EmptyTree) arg
+ else errorTree(tree, "no implicit argument matching parameter type " + pt + " was found.")
+ }
+ Apply(tree, formals map implicitArg) setPos tree.pos
}
}
}
+