diff options
Diffstat (limited to 'sources')
-rw-r--r-- | sources/scala/tools/scalac/ast/parser/Parser.scala | 43 | ||||
-rw-r--r-- | sources/scala/tools/scalac/typechecker/Analyzer.scala | 2669 | ||||
-rw-r--r-- | sources/scala/tools/scalac/typechecker/AnalyzerPhase.scala | 73 | ||||
-rw-r--r-- | sources/scala/tools/scalac/typechecker/ConstantFolder.scala | 311 | ||||
-rw-r--r-- | sources/scala/tools/scalac/typechecker/Context.scala | 64 | ||||
-rw-r--r-- | sources/scala/tools/scalac/typechecker/DeSugarize.scala | 575 | ||||
-rw-r--r-- | sources/scala/tools/scalac/typechecker/ImportList.scala | 65 | ||||
-rw-r--r-- | sources/scala/tools/scalac/typechecker/Infer.scala | 889 | ||||
-rw-r--r-- | sources/scala/tools/scalac/typechecker/Substituter.scala | 95 | ||||
-rw-r--r-- | sources/scala/tools/scalac/util/NewArray.scala | 99 |
10 files changed, 4861 insertions, 22 deletions
diff --git a/sources/scala/tools/scalac/ast/parser/Parser.scala b/sources/scala/tools/scalac/ast/parser/Parser.scala index ffc38c8c9d..0466e11b3d 100644 --- a/sources/scala/tools/scalac/ast/parser/Parser.scala +++ b/sources/scala/tools/scalac/ast/parser/Parser.scala @@ -338,18 +338,16 @@ class Parser(unit: Unit) { /** Convert tree to formal parameter list */ - def convertToParams(t: Tree): Array[Tree$ValDef] = { - t match { - case Tree$Function(params, Tree.Empty) => - params - case Tree$Ident(_) | Tree$Typed(Tree$Ident(_), _) => - NewArray.ValDef(convertToParam(t)); - case Tree$Block(stats) => - if (stats.length == 0) Tree.ValDef_EMPTY_ARRAY; - case _ => - } - syntaxError(t.pos, "malformed formal parameter list", false); - Tree.ValDef_EMPTY_ARRAY; + def convertToParams(t: Tree): Array[Tree$ValDef] = t match { + case Tree$Function(params, Tree.Empty) => + params + case Tree$Ident(_) | Tree$Typed(Tree$Ident(_), _) => + NewArray.ValDef(convertToParam(t)); + case Tree$Block(stats) if (stats.length == 0) => + Tree.ValDef_EMPTY_ARRAY; + case _ => + syntaxError(t.pos, "malformed formal parameter list", false); + Tree.ValDef_EMPTY_ARRAY; } /** Convert list of trees to formal parameter list @@ -634,15 +632,16 @@ class Parser(unit: Unit) { * | `(' [Types] `)' `=>' Type * | Type1 */ - def typ(): Tree = + def typ(): Tree = { + var t: Tree = _; if (s.token == LPAREN) { s.nextToken(); if (s.token == RPAREN) { s.nextToken(); val pos = accept(ARROW); - make.FunType(pos, Tree.EMPTY_ARRAY, typ()); + return make.FunType(pos, Tree.EMPTY_ARRAY, typ()); } else { - val t = typ(); + t = typ(); if (s.token == COMMA) { s.nextToken(); val ts = new TreeList(); @@ -650,19 +649,19 @@ class Parser(unit: Unit) { ts.append(types()); accept(RPAREN); val pos = accept(ARROW); - make.FunType(pos, ts.toArray(), typ()); + return make.FunType(pos, ts.toArray(), typ()); } else { accept(RPAREN); - t } } } else { - val t = type1(); - if (s.token == ARROW) - make.FunType(s.skipToken(), NewArray.Tree(t), typ()) - else - t + t = type1() } + if (s.token == ARROW) + make.FunType(s.skipToken(), NewArray.Tree(t), typ()) + else + t + } /** Type1 ::= SimpleType {with SimpleType} [Refinement] */ diff --git a/sources/scala/tools/scalac/typechecker/Analyzer.scala b/sources/scala/tools/scalac/typechecker/Analyzer.scala new file mode 100644 index 0000000000..2b906e0db4 --- /dev/null +++ b/sources/scala/tools/scalac/typechecker/Analyzer.scala @@ -0,0 +1,2669 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +\* */ + +// $Id$ + +// todo: eliminate Typed nodes. +// todo: use SELECTOR flag to avoid access methods for privates +// todo: use mangled name or drop. +// todo: emit warnings for unchecked. +// todo: synchronize on module instantiation. +// todo: empty package + +package scala.tools.scalac.typechecker; + +import ch.epfl.lamp.util.Position; +import scalac._; +import scalac.util._; +import scalac.ast._; +import scalac.ast.printer._; +import scalac.symtab._; +import scalac.symtab.classfile._; +import Tree._; +import java.util.HashMap; +import java.lang.{Boolean, Byte, Short, Character, Integer, Object} +import scala.tools.scalac.util.NewArray; + +/** The main attribution phase. + */ +class Analyzer(global: Global, descr: AnalyzerPhase) extends Transformer(global) { + + import Modifiers._; + import Kinds._; + + val definitions = global.definitions; + val infer = new Infer(this); + val desugarize = new DeSugarize(make, copy, gen, infer, global); + val constfold = new ConstantFolder(this); + + var unit: Unit = _; + + private var context: Context = _; + private var pt: Type = _; + private var mode: int = _; + + private var inAlternative: boolean = _; + private var patternVars: HashMap = _; // for pattern matching; maps x to {true,false} + + override def apply(units: Array[Unit]): unit = { + for (val i <- Iterator.range(0, units.length)) + enterUnit(units(i)); + super.apply(units); + var n = descr.newSources.size(); + while (n > 0) { // this calls apply(u) for every unit `u'. + val l = global.units.length; + val newUnits = new Array[Unit](l + n); + System.arraycopy( + global.units.asInstanceOf[Array[Object]], 0, + newUnits.asInstanceOf[Array[Object]], 0, l); + for (val i <- Iterator.range(0, n)) { + newUnits(i + l) = descr.newSources.get(i).asInstanceOf[Unit]; + } + global.units = newUnits; + descr.newSources.clear(); + for (val i <- Iterator.range(l, newUnits.length)) + apply(newUnits(i)); + n = descr.newSources.size(); + } + } + + def enterUnit(unit: Unit): unit = + enter( + new Context( + Tree.Empty, + if (unit.console) descr.consoleContext else descr.startContext), + unit); + + def enter(context: Context, unit: Unit): unit = { + assert(this.unit == null, "start unit non null for " + unit); + this.unit = unit; + this.context = context; + this.patternVars = new HashMap(); + val prevImports = context.imports; + descr.contexts.put(unit, context); + enterSyms(unit.body); + context.imports = prevImports; + this.unit = null; + this.context = null; + } + + def lateEnter(unit: Unit, sym: Symbol): unit = { + enterUnit(unit); + if (sym.rawFirstInfo().isInstanceOf[SourceCompleter]) { + sym.setInfo(Type.ErrorType); + val kind = if (sym.name.isTermName()) "object " else "class "; + throw new Type$Error("file " + unit.source + " does not define public " + + kind + sym.fullName()); + } else { + descr.newSources.add(unit); + } + } + + override def apply(unit: Unit): unit = { + global.log("checking " + unit); + assert(this.unit == null, "start unit non null for " + unit); + this.unit = unit; + this.context = descr.contexts.remove(unit).asInstanceOf[Context]; + assert(this.context != null, "could not find context for " + unit); + unit.body = transformStatSeq(unit.body, Symbol.NONE); + if (global.target != Global.TARGET_INT && global.reporter.errors() == 0) { + genSymData(unit.body); + } + this.unit = null; + this.context = null; + global.operation("checked " + unit); + } + + def genSymData(stats: Array[Tree]): unit = { + for (val i <- Iterator.range(0, stats.length)) { + stats(i) match { + case Tree$ClassDef(_, _, _, _, _, _) | Tree$ModuleDef(_, _, _, _) => + val sym = stats(i).symbol(); + val fullname = sym.fullName(); + if (global.symdata.get(fullname) == null) { + val pickle: Pickle = new Pickle(); + pickle.add(sym.owner().info().lookup(sym.name.toTermName())); + pickle.add(sym.owner().info().lookup(sym.name.toTypeName())); + pickle.pickle(); + global.symdata.put(fullname, pickle); + } + case Tree$PackageDef(packaged, templ) => + genSymData(templ.body); + case _ => + } + } + } + + /** Mode constants + */ + val NOmode = 0x000; + val EXPRmode = 0x001; // these 4 modes are mutually exclusive. + val PATTERNmode = 0x002; + val CONSTRmode = 0x004; + val TYPEmode = 0x008; + + val FUNmode = 0x10; // orthogonal to above. When set + // we are looking for a method or constructor + + val POLYmode = 0x020; // orthogonal to above. When set + // expression types can be polymorphic. + + val QUALmode = 0x040; // orthogonal to above. When set + // expressions may be packages and + // Java statics modules. + + val SUPERmode = 0x080; // Goes with CONSTRmode. When set + // we are checking a superclass + // constructor invocation. + + val baseModes = EXPRmode | PATTERNmode | CONSTRmode; + + val SEQUENCEmode = 0x1000; // orthogonal to above. When set + // we turn "x" into "x@_" + // and allow args to be of type Seq( a) instead of a + +// Diagnostics ---------------------------------------------------------------- + + def errorTree(pos: int): Tree = + make.Bad(pos).setSymbol(Symbol.ERROR).setType(Type.ErrorType); + + def error(pos: int, msg: String): Tree = { + unit.error(pos, msg); + errorTree(pos); + } + + def typeError(pos: int, found: Type, req: Type): unit = { + var msg: String = infer.typeErrorMsg("type mismatch", found, req); + val foundResult: Type = found.resultType(); + if (foundResult != found && infer.isCompatible(foundResult, req)) + msg = msg + "\n possible cause: missing arguments for method or constructor"; + error(pos, msg); + } + + def reportTypeError(pos: int, ex: Type$Error): Tree = { + if (global.debug) ex.printStackTrace(); + if (ex.isInstanceOf[CyclicReference]) { + val cyc: CyclicReference = ex.asInstanceOf[CyclicReference]; + if (cyc.info.isInstanceOf[LazyTreeType]) { + (cyc.info.asInstanceOf[LazyTreeType]).tree match { + case Tree$ValDef(_, _, Tree.Empty, _) => + return error(pos, "recursive " + cyc.sym + " needs type"); + case Tree$DefDef(_, _, _, _, Tree.Empty, _) => + return error(pos, "recursive function " + cyc.sym.name + " needs result type"); + case _ => + } + } + } + error(pos, ex.msg); + } + +// Name resolution ----------------------------------------------------------- + + def decode(name: Name): String = + if (name.isTypeName()) "type " + NameTransformer.decode(name); + else "value " + NameTransformer.decode(name); + + /** Check that `sym' is accessible as a member of tree `site' in current context. + */ + def checkAccessible(pos: int, sym: Symbol, symtype: Type, site: Tree): Type = { + if ((sym.owner().flags & INCONSTRUCTOR) != 0 && + !(sym.kind == TYPE && sym.isParameter()) && + site.isInstanceOf[Tree$This]) { + error(pos, "" + sym + " cannot be accessed from constructor"); + Type.ErrorType; + } else { + symtype match { + case Type$OverloadedType(alts, alttypes) => + var nacc: int = 0; + for (val i <- Iterator.range(0, alts.length)) { + if (isAccessible(alts(i), site)) + nacc = nacc + 1; + } + if (nacc == 0) { + error(pos, "" + sym + " cannot be accessed in " + site.getType().widen()); + Type.ErrorType + } else { + val alts1: Array[Symbol] = new Array[Symbol](nacc); + val alttypes1: Array[Type] = new Array[Type](nacc); + nacc = 0; + for (val i <- Iterator.range(0, alts.length)) { + if (isAccessible(alts(i), site)) { + alts1(nacc) = alts(i); + alttypes1(nacc) = alttypes(i); + nacc = nacc + 1; + } + } + new Type$OverloadedType(alts1, alttypes1) + } + case _ => + if (isAccessible(sym, site)) { + symtype + } else { + error(pos, "" + sym + " cannot be accessed in " + site.getType().widen()); + Type.ErrorType + } + } + } + } + + /** Is `sym' accessible as a member of tree `site' in current context? + */ + private def isAccessible(sym: Symbol, site: Tree): boolean = { + + /** Are we inside definition of `owner'? + */ + def accessWithin(owner: Symbol): boolean = { + var c: Context = context; + while (c != Context.NONE && c.owner != owner) { + c = c.outer.enclClass; + } + c != Context.NONE; + } + + /** Is `clazz' a subclass of an enclosing class? + */ + def isSubClassOfEnclosing(clazz: Symbol): boolean = { + var c: Context = context; + while (c != Context.NONE && !clazz.isSubClass(c.owner)) { + c = c.outer.enclClass; + } + c != Context.NONE; + } + + (sym.flags & (PRIVATE | PROTECTED)) == 0 + || + accessWithin(sym.owner()) + || + ((sym.flags & PRIVATE) == 0) && + site.getType().symbol().isSubClass(sym.owner()) && + (site.isInstanceOf[Tree$Super] || + isSubClassOfEnclosing(site.getType().symbol())) + } + +// Checking methods ---------------------------------------------------------- + + /** 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 + * - symbols with `override' modifier override some other symbol. + */ + def validate(sym: Symbol): unit = { + if ((sym.flags & (ABSTRACT | OVERRIDE)) == ABSTRACT && sym.kind != CLASS) { + error(sym.pos, "`abstract' modifier can be used only for classes; " + + "\nit should be omitted for abstract members"); + } + if ((sym.flags & OVERRIDE) != 0 && sym.kind == CLASS) { + error(sym.pos, "`override' modifier not allowed for classes"); + } + if ((sym.flags & DEF) != 0 && sym.owner().isPrimaryConstructor() && + (sym.owner().constructorClass().flags & CASE) != 0) { + error(sym.pos, "`def' modifier not allowed for case class parameters"); + } + /*!!! + if ((sym.flags & REPEATED) != 0 && sym.owner().isPrimaryConstructor()) { + error(sym.pos, "`*' modifier not allowed for class parameters"); + } + */ + if ((sym.flags & DEFERRED) != 0) { + if (sym.owner().kind != CLASS || (sym.owner().flags & MODUL) != 0 || sym.owner().isAnonymousClass()) { + error(sym.pos, + "only classes can have declared but undefined members" + + (if ((sym.flags & MUTABLE) == 0) "" + else "\n(Note that variables need to be initialized to be defined)")); + sym.flags = sym.flags & ~DEFERRED; + } + } + checkNoConflict(sym, DEFERRED, PRIVATE); + checkNoConflict(sym, FINAL, SEALED); + checkNoConflict(sym, FINAL, PRIVATE); + checkNoConflict(sym, PRIVATE, PROTECTED); + checkNoConflict(sym, PRIVATE, OVERRIDE); + checkNoConflict(sym, DEFERRED, FINAL); + } + + /** Check that + * - all parents are class types + * - supertype conforms to supertypes of all mixin types. + * - final 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. + * - parent constructors do not refer to value parameters of class. + * - no two parents define same symbol. + */ + def validateParentClasses(constrs: Array[Tree], parents: Array[Type], selfType: Type): unit = { + var i = 0; + while (i < parents.length) { + if (!checkClassType(constrs(i).pos, parents(i))) return; + val bsym: Symbol = parents(i).symbol(); + if (i == 0) { + if ((bsym.flags & (JAVA | INTERFACE)) == (JAVA | INTERFACE)) + error(constrs(0).pos, "superclass may not be a Java interface"); + } else { + if ((bsym.flags & (JAVA | INTERFACE)) == JAVA) + error(constrs(i).pos, "Java class may not be used as mixin"); + val grandparents = parents(i).parents(); + if (grandparents.length > 0 && !parents(0).isSubType(grandparents(0))) + error(constrs(i).pos, "illegal inheritance;\n " + parents(0) + + " does not conform to " + parents(i) + "'s supertype"); + } + if ((bsym.flags & FINAL) != 0) { + error(constrs(i).pos, "illegal inheritance from final class"); + } else if (bsym.isSealed() || + bsym.isSubClass(definitions.ANYVAL_CLASS) || + bsym.isSubClass(definitions.ARRAY_CLASS)) { + // are we in same scope as base type definition? + val e: Scope$Entry = context.scope.lookupEntry(bsym.name); + if (e.sym != bsym || e.owner != context.scope) { + // we are not within same statement sequence + var c: Context = context; + while (c != Context.NONE && c.owner != bsym) + c = c.outer; + if (c == Context.NONE) { + error(constrs(i).pos, "illegal inheritance from sealed class"); + } + } + } + if (!selfType.isSubType(parents(i).instanceType())) { + error(constrs(i).pos, "illegal inheritance;\n self-type " + + selfType + " does not conform to " + parents(i) + + "'s selftype " + parents(i).instanceType()); + } + for (val j <- Iterator.range(0, i)) { + if (parents(i).symbol() == parents(j).symbol()) + error(constrs(i).pos, "" + parents(i).symbol() + " is inherited twice"); + } + i = i + 1; + } + } + + /** Check that type is a class type. + */ + private def checkClassType(pos: int, tp: Type): boolean = { + tp.unalias() match { + case Type$TypeRef(_, sym, _) => + if (sym.kind == CLASS) return true; + else if (sym.kind == ERROR) return false; + case Type.ErrorType => + return false; + case _ => + } + error(pos, "class type expected"); + false + } + + /** Check that type is an object type + */ + private def checkObjectType(pos: int, tp: Type): Type = + if (tp.isObjectType()) tp + else { + if (tp != Type.ErrorType) error(pos, "object type expected"); + Type.ErrorType + } + + /** Check that type is eta-expandable (i.e. no `def' or `*' parameters) + */ + def checkEtaExpandable(pos: int, tp: Type): unit = tp match { + case Type$MethodType(params, restype) => + for (val i <- Iterator.range(0, params.length)) { + if ((params(i).flags & DEF) != 0) + error(pos, "method with `def' parameters needs to be fully applied"); + if ((params(i).flags & REPEATED) != 0) + error(pos, "method with `*' parameters needs to be fully applied"); + } + checkEtaExpandable(pos, restype); + case _ => + } + + /** Check that `sym' does not contain both `flag1' and `flag2' + */ + def checkNoConflict(sym: Symbol, flag1: int, flag2: int): unit = { + if ((sym.flags & (flag1 | flag2)) == (flag1 | flag2)) { + if (flag1 == DEFERRED) + error(sym.pos, "abstract member may not have " + + Modifiers$Helper.toString(flag2) + " modifier"); + else + error(sym.pos, "illegal combination of modifiers: " + + Modifiers$Helper.toString(flag1) + " and " + + Modifiers$Helper.toString(flag2)); + } + } + + /** Check that type `tp' is not a subtype of itself. + */ + def checkNonCyclic(pos: int, tp: Type): unit = tp match { + case Type$TypeRef(pre, sym, args) => + sym.initialize(); + if ((sym.flags & LOCKED) != 0) { + error(pos, "cyclic aliasing or subtyping involving " + sym); + } else if (sym.kind == ALIAS || sym.kind == TYPE) { + sym.flags = sym.flags | LOCKED; + //System.out.println("checking " + sym);//DEBUG + checkNonCyclic( + pos, pre.memberInfo(sym).subst(sym.typeParams(), args)); + if (sym.kind == TYPE) + checkNonCyclic( + pos, pre.memberLoBound(sym).subst(sym.typeParams(), args)); + sym.flags = sym.flags & ~LOCKED; + } + + case Type$CompoundType(parents, members) => + for (val i <- Iterator.range(0, parents.length)) { + checkNonCyclic(pos, parents(i)); + } + + case Type$SingleType(pre, sym) => + sym.initialize(); + if ((sym.flags & LOCKED) != 0) { + error(pos, "cyclic aliasing or subtyping involving " + sym); + } + + case _ => + } + + /** Check that type does not refer to components defined in current scope. + */ + def checkNoEscape(pos: int, tp: Type): Type = { + + val checkNoEscapeMap = new Type$Map() { + override def apply(t: Type): Type = { + t.unalias() match { + case Type$TypeRef(pre, sym, args) => + if (pre.isInstanceOf[Type$ThisType]) checkNoEscape(t, sym); + case Type$SingleType(Type$ThisType(_), sym) => + checkNoEscape(t, sym); + case _ => + } + return map(t); + } + private def checkNoEscape(t: Type, sym: Symbol): unit = { + val e: Scope$Entry = context.scope.lookupEntry(sym.name); + if (e.sym == sym && e.owner == context.scope && + !(e.sym.kind == TYPE && (e.sym.flags & PARAM) != 0)) { + throw new Type$Error( + "type " + t + " escapes its defining scope"); + } + } + }; + + try { + checkNoEscapeMap.apply(tp) + } catch { + case ex: Type$Error => + if ((mode & EXPRmode) != 0 && infer.isFullyDefined(pt)) pt + else { + error(pos, ex.msg + " as part of " + tp.unalias()); + Type.ErrorType + } + } + } + + /** Check that there are no dependent parameter types among parameters + */ + def checkNoEscapeParams(vparams: Array[Array[Tree$ValDef]]): unit = { + for (val i <- Iterator.range(0, vparams.length)) + for (val j <- Iterator.range(0, vparams(i).length)) + checkNoEscape(vparams(i)(j).pos, vparams(i)(j).tpe.getType()); + } + + /** Check that tree represents a pure definition. + */ + def checkPureDef(tree: Tree, clazz: Symbol): unit = { + if (!TreeInfo.isPureDef(tree) && tree.getType() != Type.ErrorType) + error(tree.pos, "" + clazz + " may contain only pure definitions"); + } + + /** Check that tree represents a pure constructor. + */ + def checkPureConstr(tree: Tree, clazz: Symbol): unit = { + if (!TreeInfo.isPureConstr(tree) && tree.getType() != Type.ErrorType) + error(tree.pos, "" + clazz + " may invoke only pure superclass constructors"); + } + + /** Check that tree represents a trait constructor. + */ + def checkTrait(tree: Tree, clazz: Symbol): unit = { + if (!tree.getType().symbol().isTrait() && tree.getType() != Type.ErrorType) + error(tree.pos, " " + clazz + " may inherit only traits as mixins"); + } + + /** Check that tree is a stable expression .p + */ + def checkStable(tree: Tree): Tree = + if (TreeInfo.isPureExpr(tree) || tree.getType() == Type.ErrorType) tree; + else error(tree.pos, "stable identifier required, but " + tree + " found."); + + /** Check that class can be instantiated. + */ + def checkInstantiatable(pos: int, tp: Type): unit = { + val clazz: Symbol = tp.symbol(); + if (clazz.kind == CLASS) { + if (clazz.isAbstractClass()) + error(pos, "" + clazz + " is abstract, so it cannot be instantiated"); + else if (!tp.isSubType(tp.instanceType())) + error(pos, "" + tp + " does not conform to its self-type " + + tp.instanceType() + ", so it cannot be instantiated"); + } + } + + /** Check that all subtrees have their types defined. + * Used for asserting an internal invariant + */ + private class CheckDefined extends Traverser { + var all: Tree = null; + override def traverse(tree: Tree): unit = { + if (tree.getType() == null) assert(false, "" + tree + " in " + all); + if (tree.getType() != Type.ErrorType) + super.traverse(tree); + } + } + + private val checkDefined: CheckDefined = new CheckDefined(); + + // Helper definitions for calculating types ----------------------------------------- + + /** The qualifier type of a potential application of the `match' method. + * or NoType, if this is something else. + */ + private def matchQualType(fn: Tree): Type = { + fn match { + case Tree$Select(qual, _) => + if (fn.symbol() == definitions.ANY_MATCH) + return qual.getType().widen(); + + case Tree$TypeApply(fn1, _) => + return matchQualType(fn1); + + case Tree$Ident(_) => + if (fn.symbol() == definitions.ANY_MATCH) + return context.enclClass.owner.typeOfThis(); + + case _ => + } + if (fn.getType() == Type.ErrorType) Type.ErrorType else Type.NoType + } + + private def isSetterMethod(sym: Symbol): boolean = + sym != null && + !sym.isLocal() && + !sym.isStable() && + sym.getType().isInstanceOf[Type$PolyType] && + sym.typeParams().length == 0; + +// Contexts ------------------------------------------------------------------- + + /** Push new context associated with given tree, owner, and scope on stack. + * Fields `imports' and, possibly, `enclClass' are inherited from parent. + */ + def pushContext(tree: Tree, owner: Symbol, scope: Scope): unit = + context = new Context(tree, owner, scope, context); + + /** Pop context from stack. + */ + def popContext(): unit = + context = context.outer; + + // Lazy Types ------------------------------------------------------------------ + + /** A lazy type which, when forced returns the type of a symbol defined + * in `tree'. + */ + class LazyTreeType(_tree: Tree) extends Type$LazyType { + val tree: Tree = _tree; + val u: Unit = unit; + val c: Context = context; + + override def complete(sym: Symbol): unit = { + defineSym(tree, u, c); + } + } + + /** A lazy type for case constructor methods (whose name is a term name) + * which sets the method's type to the class constructor type. + */ + class LazyConstrMethodType(_tree: Tree) extends LazyTreeType(_tree) { + override def complete(sym: Symbol): unit = { + val constr: Symbol = tree.symbol().primaryConstructor(); + if (!sym.isInitialized()) + sym.setInfo(constr.getType().instanceType().cloneType(constr, sym)); + } + } + + /** A lazy type for self types + */ + class LazySelfType(clazz: Symbol, tree: Tree) extends LazyTreeType(tree) { + override def complete(sym: Symbol): unit = { + defineSelfType(sym, clazz, tree, u, c); + } + } + +// Entering Symbols ---------------------------------------------------------- + + def transformPackageId(tree: Tree): Tree = { + if (tree.getType() != null) return tree; + tree match { + case Tree$Ident(name) => + tree + .setSymbol(packageSymbol(tree.pos, context.owner, name)) + .setType(tree.symbol().getType()) + + case Tree$Select(qual, name) => + val qual1: Tree = transformPackageId(qual); + val sym: Symbol = packageSymbol(tree.pos, qual1.symbol(), name); + copy.Select(tree, sym, qual1).setType(sym.getType()) + + case _ => + transform(tree); + } + } + + def packageSymbol(pos: int, base: Symbol, name: Name): Symbol = { + var p: Symbol = base.members().lookup(name); + if (p.kind == NONE) { + p = TermSymbol.newJavaPackageModule(name, base.moduleClass(), null); + base.members().enter(p); + } else if (!p.isPackage()) { + error(pos, "package and class with same name"); + p = Symbol.ERROR; + } + p + } + + /** Enter symbol `sym' in current scope. Check for double definitions. + * Handle overloading. + */ + def enterInScope(sym: Symbol): unit = { + // handle double and overloaded definitions + val e: Scope$Entry = context.scope.lookupEntry(sym.name); + val other: Symbol = e.sym; + if (sym == other) { + if (global.debug) global.log("redefined: " + sym + ":" + sym.rawInfo()); + } else if (e.owner == context.scope) { + assert(!other.isExternal(), other); + if (sym.owner().isPackage()) { + if (global.compiledNow.get(other) != null) { + error(sym.pos, "" + sym + " is compiled twice"); + } + context.scope.unlink(e); + context.scope.enter(sym); + } else if (context.owner.kind == CLASS && sym.kind == VAL && other.kind == VAL && ((sym.flags & ACCESSOR) == 0 || (other.flags & ACCESSOR) == 0)) { + e.setSymbol(other.overloadWith(sym)); + } else { + if (context.owner.kind == CLASS) + error(sym.pos, + sym.nameString() + " is already defined as " + + other + other.locationString()); + else + error(sym.pos, + sym.nameString() + + " is already defined in local scope"); + } + } else { + context.scope.enter(sym); + } + if (sym.owner().isPackage()) + global.compiledNow.put(sym, unit.source); + } + + /** If `tree' is a definition, create a symbol for it with a lazily + * constructed type, and enter into current scope. + */ + def enterSym(tree: Tree): Symbol = { + + /** Enter `sym' in current scope and make it the symbol of `tree'. + */ + def enterSym(tree: Tree, sym: Symbol): Symbol = { + //if (global.debug) System.out.println("entering " + sym);//DEBUG + if (!sym.isInitialized()) { + //System.err.println("undefined: " + sym + ":" + sym.rawInfo());//DEBUG + sym.setInfo(new LazyTreeType(tree)); + } + if (!sym.isConstructor()) { + val owner: Symbol = sym.owner(); + if (sym.kind == VAL && (sym.flags & (PRIVATE | SEALED)) == 0 && + owner != null && owner.kind == CLASS && + (owner.flags & FINAL) != 0) + sym.flags = sym.flags | FINAL; + enterInScope(sym); + } + tree.setSymbol(sym); + + // set the comment associated with a symbol + val comment: String = global.mapTreeComment.get(tree).asInstanceOf[String]; + if (comment != null) + global.mapSymbolComment.put(sym, comment); + + sym + } + + /** Make `sym' the symbol of import `tree' and create an entry in + * current imports list. + */ + def enterImport(tree: Tree, sym: Symbol): Symbol = { + sym.setInfo(new LazyTreeType(tree)); + tree.setSymbol(sym); + context.imports = new ImportList(tree, context.scope, context.imports); + sym + } + + val owner: Symbol = context.owner; + tree match { + case Tree$PackageDef(_packaged, templ) => + var packaged = _packaged; + templ match { + case Tree$Template(_, body) => + pushContext(tree, context.owner, context.scope); + context.imports = null; + packaged = transformPackageId(packaged); + tree.asInstanceOf[Tree$PackageDef].packaged = packaged; + popContext(); + val pkg: Symbol = checkStable(packaged).symbol(); + if (pkg != null && pkg.kind != ERROR) { + if (pkg.isPackage()) { + pushContext(templ, pkg.moduleClass(), pkg.members()); + enterSyms(body); + popContext(); + } else { + error(tree.pos, "only Java packages allowed for now"); + } + } + templ.setSymbol(Symbol.NONE); + null + case _ => + throw new ApplicationError(); + } + + case Tree$ClassDef(mods, name, tparams, vparams, _, templ) => + val clazz: ClassSymbol = ClassSymbol.define( + tree.pos, name, owner, mods, context.scope); + if (clazz.isLocalClass()) unit.mangler.setMangledName(clazz); + if (!clazz.primaryConstructor().isInitialized()) + clazz.primaryConstructor().setInfo(new LazyTreeType(tree)); + if ((mods & CASE) != 0) { + if ((mods & ABSTRACT) == 0) { + // enter case constructor method. + val cf: Symbol = TermSymbol.define( + tree.pos, name.toTermName(), owner, + mods & ACCESSFLAGS | CASE, context.scope); + enterInScope(cf); + if (!cf.isInitialized() || cf.info().symbol().isModuleClass()) { + cf.setInfo(new LazyConstrMethodType(tree)); + } + } + } + enterSym(tree, clazz) + + case Tree$ModuleDef(mods, name, _, _) => + val modul: TermSymbol = TermSymbol.define( + tree.pos, name, owner, mods, context.scope).makeModule(); + val clazz: Symbol = modul.moduleClass(); + if (!clazz.isInitialized()) + clazz.setInfo(new LazyTreeType(tree)); + if (clazz.isLocalClass()) unit.mangler.setMangledName(clazz); + enterSym(tree, modul) + + case Tree$ValDef(mods, name, _, _) => + enterSym( + tree, + TermSymbol.define(tree.pos, name, owner, mods, context.scope)) + + case Tree$DefDef(mods, name, _, _, _, _) => + var sym: Symbol = null; + if (name == Names.CONSTRUCTOR) { + val clazz: Symbol = context.enclClass.owner; + if (!(context.tree.isInstanceOf[Tree$Template]) || + clazz.isModuleClass() || + clazz.isAnonymousClass() || + clazz.isCompoundSym() || + clazz.isPackage()) { + error(tree.pos, "constructor definition not allowed here"); + } + sym = context.enclClass.owner.addConstructor(); + } else { + sym = TermSymbol.define(tree.pos, name, owner, mods, context.scope); + } + enterSym(tree, sym); + + case Tree$AliasTypeDef(mods, name, _, _) => + val tsym: Symbol = AliasTypeSymbol.define(tree.pos, name, owner, mods, context.scope); + if (!tsym.primaryConstructor().isInitialized()) + tsym.primaryConstructor().setInfo(new LazyTreeType(tree)); + enterSym(tree, tsym) + + case Tree$AbsTypeDef(mods, name, _, _) => + enterSym( + tree, + AbsTypeSymbol.define(tree.pos, name, owner, mods, context.scope)) + + case Tree$Import(expr, selectors) => + enterImport(tree, + new TermSymbol( + tree.pos, + Name.fromString("import " + expr), + Symbol.NONE, SYNTHETIC)) + + case _ => + null + } + } + + /** Enter all symbols in statement list + */ + def enterSyms(stats: Array[Tree]): unit = { + for (val i <- Iterator.range(0, stats.length)) + enterSym(stats(i)); + } + + def enterParams[t <: Tree](params: Array[t]): Array[Symbol] = { + for (val i <- Iterator.range(0, params.length)) { + enterSym(params(i)); + (params(i) : Tree) match { + case Tree$ValDef(mods, _, _, _) => + if ((mods & REPEATED) != 0 && params.length > 1) + error(params(i).pos, + "`*' parameter must be the only parameter of a `('...`)' section"); + case _ => + } + } + Tree.symbolOf(params.asInstanceOf[Array[Tree]]) + } + + def enterParams(vparams: Array[Array[Tree$ValDef]]): Array[Array[Symbol]] = { + val vparamSyms = new Array[Array[Symbol]](vparams.length); + for (val i <- Iterator.range(0, vparams.length)) { + vparamSyms(i) = enterParams(vparams(i)); + } + vparamSyms + } + + /** Re-enter type parameters in current scope. + */ + def reenterParams(tparams: Array[Tree$AbsTypeDef], tsyms: Array[Symbol]): unit = { + for (val i <- Iterator.range(0, tparams.length)) { + tsyms(i).pos = tparams(i).pos; + tsyms(i).name = tparams(i).name; + //necessary since tsyms might have been unpickled + tparams(i).setSymbol(tsyms(i)); + context.scope.enter(tsyms(i)); + } + } + + /** Re-enter type and value parameters in current scope. + */ + def reenterParams(tparams: Array[Tree$AbsTypeDef], vparamss: Array[Array[Tree$ValDef]], mt: Type): unit = { + var rest: Type = mt; + rest match { + case Type$PolyType(tsyms, restp) => + reenterParams(tparams, tsyms); + rest = restp; + case _ => + } + for (val j <- Iterator.range(0, vparamss.length)) { + val vparams = vparamss(j); + rest match { + case Type$MethodType(vsyms, restp) => + for (val i <- Iterator.range(0, vparams.length)) { + vsyms(i).pos = vparams(i).pos; + vsyms(i).name = vparams(i).name; + //necessary since vsyms might have been unpickled + vparams(i).setSymbol(vsyms(i)); + context.scope.enter(vsyms(i)); + } + rest = restp; + case _ => + } + } + } + +// Definining Symbols ------------------------------------------------------- + + /** Define symbol associated with `tree' using given `unit' and `context'. + */ + def defineSym(tree: Tree, unit: Unit, curcontext: Context): unit = { + val savedUnit: Unit = this.unit; + this.unit = unit; + val savedContext: Context = this.context; + this.context = curcontext; + val savedMode: int = this.mode; + this.mode = EXPRmode; + val savedPt: Type = this.pt; + this.pt = Type.AnyType; + + try { + val sym: Symbol = tree.symbol(); + if (global.debug) global.log("defining " + sym); + var owntype: Type = null; + tree match { + case Tree$ClassDef(mods, name, tparams, vparams, tpe, templ) => + pushContext( + tree, sym.primaryConstructor(), new Scope(context.scope)); + val tparamSyms = enterParams(tparams); + var vparamSyms = enterParams(vparams); + if (vparamSyms.length == 0) + vparamSyms = NewArray.SymbolArray{Symbol.EMPTY_ARRAY}; + if ((mods & CASE) != 0 && vparams.length > 0) + templ.body = desugarize.addCaseElements(templ.body, vparams(0)); + + val constrtype: Type = makeMethodType( + tparamSyms, + vparamSyms, + new Type$TypeRef(sym.owner().thisType(), sym, Symbol.getType(tparamSyms))); + //System.out.println("set info " + sym.constructor() + " to " + constrtype + " was " + sym.constructor().rawInfo());//DEBUG + sym.primaryConstructor().setInfo(constrtype); + // necessary so that we can access tparams + sym.primaryConstructor().flags = + sym.primaryConstructor().flags | INITIALIZED; + + if (tpe != Tree.Empty) + sym.setTypeOfThis(new LazySelfType(sym, tpe)); + + defineTemplate(templ, sym, new Scope()); + owntype = templ.getType(); + popContext(); + + case Tree$ModuleDef(mods, name, _tpe, templ) => + var tpe = _tpe; + val clazz: Symbol = sym.moduleClass(); + defineTemplate(templ, clazz, new Scope()); + clazz.setInfo(templ.getType()); + tpe = transform(tpe, TYPEmode); + (tree.asInstanceOf[Tree$ModuleDef]).tpe = tpe; + if (tpe != Tree.Empty) + clazz.setTypeOfThis(new LazySelfType(sym, tpe)); + owntype = if (tpe == Tree.Empty) clazz.getType() else tpe.getType(); + + case Tree$DefDef(mods, name, tparams, vparams, _tpe, _rhs) => + var tpe = _tpe; + var rhs = _rhs; + var restype: Type = null; + pushContext(tree, sym, new Scope(context.scope)); + if (name == Names.CONSTRUCTOR) + context.enclClass.owner.flags = + context.enclClass.owner.flags | INCONSTRUCTOR; + val tparamSyms = enterParams(tparams); + val vparamSyms = enterParams(vparams); + if (tpe != Tree.Empty) { + tpe = transform(tpe, TYPEmode); + (tree.asInstanceOf[Tree$DefDef]).tpe = tpe; + restype = tpe.getType(); + } else if (name == Names.CONSTRUCTOR) { + restype = context.enclClass.owner.getType().subst( + context.enclClass.owner.typeParams(), tparamSyms); + context.enclClass.owner.flags = + context.enclClass.owner.flags & ~INCONSTRUCTOR; + } else { + rhs = transform(rhs, EXPRmode); + (tree.asInstanceOf[Tree$DefDef]).rhs = rhs; + restype = rhs.getType(); + if (!sym.isFinal()) restype = restype.deconst(); + } + restype = checkNoEscape(tpe.pos, restype); + popContext(); + owntype = makeMethodType(tparamSyms, vparamSyms, restype); + //System.out.println("methtype " + name + ":" + owntype);//DEBUG + + case Tree$ValDef(mods, name, _tpe, _rhs) => + var tpe = _tpe; + var rhs = _rhs; + if (tpe != Tree.Empty) { + tpe = transform(tpe, TYPEmode); + (tree.asInstanceOf[Tree$ValDef]).tpe = tpe; + owntype = tpe.getType(); + } else { + pushContext(tree, sym, context.scope); + if (rhs == Tree.Empty) { + if ((sym.owner().flags & ACCESSOR) != 0) { + // this is the parameter of a variable setter method. + assert((sym.flags & PARAM) != 0); + owntype = sym.owner().accessed().getType(); + } else { + error(tree.pos, "missing parameter type"); + owntype = Type.ErrorType; + } + } else { + if ((sym.flags & CASEACCESSOR) != 0) { + rhs.setType(rhs.symbol().getType()); + } else { + rhs = transform(rhs, EXPRmode); + (tree.asInstanceOf[Tree$ValDef]).rhs = rhs; + } + owntype = rhs.getType(); + if (sym.isVariable() || !sym.isFinal()) + owntype = owntype.deconst(); + } + popContext(); + } + + case Tree$AliasTypeDef(mods, name, tparams, _rhs) => + var rhs = _rhs; + pushContext(tree, sym.primaryConstructor(), new Scope(context.scope)); + val tparamSyms = enterParams(tparams); + sym.primaryConstructor().setInfo( + new Type$PolyType(tparamSyms, sym.typeConstructor())); + // necessary so that we can access tparams + sym.primaryConstructor().flags = + sym.primaryConstructor().flags | INITIALIZED; + rhs = transform(rhs, TYPEmode); + (tree.asInstanceOf[Tree$AliasTypeDef]).rhs = rhs; + owntype = rhs.getType(); + popContext(); + + case Tree$AbsTypeDef(mods, name, _rhs, _lobound) => + var rhs = _rhs; + var lobound = _lobound; + //can't have `sym' as owner since checkNonCyclic would fail. + rhs = transform(rhs, TYPEmode); + tree.asInstanceOf[Tree$AbsTypeDef].rhs = rhs; + lobound = transform(lobound, TYPEmode); + (tree.asInstanceOf[Tree$AbsTypeDef]).lobound = lobound; + owntype = rhs.getType(); + sym.setLoBound(lobound.getType()); + owntype.symbol().initialize();//to detect cycles todo: needed? + + case Tree$Import(_expr, selectors) => + val expr = transform(_expr, EXPRmode | QUALmode); + tree.asInstanceOf[Tree$Import].expr = expr; + checkStable(expr); + owntype = expr.getType(); + val tp: Type = owntype.widen(); + for (val i <- Iterator.range(0, selectors.length)) { + if (selectors(i) != Names.IMPORT_WILDCARD && + tp.lookup(selectors(i)) == Symbol.NONE && + tp.lookup(selectors(i).toTypeName()) == Symbol.NONE) + error(tree.pos, "" + NameTransformer.decode(selectors(i)) + " is not a member of " + expr + " of type " + expr.getType()); + } + + case _ => + throw new ApplicationError(); + } + sym.setInfo(owntype); + validate(sym); + if (global.debug) global.log("defined " + sym); + } catch { + case ex: Type$Error => + reportTypeError(tree.pos, ex); + tree.setType(Type.ErrorType); + if (tree.hasSymbol()) { + if (tree.symbol() != null) tree.symbol().setInfo(Type.ErrorType); + else tree.setSymbol(Symbol.ERROR); + } + } + + this.unit = savedUnit; + this.context = savedContext; + this.mode = savedMode; + this.pt = savedPt; + } + + /** Definition phase for a template. This enters all symbols in template + * into symbol table. + */ + def defineTemplate(templ: Tree$Template, clazz: Symbol, members: Scope): unit = { + // attribute parent constructors + val constrs = transformConstrInvocations(templ.pos, templ.parents); + val parents = Tree.typeOf(constrs); + + // enter all members + pushContext(templ, clazz, members); + templ.body = desugarize.Statements(templ.body, false); + enterSyms(templ.body); + popContext(); + templ.setType(Type.compoundType(parents, members, clazz)); + } + + def makeMethodType(tparams: Array[Symbol], vparams: Array[Array[Symbol]], restpe: Type): Type = + if (tparams.length == 0 && vparams.length == 0) { + new Type$PolyType(tparams, restpe); + } else { + var result: Type = restpe; + var i = vparams.length - 1; + while (i >= 0) { + result = new Type$MethodType(vparams(i), result); + i = i - 1; + } + if (tparams.length != 0) + result = new Type$PolyType(tparams, result); + result + } + + def makeStableId(pos: int, tp: Type): Tree = + if (tp.symbol().isCompoundSym()) gen.This(pos, tp.symbol()) + else gen.mkStableId(pos, tp); + + /** Define self type of class or module `sym' + * associated with `tree' using given `unit' and `context'. + */ + def defineSelfType(sym: Symbol, clazz: Symbol, tree: Tree, unit: Unit, curcontext: Context): unit = { + val savedUnit: Unit = this.unit; + this.unit = unit; + val savedContext: Context = this.context; + this.context = curcontext; + + val selftype: Type = transform(tree, TYPEmode).getType(); + selftype match { + case Type$CompoundType(parts, members) => + val parts1 = new Array[Type](parts.length + 1); + System.arraycopy(parts.asInstanceOf[Array[Object]], 0, + parts1.asInstanceOf[Array[Object]], 0, parts.length); + parts1(parts.length) = clazz.getType(); + sym.setInfo(Type.compoundType(parts1, members)); + + case _ => + sym.setInfo( + Type.compoundType( + NewArray.Type(selftype, clazz.getType()), Scope.EMPTY)); + } + + this.unit = savedUnit; + this.context= savedContext; + } + +// Attribution and Transform ------------------------------------------------- + + /** Turn tree type into stable type if possible and required by + * context. + */ + def mkStable(tree: Tree, pre: Type, mode: int, pt: Type): Tree = { + tree.getType() match { + case Type$ConstantType(_, value) => + return make.Literal(tree.pos, value).setType(tree.getType()) + case Type$PolyType(tparams, restp) => + if (tparams.length == 0) { + restp match { + case Type$ConstantType(_, value) => + return make.Literal(tree.pos, value).setType(tree.getType()); + case _ => + } + } + case _ => + } + if ((pt != null && pt.isStable() || (mode & QUALmode) != 0) && pre.isStable()) { + var sym: Symbol = tree.symbol(); + tree.getType() match { + case Type$OverloadedType(alts, alttypes) => + if ((mode & FUNmode) == 0) { + try { + infer.exprAlternative(tree, alts, alttypes, pt); + sym = tree.symbol(); + } catch { + case ex: Type$Error => + reportTypeError(tree.pos, ex); + } + } + case _ => + } + if (sym.isStable()) { + tree.setType(Type.singleType(pre, sym)); + } + } + tree + } + + /** Adapt tree to given mode and given prototype + */ + def adapt(tree: Tree, mode: int, pt: Type): Tree = { + //System.out.println(tree + ":" + tree.getType() + " adapt " + pt + " " + mode);//DEBUG + tree.getType() match { + case Type$OverloadedType(alts, alttypes) => + // resolve overloading + if ((mode & FUNmode) == 0) { + try { + infer.exprAlternative(tree, alts, alttypes, pt); + } catch { + case ex: Type$Error => + reportTypeError(tree.pos, ex); + } + tree.getType() match { + case Type$OverloadedType(_, _) => + // overload resolution failed bcs no alternative matched prototype. + typeError(tree.pos, tree.getType(), pt); + tree.setSymbol(Symbol.ERROR).setType(Type.ErrorType); + case _ => + } + return adapt(tree, mode, pt); + } + + case Type$PolyType(tparams, restp) => + // apply parameterless functions + // instantiate polymorphic expressions + if (tparams.length == 0) { + return adapt(tree.setType(restp), mode, pt); + } else if ((mode & (FUNmode | POLYmode)) == 0) { + var tree1: Tree = null; + try { + tree1 = infer.exprInstance(tree, tparams, restp, pt); + } catch { + case ex: Type$Error => + tree1 = error(tree.pos, ex.msg); + } + return adapt(tree1, mode, pt); + } + + case Type$MethodType(_, _) => + // convert unapplied methods to functions. + if ((mode & (EXPRmode | FUNmode)) == EXPRmode && infer.isCompatible(tree.getType(), pt)) { + checkEtaExpandable(tree.pos, tree.getType()); + return transform(desugarize.etaExpand(tree, tree.getType()), mode, pt); + } else if ((mode & (CONSTRmode | FUNmode)) == CONSTRmode) { + return error(tree.pos, "missing arguments for class constructor"); + } + + case _ => + } + if ((mode & PATTERNmode) != 0) { + if (tree.isType()) { + val clazz: Symbol = tree.getType().withDefaultArgs().unalias().symbol(); + + if (clazz.isCaseClass()) { + // set type to instantiated case class constructor + tree.setType(tree.getType().prefix().memberType(clazz.primaryConstructor())); + // MZ: this is a hack, but I didn't know how to do it better + if ((clazz.flags & (JAVA | CASE)) == (JAVA | CASE)) { + val altconstr = clazz.allConstructors().alternativeSymbols(); + tree.setType(tree.getType().prefix().memberType( + altconstr(altconstr.length - 1))); + } + tree.getType() match { + case Type$PolyType(tparams, restp) => + try { + infer.constructorInstance(tree, tparams, restp, pt); + //System.out.println("constr inst " + ArrayApply.toString(tparams) + restp + " against " + pt + " = " + tree.getType());//DEBUG + } catch { + case ex: Type$Error => + if (pt != Type.ErrorType) error(tree.pos, ex.msg); + tree.setType(Type.ErrorType); + } + case _ => + } + } else if (clazz.isSubClass(definitions.SEQ_CLASS)) { + // set type to instantiated sequence class constructor + // todo: should we admit even supertypes of the target type? + val seqtp: Type = pt.baseType(clazz); + if (seqtp != Type.NoType) { + def seqConstructorType(paramtp: Type, resulttp: Type) = { + val constr: Symbol = resulttp.symbol().primaryConstructor(); + val param: Symbol = new TermSymbol( + Position.NOPOS, Names.PATTERN_WILDCARD, constr, PARAM | REPEATED).setInfo( + paramtp.baseType(definitions.SEQ_CLASS)); + new Type$MethodType(NewArray.Symbol(param), resulttp); + } + tree.setType(seqConstructorType(seqtp, pt)); + } else { + return error(tree.pos, "expected pattern type " + pt + + " does not conform to sequence " + clazz); + } + } else if (tree.getType() != Type.ErrorType) { + return error(tree.pos, "" + tree.getType().symbol() + + " is neither a case class constructor nor a sequence class constructor"); + } + } + if ((mode & FUNmode) != 0) { + return tree; + } else { + val sym: Symbol = tree.symbol(); + // check that idents or selects are stable. + tree match { + case Tree$Ident(_) | Tree$Select(_, _) => + checkStable(tree); + case _ => + } + } + } else if ((mode & EXPRmode) != 0) { + if ((mode & FUNmode) != 0) { + if (tree.getType().isObjectType()) { + // insert apply method + val applyMeth: Symbol = tree.getType().lookup(Names.apply); + if (applyMeth != Symbol.NONE) { + val applyType: Type = checkAccessible( + tree.pos, applyMeth, tree.getType().memberType(applyMeth), + tree); + val tree1 = make.Select(tree.pos, tree, Names.apply) + .setSymbol(applyMeth) + .setType(applyType); + return adapt(tree1, mode, pt); + } + } + } else if ((mode & QUALmode) == 0) { + // check that packages and static modules are not used as values + tree match { + case Tree$Ident(_) | Tree$Select(_, _) => + val sym: Symbol = tree.symbol(); + if (sym != null && sym.kind != ERROR && !sym.isValue()) { + return error(tree.pos, "" + tree.symbol() + " is not a value"); + } + case _ => + } + } + } + + var owntype: Type = tree.getType(); + if ((mode & (CONSTRmode | FUNmode)) == (CONSTRmode)) { + owntype = owntype.instanceType(); + // this works as for superclass constructor calls the expected + // type `pt' is always AnyType (see transformConstrInvocations). + } + if (!(owntype.isInstanceOf[Type$PolyType] || owntype.isSubType(pt))) { + tree match { + case Tree$Literal(value) => + var n: int = Integer.MAX_VALUE; + if (value.isInstanceOf[Integer]) + n = value.asInstanceOf[Integer].intValue(); + else if (value.isInstanceOf[Character]) + n = value.asInstanceOf[Character].charValue(); + val value1: Object = + if (pt.symbol() == definitions.BYTE_CLASS && -128 <= n && n <= 127) + new Byte(n.asInstanceOf[byte]) + else if (pt.symbol() == definitions.SHORT_CLASS && -32768 <= n && n <= 32767) + new Short(n.asInstanceOf[short]) + else if (pt.symbol() == definitions.CHAR_CLASS && 0 <= n && n <= 65535) + new Character(n.asInstanceOf[char]) + else null; + if (value1 != null) + return make.Literal(tree.pos, value1).setType(new Type$ConstantType(pt, value1)); + case _ => + } + if ((mode & EXPRmode) != 0) { + if (pt.symbol() == definitions.UNIT_CLASS) { + return gen.Block(NewArray.Tree(tree, gen.mkUnitLit(tree.pos))); + } else { + val coerceMeth: Symbol = tree.getType().lookup(Names.coerce); + if (coerceMeth != Symbol.NONE) { + val coerceType: Type = checkAccessible( + tree.pos, coerceMeth, tree.getType().memberType(coerceMeth), + tree); + val tree1 = make.Select(tree.pos, tree, Names.coerce) + .setSymbol(coerceMeth) + .setType(coerceType); + return adapt(tree1, mode, pt); + } + } + } + if ((mode & CONSTRmode) == 0) { + typeError(tree.pos, owntype, pt); + Type.explainTypes(owntype, pt); + tree.setType(Type.ErrorType); + } // for constructors, delay until after the `new'. + } + tree + } + + /** 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. + */ + def transformIdent(_tree: Tree, name: Name): Tree = { + var tree = _tree; + //System.out.println("transforming " + name);//DEBUG + // find applicable definition and assign to `sym' + var sym: Symbol = Symbol.NONE; + var pre: Type = null; + var qual: Tree = Tree.Empty; + var stopPos: int = Integer.MIN_VALUE; + var nextcontext: Context = context; + while (sym.kind == NONE && nextcontext != Context.NONE) { + sym = nextcontext.scope.lookup(name); + if (sym.kind != NONE) { + stopPos = sym.pos; + } else { + nextcontext = nextcontext.enclClass; + if (nextcontext != Context.NONE) { + sym = nextcontext.owner.thisSym().info().lookup(name); + if (sym.kind != NONE) { + stopPos = nextcontext.owner.pos; + } else { + nextcontext = nextcontext.outer; + } + } + } + } + + // find applicable import and assign to `sym1' + var nextimports: ImportList = context.imports; + var lastimports: ImportList = null; + var sym1: Symbol = Symbol.NONE; + +// System.out.println("name = " + name + ", pos = " + tree.pos + ", importlist = ");//DEBUG +// for (val imp: ImportList = nextimports; imp != null; imp = imp.prev) { +// new TextTreePrinter().print(" ").print(imp.tree).println().end();//DEBUG +// } + + while (nextimports != null && nextimports.tree.pos >= tree.pos) { + nextimports = nextimports.prev; + } + while (sym1.kind == NONE && nextimports != null && nextimports.tree.pos > stopPos) { + sym1 = nextimports.importedSymbol(name); + lastimports = nextimports; + nextimports = nextimports.prev; + } + + // evaluate what was found + if (sym1.kind == NONE) { + if (sym.kind == NONE) { + //System.out.println(name);//DEBUG + error(tree.pos, "not found: " + decode(name)); + return tree.setSymbol(Symbol.ERROR).setType(Type.ErrorType); + } else { + if (sym.owner().kind == CLASS) { + pre = nextcontext.enclClass.owner.thisType(); + if (!sym.owner().isPackage()) { + val qual1: Tree = makeStableId(tree.pos, pre); + tree = make.Select(tree.pos, qual1, name); + //System.out.println(name + " :::> " + tree + " " + qual1.symbol());//DEBUG + } + } else { + pre = Type.localThisType; + } + } + } else if (sym.kind != NONE && !sym.isExternal()) { + return error(tree.pos, + "reference to " + name + " is ambiguous;\n" + + "it is both defined in " + sym.owner() + + " and imported subsequently by \n" + nextimports.tree); + } else { + // check that there are no other applicable imports in same scope. + while (nextimports != null && nextimports.enclScope == lastimports.enclScope) { + if (!nextimports.sameImport(lastimports) && nextimports.importedSymbol(name).kind != NONE) { + return error(tree.pos, + "reference to " + name + " is ambiguous;\n" + + "it is imported twice in the same scope by\n " + + lastimports.tree + "\nand " + nextimports.tree); + } + nextimports = nextimports.prev; + } + sym = sym1; + qual = lastimports.importPrefix().duplicate(); + pre = qual.getType(); + //new TextTreePrinter().print(name + " => ").print(lastimports.tree).print("." + name).println().end();//DEBUG + tree = make.Select(tree.pos, qual, name); + } + + var symtype: Type = + (if (sym.isType()) sym.typeConstructor() else sym.getType()) + .asSeenFrom(pre, sym.owner()); + if (qual != Tree.Empty) + symtype = checkAccessible(tree.pos, sym, symtype, qual); + if (symtype == Type.NoType) + return error(tree.pos, "not found: " + decode(name)); + //System.out.println(name + ":" + symtype);//DEBUG + mkStable(tree.setSymbol(sym).setType(symtype), pre, mode, pt) + } + + /** Attribute a selection where `tree' is `qual.name'. + * `qual' is already attributed. + */ + def transformSelect(tree: Tree, _qual: Tree, name: Name): Tree = { + var qual = _qual; + var uninst: Array[Symbol] = Symbol.EMPTY_ARRAY; + qual.getType() match { + case Type$PolyType(tparams, restype) => + qual = infer.mkTypeApply(qual, tparams, restype, Symbol.getType(tparams)); + uninst = tparams; + case _ => + } + val sym: Symbol = qual.getType().lookup(name); + if (sym.kind == NONE) { + //System.out.println(qual.getType() + " has members " + qual.getType().members());//DEBUG + error(tree.pos, + decode(name) + " is not a member of " + qual.getType().widen()); + } else { + var symtype: Type = + (if (sym.isType()) sym.typeConstructor() else sym.getType()) + .asSeenFrom(qual.getType(), sym.owner()); + if (symtype == Type.NoType) + return error(tree.pos, "not found: " + decode(name)); + else + symtype = checkAccessible(tree.pos, sym, symtype, qual); + //System.out.println(sym.name + ":" + symtype);//DEBUG + if (uninst.length != 0) { + symtype match { + case Type$PolyType(tparams, restype) => + symtype = new Type$PolyType(tparams, new Type$PolyType(uninst, restype)); + case _ => + symtype = new Type$PolyType(uninst, symtype); + } + } + //System.out.println(qual.getType() + ".member: " + sym + ":" + symtype);//DEBUG + val tree1: Tree = tree match { + case Tree$Select(_, _) => + copy.Select(tree, sym, qual) + case Tree$SelectFromType(_, _) => + copy.SelectFromType(tree, sym, qual) + } + mkStable(tree1.setType(symtype), qual.getType(), mode, pt) + } + } + + /** Attribute a pattern matching expression where `pattpe' is the + * expected type of the patterns and `pt' is the expected type of the + * results. + */ + def transformVisitor(tree: Tree, pattpe: Type, pt: Type): Tree = + //System.out.println("trans visitor with " + pattpe + "," + pt);//DEBUG + tree match { + case Tree$Visitor(cases) => + val cases1 = cases; + for (val i <- Iterator.range(0, cases.length)) + cases1(i) = transformCase(cases(i), pattpe, pt); + return copy.Visitor(tree, cases1) + .setType(Type.lub(Tree.typeOf(cases1.asInstanceOf[Array[Tree]]))); + case _ => + throw new ApplicationError(); + } + + /** Attribute a case where `pattpe' is the expected type of the pattern + * and `pt' is the expected type of the result. + */ + def transformCase(tree: Tree$CaseDef, pattpe: Type, pt: Type): Tree$CaseDef = + tree match { + case Tree$CaseDef(pat, guard, body) => + pushContext(tree, context.owner, new Scope(context.scope)); + this.inAlternative = false; // no vars allowed below Alternative + val pat1: Tree = transform(pat, PATTERNmode, pattpe); + val guard1: Tree = + if (guard == Tree.Empty) Tree.Empty + else transform(guard, EXPRmode, definitions.BOOLEAN_TYPE()); + val body1: Tree = transform(body, EXPRmode, pt); + popContext(); + return copy.CaseDef(tree, pat1, guard1, body1) + .setType(body1.getType()).asInstanceOf[Tree$CaseDef]; + } + + def transformStatSeq(stats: Array[Tree], exprOwner: Symbol): Array[Tree] = { + var stats1 = stats; + for (val i <- Iterator.range(0, stats.length)) { + val stat: Tree = stats(i); + if (context.owner.isCompoundSym() && !TreeInfo.isDeclaration(stat)) { + error(stat.pos, "only declarations allowed here"); + } + val mode: int = if (TreeInfo.isDefinition(stat)) NOmode else EXPRmode; + var stat1: Tree = null; + if (exprOwner.kind != NONE && !TreeInfo.isDefinition(stat)) { + pushContext(stat, exprOwner, context.scope); + stat1 = transform(stat, mode); + popContext(); + } else { + stat1 = transform(stat, mode); + } + // todo: if we comment next 4 lines out, test/pos/scoping2 fails. + // find out why + if (stat1 != stat && stats1 == stats) { + stats1 = new Array[Tree](stats.length); + System.arraycopy(stats.asInstanceOf[Array[Object]], 0, + stats1.asInstanceOf[Array[Object]], 0, i); + } + stats1(i) = stat1; + } + stats1 + } + + /** Attribute a sequence of constructor invocations. + */ + def transformConstrInvocations(pos: int, constrs: Array[Tree]): Array[Tree] = { + for (val i <- Iterator.range(0, constrs.length)) { + constrs(i) = transform(constrs(i), CONSTRmode | SUPERmode, Type.AnyType); + val f: Symbol = TreeInfo.methSymbol(constrs(i)); + if (f != null) { + val c: Symbol = f.constructorClass(); + if (c.kind == CLASS) { + c.initialize();//to detect cycles + if (i > 0 && (c.flags & JAVA) == 0 && c.isExternal()) { + // need to load tree for mixins + new SourceCompleter(global, true).complete(c); + } + } + } + } + constrs + } + + def transformConstrInvocationArgs(constrs: Array[Tree]): unit = { + for (val i <- Iterator.range(0, constrs.length)) { + constrs(i) match { + case Tree$Apply(fn, args) => + if (fn.getType().isInstanceOf[Type$MethodType]) + transformArgs( + constrs(i).pos, TreeInfo.methSymbol(fn), Symbol.EMPTY_ARRAY, + fn.getType(), EXPRmode, args, Type.AnyType); + case _ => + } + } + } + + /** Attribute a template + */ + def transformTemplate(templ: Tree$Template, owner: Symbol): Tree$Template = { + if (global.debug) global.log("transforming template of " + owner);//debug + if (templ.getType() == null) + defineTemplate(templ, owner, owner.members());//may happen for mixins + //System.out.println(owner.info());//DEBUG + val parents = templ.parents; + transformConstrInvocationArgs(parents); + if (owner.kind != ERROR) { + validateParentClasses(parents, owner.info().parents(), owner.typeOfThis()); + } + pushContext(templ, owner, owner.members()); + templ.setSymbol(TermSymbol.newLocalDummy(owner)); + val body1 = transformStatSeq(templ.body, templ.symbol()); + popContext(); + if (owner.isTrait()) { + for (val i <- Iterator.range(0, parents.length)) { + checkPureConstr(parents(i), owner); + if (i >= 1) checkTrait(parents(i), owner); + } + for (val i <- Iterator.range(0, templ.body.length)) + checkPureDef(body1(i), owner); + } + val templ1: Tree$Template = copy.Template(templ, parents, body1); + templ1.setType(owner.getType()); + templ1 + } + + /** Attribute an argument list. + * @param pos Position for error reporting + * @param meth The symbol of the called method, or `null' if none exists. + * @param tparams The type parameters that need to be instantiated + * @param methtype The method's type w/o type parameters + * @param argMode The argument mode (either EXPRmode or PATTERNmode) + * @param args The actual arguments + * @param pt The proto-resulttype. + * @return The vector of instantiated argument types, or null if error. + */ + def transformArgs(pos: int, meth: Symbol, tparams: Array[Symbol], methtype: Type, argMode: int, args: Array[Tree], pt: Type): Array[Type] = { + //System.out.println("trans args " + meth + ArrayApply.toString(tparams) + ":" + methtype + "," + pt);//DEBUG + val argtypes = new Array[Type](args.length); + methtype match { + case Type$MethodType(params, restp) => + val formals = infer.formalTypes(params, args.length); + if (formals.length != args.length) { + error(pos, "wrong number of arguments for " + + (if (meth == null) "<function>" else meth) + + ArrayApply.toString(formals.asInstanceOf[Array[Object]], "(", ",", ")")); + return null; + } + if (tparams.length == 0) { + for (val i <- Iterator.range(0, args.length)) { + args(i) = transform(args(i), argMode, formals(i)); + argtypes(i) = args(i).getType().deconst(); + } + } else { + // targs: the type arguments inferred from the prototype + val targs: Array[Type] = infer.protoTypeArgs(tparams, restp, pt, params); + + // argpts: prototypes for arguments + val argpts = new Array[Type](formals.length); + for (val i <- Iterator.range(0, formals.length)) + argpts(i) = formals(i).subst(tparams, targs); + + // transform arguments with (targs/tparams)formals as prototypes + for (val i <- Iterator.range(0, args.length)) + args(i) = transform( + args(i), argMode | POLYmode, formals(i).subst(tparams, targs)); + + // targs1: same as targs except that every AnyType is mapped to + // formal parameter type. + val targs1 = new Array[Type](targs.length); + for (val i <- Iterator.range(0, targs.length)) + targs1(i) = if (targs(i) != Type.AnyType) targs(i) + else tparams(i).getType(); + + for (val i <- Iterator.range(0, args.length)) { + argtypes(i) = args(i).getType().deconst(); + argtypes(i) match { + case Type$PolyType(tparams1, restype1) => + argtypes(i) = infer.argumentTypeInstance( + tparams1, restype1, + formals(i).subst(tparams, targs1), + argpts(i)); + case _ => + } + } + } + // desugarizing ident patterns + if (params.length == 1 && (params(0).flags & REPEATED) != 0) { + if ((mode & PATTERNmode) != 0) { + def desug_allIdentPatterns(trees: Array[Tree], currentOwner: Symbol): unit = { + for (val i <- Iterator.range(0, trees.length)) + trees(i) match { + case Tree$Ident(name) => + if (name != Names.PATTERN_WILDCARD) { + val vble: Symbol = context.scope.lookup(name); + trees(i) = desugarize.IdentPattern(trees(i)).setSymbol(vble) + .setType(vble.getType()); + } else { + trees(i) = gen.Ident(trees(i).pos, definitions.PATTERN_WILDCARD); + } + case _ => + } + } + desug_allIdentPatterns(args, context.owner); + } else { + assert(args.length != 1 || !(args(0).isInstanceOf[Tree$Sequence])); + } + } + argtypes; + + case Type$PolyType(tparams1, restp) => + var tparams2: Array[Symbol] = tparams1; + if (tparams.length != 0) { + tparams2 = new Array[Symbol](tparams.length + tparams1.length); + System.arraycopy(tparams.asInstanceOf[Array[Object]], 0, + tparams2.asInstanceOf[Array[Object]], 0, + tparams.length); + System.arraycopy(tparams1.asInstanceOf[Array[Object]], 0, + tparams2.asInstanceOf[Array[Object]], tparams.length, + tparams1.length); + } + transformArgs(pos, meth, tparams2, restp, argMode, args, pt) + + case Type.ErrorType => + for (val i <- Iterator.range(0, args.length)) { + args(i) = transform(args(i), argMode, Type.ErrorType); + argtypes(i) = args(i).getType().deconst(); + } + argtypes + + case _ => + for (val i <- Iterator.range(0, args.length)) { + args(i) = transform(args(i), argMode, Type.AnyType); + argtypes(i) = args(i).getType().deconst(); + } + argtypes + } + } + + /** Atribute an expression or pattern with prototype `pt'. + * Check that expression's type conforms to `pt'. + * Resolve overloading and apply parameterless functions. + * Insert `apply' function if needed. + */ + def transform(tree: Tree, mode: int, pt: Type): Tree = { + val savedMode: int = this.mode; + val savedPt: Type = this.pt; + this.mode = mode; + this.pt = pt; + val tree1: Tree = adapt(transform(tree), mode, pt); + + assert(tree.getType() != Type.AnyType, tree);//debug + + //new TextTreePrinter().print(tree1).print(": " + tree1.getType()).println().end();//DEBUG + + this.mode = savedMode; + this.pt = savedPt; + tree1 + } + + /** Transform expression or type with a given mode. + */ + def transform(tree: Tree, mode: int): Tree = { + if ((mode & (EXPRmode | PATTERNmode | CONSTRmode)) != 0) + return transform(tree, mode, Type.AnyType); + + val savedMode: int = this.mode; + this.mode = mode; + val tree1: Tree = transform(tree); + this.mode = savedMode; + + if ((mode & TYPEmode) != 0) { + val sym: Symbol = tree1.symbol(); + if ((mode & FUNmode) == 0 && sym != null && sym.typeParams().length != 0) + return error(tree.pos, "" + sym + " takes type parameters.") +// else if (tree1.isType()) +// return gen.mkType(tree1.pos, tree1.getType()); + } + tree1 + } + + def transform(trees: Array[Tree], mode: int): Array[Tree] = { + for (val i <- Iterator.range(0, trees.length)) + trees(i) = transform(trees(i), mode); + trees + } + + override def transform(trees: Array[Tree]): Array[Tree] = + super.transform(trees); + + override def transform(trees: Array[Tree$CaseDef]): Array[Tree$CaseDef] = + super.transform(trees); + + override def transform(trees: Array[Tree$AbsTypeDef]): Array[Tree$AbsTypeDef] = + super.transform(trees); + + override def transform(trees: Array[Tree$ValDef]): Array[Tree$ValDef] = + super.transform(trees); + + override def transform(trees: Array[Array[Tree$ValDef]]): Array[Array[Tree$ValDef]] = + super.transform(trees); + + /** The main attribution function + */ + override def transform(tree: Tree): Tree = { + + def qualifyingClass(tree: Tree, name: Name): Symbol = { + if (name == TypeNames.EMPTY) { + val clazz: Symbol = context.enclClass.owner; + if (clazz != null) + clazz + else { + error(tree.pos, "" + tree + + " can be used only in a class, object, or template"); + Symbol.ERROR + } + } else { + var i: Context = context; + while (i != Context.NONE && + !(i.owner.kind == CLASS && i.owner.name == name)) + i = i.outer; + if (i != Context.NONE) + i.owner + else { + error(tree.pos, "" + name + " is not an enclosing class"); + Symbol.ERROR + } + } + } + + //System.out.println("transforming " + tree);//DEBUG + if (tree.getType() != null) { + checkDefined.all = tree; checkDefined.traverse(tree);//debug + return tree; + } + val sym: Symbol = tree.symbol(); + if (sym != null && !sym.isInitialized()) sym.initialize(); + if (global.debug && TreeInfo.isDefinition(tree)) global.log("transforming definition of " + sym); + try { + tree match { + case Tree$Bad() => + tree.setSymbol(Symbol.ERROR).setType(Type.ErrorType) + + case Tree.Empty => + tree.setType(Type.NoType) + + case Tree$PackageDef(pkg, templ @ Tree$Template(parents, body)) => + val pkgSym: Symbol = pkg.symbol(); + if (pkgSym != null && pkgSym.isPackage()) { + pushContext(templ, pkgSym, pkgSym.members()); + val body1: Array[Tree] = transform(body); + popContext(); + val templ1: Tree$Template = copy.Template(templ, parents, body1); + templ1.setType(Type.NoType).setSymbol(Symbol.NONE); + copy.PackageDef(tree, pkg, templ1) + .setType(Type.NoType); + } else { + tree.setType(Type.ErrorType); + } + + case Tree$PackageDef(_, _) => + tree.setType(Type.ErrorType) + + case Tree$ClassDef(_, _, tparams, vparams, tpe, templ) => + pushContext( + tree, sym.primaryConstructor(), new Scope(context.scope)); + reenterParams(tparams, vparams, sym.primaryConstructor().getType()); + val tparams1 = transform(tparams); + val vparams1 = transform(vparams); + checkNoEscapeParams(vparams1); + val tpe1: Tree = transform(tpe, TYPEmode); + if ((sym.flags & CASE) != 0 && vparams.length > 0 && templ.getType() == null) + templ.body = desugarize.addCaseElements(templ.body, vparams(0)); + + val templ1: Tree$Template = transformTemplate(templ, sym); + checkNoEscape(tree.pos, sym.info()); + popContext(); + copy.ClassDef(tree, sym, tparams1, vparams1, tpe1, templ1) + .setType(Type.NoType); + + case Tree$ModuleDef(_, _, tpe, templ) => + sym.moduleClass().initialize(); + val tpe1: Tree = transform(tpe, TYPEmode); + val templ1: Tree$Template = transformTemplate(templ, sym.moduleClass()); + if (tpe1 != Tree.Empty && !templ1.getType().isSubType(tpe1.getType())) + error(tree.pos, "" + sym + " does not implement " + tpe1.getType()); + copy.ModuleDef(tree, sym, tpe1, templ1) + .setType(Type.NoType); + + case Tree$DefDef(_, name, tparams, vparams, tpe, rhs) => + pushContext(tree, sym, new Scope(context.scope)); + reenterParams(tparams, vparams, sym.getType()); + if (name == Names.CONSTRUCTOR) + context.enclClass.owner.flags = context.enclClass.owner.flags | INCONSTRUCTOR; + val tparams1 = transform(tparams); + val vparams1 = transform(vparams); + checkNoEscapeParams(vparams1); + val tpe1: Tree = + if (tpe == Tree.Empty) gen.mkType(tree.pos, sym.getType().resultType()) + else transform(tpe, TYPEmode); + var rhs1: Tree = + if (rhs == Tree.Empty) rhs + else transform( + rhs, + if (name == Names.CONSTRUCTOR) CONSTRmode else EXPRmode, + tpe1.getType()); + popContext(); + context.enclClass.owner.flags = context.enclClass.owner.flags & ~INCONSTRUCTOR; + sym.flags = sym.flags | LOCKED; + checkNonCyclic(tree.pos, tpe1.getType()); + sym.flags = sym.flags & ~LOCKED; + copy.DefDef(tree, sym, tparams1, vparams1, tpe1, rhs1) + .setType(Type.NoType); + + case Tree$ValDef(_, _, tpe, rhs) => + val tpe1: Tree = + if (tpe == Tree.Empty) gen.mkType(tree.pos, sym.getType()) + else transform(tpe, TYPEmode); + var rhs1: Tree = rhs; + if (rhs != Tree.Empty) { + pushContext(tree, sym, context.scope); + rhs1 = transform(rhs, EXPRmode, tpe1.getType()); + popContext(); + } else if ((sym.flags & (MUTABLE | DEFERRED)) == MUTABLE) { + rhs1 = gen.mkDefaultValue(tree.pos, sym.getType()); + } + sym.flags = sym.flags | LOCKED; + checkNonCyclic(tree.pos, tpe1.getType()); + sym.flags = sym.flags & ~LOCKED; + copy.ValDef(tree, sym, tpe1, rhs1) + .setType(Type.NoType); + + case Tree$AbsTypeDef(_, _, rhs, lobound) => + val rhs1: Tree = transform(rhs, TYPEmode); + val lobound1: Tree = transform(lobound, TYPEmode); + checkNonCyclic(tree.pos, sym.getType()); + copy.AbsTypeDef(tree, sym, rhs1, lobound1) + .setType(Type.NoType); + + case Tree$AliasTypeDef(_, _, tparams, rhs) => + pushContext(tree, sym.primaryConstructor(), new Scope(context.scope)); + reenterParams(tparams, sym.typeParams()); + val tparams1 = transform(tparams); + val rhs1: Tree = transform(rhs, TYPEmode); + popContext(); + checkNonCyclic(tree.pos, sym.getType()); + copy.AliasTypeDef(tree, sym, tparams1, rhs1) + .setType(Type.NoType); + + case Tree$Import(expr, selectors) => + context.imports = new ImportList(tree, context.scope, context.imports); + Tree.Empty + + case Tree$Block(stats) => + pushContext(tree, context.owner, new Scope(context.scope)); + val stats1 = desugarize.Statements(stats, true); + enterSyms(stats1); + context.imports = context.outer.imports; + val curmode: int = mode; + val owntype: Type = + if ((curmode & CONSTRmode) != 0) { + stats1(0) = transform(stats1(0), curmode, pt); + context.enclClass.owner.flags = context.enclClass.owner.flags & ~INCONSTRUCTOR; + for (val i <- Iterator.range(1, stats1.length)) + stats1(i) = transform(stats1(i), EXPRmode); + stats1(0).getType() + } else { + for (val i <- Iterator.range(0, stats1.length - 1)) + stats1(i) = transform(stats1(i), EXPRmode); + if (stats1.length > 0) { + stats1(stats1.length - 1) = + transform(stats1(stats1.length - 1), curmode & ~FUNmode, pt); + checkNoEscape(tree.pos, stats1(stats1.length - 1).getType()) + } else { + definitions.UNIT_TYPE() + } + } + popContext(); + copy.Block(tree, stats1) + .setType(owntype); + + case Tree$Sequence(trees) => + for (val i <- Iterator.range(0, trees.length)) { + trees(i) = transform(trees(i), + this.mode | SEQUENCEmode, + pt); + } + copy.Sequence(tree, trees).setType(pt); + + case Tree$Alternative(choices) => + val save: boolean = this.inAlternative; + this.inAlternative = true; + + val newts = new Array[Tree](choices.length); + for (val i <- Iterator.range(0, choices.length)) + newts(i) = transform(choices(i), this.mode, pt); + + //val tpe: Type = Type.lub(Tree.typeOf(newts)); + + this.inAlternative = save; + copy.Alternative(tree, newts).setType(pt); + + case Tree$Bind(name, body) => + var vble: Symbol = null; + if(name != Names.PATTERN_WILDCARD) { + vble = new TermSymbol(tree.pos, + name, + context.owner, + 0x00000000).setType(pt); + enterInScope(vble); + //System.out.println("Bind("+name+",...) enters in scope:"+vble.fullNameString()); + + patternVars.put(vble, new Boolean(this.inAlternative)); + //System.out.println("case Bind.. put symbol vble="+vble+" in scope and patternVars."); + } + val body1: Tree = transform(body); + if(name == Names.PATTERN_WILDCARD) body1 + else { + //assert body1.getType() != null; + if(TreeInfo.isSequenceValued(body1)) { + vble.setType(definitions.LIST_TYPE(pt)); + } else { + vble.setType(body1.getType()); + } + copy.Bind(tree, name, body1) + .setSymbol(vble).setType(body1.getType()); + } + + case Tree$Visitor(cases) => + if (pt.symbol().isSubClass(definitions.PARTIALFUNCTION_CLASS)) { + val pft: Type = pt.baseType(definitions.PARTIALFUNCTION_CLASS); + val pftargs = pft.typeArgs(); + if (pftargs.length == 2 && infer.isFullyDefined(pftargs(0))) { + val pattype: Type = pftargs(0); + var restype: Type = pftargs(1); + val isDefinedAtVisitor: Tree = transformVisitor( + desugarize.isDefinedAtVisitor(tree), + pattype, definitions.BOOLEAN_TYPE()); + val applyVisitor: Tree = transformVisitor(tree, pattype, restype); + if (!infer.isFullyDefined(restype)) + restype = applyVisitor.getType().deconst(); + if (definitions.PARTIALFUNCTION_CLASS.isExternal()) + // need to load tree for mixins + new SourceCompleter(global, true).complete( + definitions.PARTIALFUNCTION_CLASS); + gen.mkPartialFunction( + tree.pos, applyVisitor, isDefinedAtVisitor, + pattype, restype, context.owner); + } else { + error(tree.pos, "expected pattern type of cases could not be determined"); + } + } else { + transform(desugarize.Visitor(tree)) + } + + case Tree$Assign(Tree$Apply(_, _), _) => + transform(desugarize.Update(tree)) + + case Tree$Assign(lhs, rhs) => + val lhs1: Tree = transform(lhs, EXPRmode); + val varsym: Symbol = lhs1.symbol(); + if (isSetterMethod(varsym)) { + // todo: change this to require setters in same template + transform(desugarize.Assign(tree.pos, lhs, rhs)); + } else if (varsym != null && (varsym.flags & MUTABLE) != 0) { + val rhs1: Tree = transform(rhs, EXPRmode, lhs1.getType()); + copy.Assign(tree, lhs1, rhs1) + .setType(definitions.UNIT_TYPE()); + } else { + if (lhs1.getType() != Type.ErrorType) + error(tree.pos, "assignment to non-variable "); + errorTree(tree.pos); + } + + case Tree$If(cond, thenp, elsep) => + val cond1: Tree = transform(cond, EXPRmode, definitions.BOOLEAN_TYPE()); + var thenp1: Tree = _, elsep1: Tree = _; + if (elsep == Tree.Empty) { + thenp1 = transform(thenp, EXPRmode, definitions.UNIT_TYPE()); + elsep1 = make.Block(tree.pos, Tree.EMPTY_ARRAY) + .setType(definitions.UNIT_TYPE()); + } else { + thenp1 = transform(thenp, EXPRmode, pt); + elsep1 = transform(elsep, EXPRmode, pt); + } + copy.If(tree, cond1, thenp1, elsep1) + .setType(Type.lub(NewArray.Type(thenp1.getType(), elsep1.getType()))); + + case Tree$Throw(expr) => + val expr1: Tree = transform( + expr, EXPRmode, definitions.JAVA_THROWABLE_TYPE()); + gen.Select(tree.pos, expr1, definitions.JAVA_THROWABLE_THROW); + + case Tree$Return(expr) => + if (!context.owner.isInitialized()) { + error(tree.pos, "method with return needs result type"); + } else { + val enclFun: Symbol = context.owner.enclMethod(); + if (enclFun.kind == VAL && !enclFun.isConstructor()) { + val expr1: Tree = transform( + expr, EXPRmode, enclFun.getType().resultType()); + copy.Return(tree, expr1) + .setSymbol(enclFun).setType(definitions.ALL_TYPE()); + } else { + error(tree.pos, "return outside method definition"); + } + } + + case Tree$New(templ) => + templ match { + case Tree$Template(parents, body) => + if (parents.length == 1 && body.length == 0) { + val parent1: Tree = transform(parents(0), CONSTRmode, pt); + val owntype: Type = parent1.getType(); + val templ1: Tree$Template = + copy.Template(templ, Symbol.NONE, NewArray.Tree(parent1), body) + .setType(owntype).asInstanceOf[Tree$Template]; + checkInstantiatable(tree.pos, owntype); + copy.New(tree, templ1) + .setType(owntype.instanceType()); + } else { + pushContext(tree, context.owner, new Scope(context.scope)); + val cd: Tree = make.ClassDef( + templ.pos, + 0, + Names.ANON_CLASS_NAME.toTypeName(), + Tree.AbsTypeDef_EMPTY_ARRAY, + NewArray.ValDefArray(Tree.ValDef_EMPTY_ARRAY), + Tree.Empty, + templ); + //new TextTreePrinter().print(cd).println().end();//DEBUG + enterSym(cd); + val cd1 = transform(cd); + val clazz: Symbol = cd1.symbol(); + if (clazz.kind != CLASS) + errorTree(tree.pos) + else { + // compute template's type with new refinement scope. + val parentTypes = clazz.info().parents(); + val refinement: Scope = new Scope(); + val base: Type = Type.compoundType(parentTypes, Scope.EMPTY); + val it: Scope$SymbolIterator = clazz.members().iterator(); + while (it.hasNext()) { + val sym1: Symbol = it.next(); + val basesym1: Symbol = base.lookupNonPrivate(sym1.name); + if (basesym1.kind != NONE && + !base.symbol().thisType().memberType(basesym1) + .isSameAs(sym1.getType())) + refinement.enter(sym1); + } + val owntype = + if (refinement.isEmpty() && parentTypes.length == 1) + parentTypes(0) + else + checkNoEscape( + tree.pos, + Type.compoundType(parentTypes, refinement, clazz)); + val alloc: Tree = + gen.New( + gen.Apply( + gen.mkRef( + tree.pos, + Type.localThisType, + clazz.primaryConstructor()), + Tree.EMPTY_ARRAY)) + .setType(owntype); + popContext(); + make.Block(tree.pos, NewArray.Tree(cd1, alloc)) + .setType(owntype); + } + } + } + + case Tree$Typed(expr, tpe) => + expr match { + case Tree$Ident(n) + if (n != Names.PATTERN_WILDCARD && (mode & PATTERNmode) != 0) => + transform(desugarize.TypedPattern(tree.asInstanceOf[Tree$Typed]), + mode, + pt); + case _ => + var expr1: Tree = _; + var tpe1: Tree = _; + tpe match { + case Tree$Ident(TypeNames.WILDCARD_STAR) => + expr1 = transform( + expr, mode & baseModes, definitions.SEQ_TYPE(pt)); + val elemtps = + expr1.getType().baseType(definitions.SEQ_CLASS).typeArgs(); + val elemtp: Type = if (elemtps.length == 1) elemtps(0) + else Type.ErrorType; + + tpe1 = tpe.setType(elemtp); + case _ => + tpe1 = transform(tpe, TYPEmode); + expr1 = transform(expr, mode & baseModes, tpe1.getType()); + } + copy.Typed(tree, expr1, tpe1).setType(tpe1.getType()) + } + + case Tree$Function(vparams, body) => + pushContext(tree, context.owner, new Scope(context.scope)); + var restype: Type = desugarize.preFunction(vparams, pt); + enterParams(vparams); + val vparams1 = transform(vparams); + val body1: Tree = transform(body, EXPRmode, restype); + if (!infer.isFullyDefined(restype)) + restype = body1.getType().deconst(); + popContext(); + gen.mkFunction(tree.pos, vparams1, body1, restype, context.owner); + + case Tree$TypeApply(fn, args) => + + val fn1: Tree = transform( + fn, (mode & (EXPRmode | CONSTRmode)) | FUNmode, Type.AnyType); + val args1 = transform(args, TYPEmode); + val argtypes = Tree.typeOf(args1); + + // propagate errors in arguments + var i = 0; + while (i < argtypes.length && argtypes(i) != Type.ErrorType) + i = i + 1; + if (i < argtypes.length) + tree.setType(Type.ErrorType); + else { + + // resolve overloading + fn1.getType() match { + case Type$OverloadedType(alts, alttypes) => + try { + infer.polyAlternative(fn1, alts, alttypes, args.length); + } catch { + case ex: Type$Error => reportTypeError(tree.pos, ex); + } + case _ => + } + + // match against arguments + fn1.getType() match { + case Type$PolyType(tparams, restp) if (tparams.length == argtypes.length) => + /* constant fold asInstanceOf calls. + fn1 match { + case Tree$Select(qual, name) => + if (fn1.symbol() == definitions.ANY_AS && + qual.getType().isInstanceOf[Type$ConstantType]) { + val restp1: Type = constfold.foldAsInstanceOf( + tree.pos, + qual.getType().asInstanceOf[Type$ConstantType], + argtypes(0)); + restp1 match { + case ConstantType(_, Object value) => + return make.Literal(tree.pos, value) + .setType(restp1); + case => + } + } + case _ => + } + */ + constfold.tryToFold( + copy.TypeApply(tree, fn1, args1) + .setType(restp.subst(tparams, argtypes))); + + case Type.ErrorType => + tree.setType(Type.ErrorType) + + case _ => + error(tree.pos, + infer.toString(fn1.symbol(), fn1.getType()) + + " cannot be applied to " + + ArrayApply.toString( + argtypes.asInstanceOf[Array[Object]], "(", ",", ")")); + } + } + + case Tree$Apply(fn, args) => + mode = mode & ~SEQUENCEmode; + var fn1: Tree = _; + var argMode: int = _; + var selfcc: boolean = false; + //todo: Should we pass in both cases a methodtype with + // AnyType's for args as a prototype? + if ((mode & EXPRmode) != 0) { + fn1 = transform(fn, mode | FUNmode, Type.AnyType); + argMode = EXPRmode; + } else if ((mode & PATTERNmode) != 0) { + fn1 = transform(fn, mode | FUNmode, pt); + argMode = PATTERNmode; + } else { + assert((mode & CONSTRmode) != 0); + fn1 = transform(fn, mode | FUNmode, Type.AnyType); + argMode = EXPRmode; + + // convert type to constructor + val tsym: Symbol = TreeInfo.methSymbol(fn1); + if (tsym.kind != ERROR) { + assert(tsym.isType(), tsym); + fn1.getType().withDefaultArgs().unalias() match { + case Type$TypeRef(pre, c, argtypes) => + if (c.kind != CLASS) { + error(tree.pos, + "" + tsym + " is not a class; cannot be instantiated"); + } else if (!pre.isStable()) { + error(tree.pos, "" + pre + " is not a legal prefix for a constructor"); + } else { + c.initialize(); + val constr: Symbol = c.allConstructors(); + val fn0: Tree = fn1; + fn1 = gen.mkRef(fn1.pos, pre, constr); + fn1 match { + case Tree$Select(fn1qual, _) => + fn1.setType(checkAccessible( + fn1.pos, constr, fn1.getType(), fn1qual)); + case _ => + } + if (tsym == c) { + fn0 match { + case Tree$AppliedType(_, targs) => + fn1 = gen.TypeApply(fn1, targs); + case _ => + } + } else { + // it was an alias type + // todo: handle overloaded constructors + if (argtypes.length != 0) + fn1 = gen.TypeApply( + fn1, gen.mkTypes(fn1.pos, argtypes)); + if (tsym.typeParams().length != 0 && + !(fn0.isInstanceOf[Tree$AppliedType])) + fn1.setType(new Type$PolyType( + tsym.typeParams(), fn1.getType())); + } + //System.out.println(TreeInfo.methSymbol(fn1) + ":" + tp + " --> " + fn1.getType() + " of " + fn1);//DEBUG + selfcc = TreeInfo.isSelfConstrCall(fn0); + } + + case _ => + error(tree.pos, + "" + tsym + " is not a class; cannot be instantiated"); + } + } + } + + // if function is overloaded with one alternative + // whose arity matches argument length, preselect this alternative. + fn1.getType() match { + case Type$OverloadedType(alts, alttypes) => + var matching1: int = -1; + var matching2: int = -1; + for (val i <- Iterator.range(0, alttypes.length)) { + val alttp: Type = alttypes(i) match { + case Type$PolyType(_, restp) => restp; + case t => t + } + alttp match { + case Type$MethodType(params, _) => + if (params.length == args.length || + params.length == 1 && (params(0).flags & REPEATED) != 0) { + matching2 = matching1; + matching1 = i; + } + case _ => + } + } + if (matching1 >= 0 && matching2 < 0) + fn1.setSymbol(alts(matching1)).setType(alttypes(matching1)); + case _ => + } + + def handleApply: Tree = { + // handle the case of application of match to a visitor specially + if (args.length == 1 && args(0).isInstanceOf[Tree$Visitor]) { + val pattp: Type = matchQualType(fn1); + if (pattp == Type.ErrorType) { + return tree.setType(Type.ErrorType) + } else if (pattp != Type.NoType) { + if (infer.isFullyDefined(pattp) && + !(fn1.getType().isInstanceOf[Type$PolyType] && + pattp.containsSome(fn1.getType().typeParams()))) { + val fn2: Tree = desugarize.postMatch(fn1, context.enclClass.owner); + val arg1: Tree = transformVisitor(args(0), pattp, pt); + return copy.Apply(tree, fn2, NewArray.Tree(arg1)) + .setType(arg1.getType()); + } else { + return error(tree.pos, "expected pattern type of cases could not be determined") : Tree; + } + } + } + + // return prematurely if function is a superclass constructor + // and no type arguments need to be inferred. + if ((mode & SUPERmode) != 0 && fn1.getType().isInstanceOf[Type$MethodType]) { + return copy.Apply(tree, fn1, args).setType(fn1.getType().resultType()) : Tree; + } + + // type arguments with formals as prototypes if they exist. + fn1.setType(infer.freshInstance(fn1.getType())); + val argtypes = transformArgs( + tree.pos, fn1.symbol(), Symbol.EMPTY_ARRAY, fn1.getType(), argMode, args, pt); + + if (argtypes == null) + return tree.setType(Type.ErrorType) + else { + var i: int = 0; + while (i < argtypes.length && argtypes(i) != Type.ErrorType) + i = i + 1; + if (i < argtypes.length) return tree.setType(Type.ErrorType); + } + + // resolve overloading1g + fn1.getType() match { + case Type$OverloadedType(alts, alttypes) => + try { + infer.methodAlternative(fn1, alts, alttypes, argtypes, pt); + } catch { + case ex: Type$Error => reportTypeError(tree.pos, ex); + } + case _ => + } + + // check that self constructors go backwards. + if (selfcc) { + val constr: Symbol = TreeInfo.methSymbol(fn1); + if (constr != null && constr.kind == VAL && + !(constr.getType().isInstanceOf[Type$OverloadedType]) && + constr.pos > tree.pos) + error(tree.pos, + "illegal forward reference to self constructor"); + } + + fn1.getType() match { + case Type$PolyType(tparams, restp) => + // if method is polymorphic, + // infer instance, and adapt arguments to instantiated formals + try { + fn1 = infer.methodInstance(fn1, tparams, restp, argtypes, pt); + //System.out.println(fn1 + ":" + fn1.getType());//DEBUG + } catch { + case ex: Type$Error => reportTypeError(tree.pos, ex); + } + fn1.getType() match { + case Type$MethodType(params, restp1) => + val formals = infer.formalTypes(params, args.length); + for (val i <- Iterator.range(0, args.length)) { + args(i) = adapt(args(i), argMode, formals(i)); + } + return constfold.tryToFold( + copy.Apply(tree, fn1, args) + .setType(restp1)); + case _ => + } + + case Type$MethodType(params, restp) => + // if method is monomorphic, + // check that it can be applied to arguments. + if (infer.isApplicable(fn1.getType(), argtypes, Type.AnyType)) { + return constfold.tryToFold( + copy.Apply(tree, fn1, args) + .setType(restp)); + } + + case Type.ErrorType => + return tree.setType(Type.ErrorType); + + case _ => + } + error( + tree.pos, + infer.applyErrorMsg( + "", fn1, " cannot be applied to ", argtypes, pt)); + } + + handleApply + + case Tree$Super(qualifier, mixin) => + val clazz: Symbol = qualifyingClass(tree, qualifier); + tree.setSymbol(clazz); + if (clazz == Symbol.ERROR) { + tree.setType(Type.ErrorType); + } else { + val parents = clazz.parents(); + if (mixin == TypeNames.EMPTY) { + tree.setType(parents(0).instanceType()); + } else { + var i = 0; + while (i < parents.length && parents(i).symbol().name != mixin) + i = i + 1; + if (i < parents.length) + tree.setType(parents(i).instanceType()); + else + error(tree.pos, + "" + mixin + " does not name a mixin base class of " + clazz); + } + } + + case Tree$This(name) => + val clazz: Symbol = qualifyingClass(tree, name); + tree.setSymbol(clazz); + if (clazz == Symbol.ERROR) + tree.setType(Type.ErrorType); + else + tree.setType( + if (pt != null && pt.isStable() || (mode & QUALmode) != 0) clazz.thisType() + else clazz.typeOfThis()); + + case Tree$Select(qual, name) => + val qualmode: int = EXPRmode | POLYmode | QUALmode; + var qual1: Tree = transform(qual, qualmode); + if (name.isTypeName()) + qual1 = checkStable(qual1); + transformSelect( + tree, adapt(qual1, qualmode, Type.AnyType), name); + + case Tree$Ident(name) => + if (name == Names.CONSTRUCTOR) { + assert((mode & CONSTRmode) != 0, tree); + copy.Ident(tree, context.enclClass.owner) + .setType(context.enclClass.owner.getType()); + } else if (((mode & (PATTERNmode | FUNmode)) == PATTERNmode) && name.isVariable()) { + var vble: Symbol = null, vble2: Symbol = null; + + // if vble is bound with @, there is already a symbol + if (name != Names.PATTERN_WILDCARD) { + vble2 = context.scope.lookup(name); + } + var tree1 = tree; + if (patternVars.containsKey(vble2)) + vble = vble2; + else { + vble = + if (name == Names.PATTERN_WILDCARD) + definitions.PATTERN_WILDCARD + else new TermSymbol(tree.pos, + name, + context.owner, + 0).setType(pt); + //if(((mode & SEQUENCEmode) != 0)&&(name != Names.PATTERN_WILDCARD)) { + if(name != Names.PATTERN_WILDCARD) { + // x => x @ _ in sequence patterns + tree1 = desugarize.IdentPattern(tree); + } + } + if (name != Names.PATTERN_WILDCARD) enterInScope(vble); + tree1.setSymbol(vble).setType(pt); + } else { + transformIdent(tree, name) + } + + case Tree$Literal(value) => + tree.setType(Type.constantType(value)) + + case Tree$LabelDef(name, params, body) => + assert(params.length == 0); + pushContext(tree, context.owner, new Scope(context.scope)); + val lsym: Symbol = new TermSymbol(tree.pos, name, context.owner, LABEL); + lsym.setInfo( + new Type$MethodType(Symbol.EMPTY_ARRAY, definitions.UNIT_TYPE())); + context.scope.enter(lsym); + val body1: Tree = transform(body, mode, pt); + popContext(); + copy.LabelDef(tree, lsym, params, body1) + .setSymbol(lsym).setType(definitions.UNIT_TYPE()); + + case Tree$TypeTerm() => + tree + + case Tree$SingletonType(ref) => + val ref1: Tree = transform(ref, EXPRmode | QUALmode, Type.AnyType); + copy.SingletonType(tree, ref1) + .setType(checkObjectType(tree.pos, ref1.getType().resultType())); + + case Tree$SelectFromType(qual, name) => + val qual1: Tree = transform(qual, TYPEmode); + transformSelect(tree, qual1, name); + + case Tree$CompoundType(parents, refinements) => + val parents1 = transform(parents, TYPEmode); + val ptypes = Tree.typeOf(parents); + val members: Scope = new Scope(); + val self: Type = Type.compoundType(ptypes, members); + val clazz: Symbol = self.symbol(); + pushContext(tree, clazz, members); + for (val i <- Iterator.range(0, refinements.length)) { + val m = enterSym(refinements(i)); + m.flags = m.flags | OVERRIDE; + } + val refinements1 = transformStatSeq(refinements, Symbol.NONE); + popContext(); + copy.CompoundType(tree, parents1, refinements1) + .setType(self) + + case Tree$AppliedType(tpe, args) => + val tpe1: Tree = transform(tpe, mode | FUNmode); + val args1 = transform(args, TYPEmode); + val argtypes = Tree.typeOf(args); + val tparams = tpe1.getType().symbol().typeParams(); + var owntype: Type = Type.ErrorType; + if (tpe1.getType() != Type.ErrorType) { + if (tparams.length == args.length) + owntype = Type.appliedType(tpe1.getType(), argtypes); + else if (tparams.length == 0) + error(tree.pos, "" + tpe1.getType() + " does not take type parameters"); + else + error(tree.pos, "wrong number of type arguments for " + + tpe1.getType()); + } + copy.AppliedType(tree, tpe1, args1).setType(owntype); + + case Tree$FunType(_, _) => + transform(desugarize.FunType(tree)) + + case _ => + throw new ApplicationError("illegal tree: " + tree) + } + } catch { + case ex: Type$Error => + reportTypeError(tree.pos, ex); + tree.setType(Type.ErrorType); + if (tree.hasSymbol()) { + if (tree.symbol() != null) tree.symbol().setInfo(Type.ErrorType); + else tree.setSymbol(Symbol.ERROR); + } + tree; + } + } +} + + +// LocalWords: SOcos diff --git a/sources/scala/tools/scalac/typechecker/AnalyzerPhase.scala b/sources/scala/tools/scalac/typechecker/AnalyzerPhase.scala new file mode 100644 index 0000000000..bfa4eef3b5 --- /dev/null +++ b/sources/scala/tools/scalac/typechecker/AnalyzerPhase.scala @@ -0,0 +1,73 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +\* */ + +// $Id$ + +package scala.tools.scalac.typechecker; + +import ch.epfl.lamp.util.Position; +import scalac._; +import scalac.util._; +import scalac.ast._; +import scalac.symtab._; +import scalac.checkers._; +import java.util.HashMap; +import java.util.ArrayList; +import scala.tools.scalac.util.NewArray; + +class AnalyzerPhase(global: Global, descriptor: PhaseDescriptor) extends scalac.typechecker.AnalyzerPhase(global, descriptor) { + + val startContext = new Context( + Tree.Empty, + global.definitions.ROOT_CLASS, + global.definitions.ROOT_CLASS.members(), + Context.NONE); + startContext.enclClass = startContext; + + if (!global.noimports) { + addImport(startContext, global.definitions.getModule(Names.java_lang)); + addImport(startContext, global.definitions.getModule(Names.scala)); + } + + if (!global.noimports && !global.nopredefs) { + addImport(startContext, global.definitions.getModule(Names.scala_Predef)); + } + + val consoleContext = new Context( + Tree.Empty, + global.definitions.ROOT_CLASS, + global.definitions.ROOT_CLASS.members(), + startContext); + + val contexts = new HashMap/*<Unit,Context>*/(); + val newSources = new ArrayList/*<Unit>*/(); + + override def addConsoleImport(module: Symbol): unit = + addImport(consoleContext, module); + + private def addImport(context: Context, module: Symbol): unit = { + global.prevPhase(); + val tree = global.treeGen.mkImportAll(Position.NOPOS, module); + global.nextPhase(); + context.imports = new ImportList(tree, new Scope(), context.imports); + } + + override def apply(units: Array[Unit]): unit = + new Analyzer(global, this).apply(units); + + override def lateEnter(global: Global, unit: Unit, symbol: Symbol): unit = { + new Analyzer(global, this).lateEnter(unit, symbol); + } + + override def postCheckers(global: Global): Array[Checker] = + NewArray.Checker( + new CheckSymbols(global), + new CheckTypes(global), + new CheckOwners(global), + new CheckNames(global) + ); +} + diff --git a/sources/scala/tools/scalac/typechecker/ConstantFolder.scala b/sources/scala/tools/scalac/typechecker/ConstantFolder.scala new file mode 100644 index 0000000000..c286be870d --- /dev/null +++ b/sources/scala/tools/scalac/typechecker/ConstantFolder.scala @@ -0,0 +1,311 @@ +/* ************************************************************************ + * Pizza constant folder + * by Martin Odersky + * + * Copyright (C) 1996,97 Martin Odersky. All rights reserved. + * Permission is hereby granted to modify and use this software for research + * and teaching purposes. Modification for commercial purposes requires + * prior written permission by the author. + * The software, or modifications thereof, may be redistributed only + * if this copyright notice stays attached. + *************************************************************************/ + +package scala.tools.scalac.typechecker; + +import scalac.util._; +import scalac.ast._; +import scalac.symtab._; +import java.lang.{Byte,Character,Short,Integer,Long,Float,Double,Boolean,Object,Number} + +class ConstantFolder(ana: Analyzer) { + + import TypeTags._; + + /** fold binary operation. + */ + def foldBinary(pos: int, left: Type$ConstantType, right: Type$ConstantType, op: Name): Type = { + try { + var optype: Type = left.deconst(); + if (optype.symbol() == ana.definitions.BYTE_CLASS || + optype.symbol() == ana.definitions.CHAR_CLASS || + optype.symbol() == ana.definitions.SHORT_CLASS) + optype = ana.definitions.INT_TYPE(); + if (optype.isSubType(right.deconst())) + optype = right.deconst(); + var value: Object = null; + optype.unbox() match { + case Type$UnboxedType(INT) => + if (op == Names.ADD) + value = new Integer(left.intValue() + right.intValue()); + else if (op == Names.SUB) + value = new Integer(left.intValue() - right.intValue()); + else if (op == Names.MUL) + value = new Integer(left.intValue() * right.intValue()); + else if (op == Names.DIV) + value = new Integer(left.intValue() / right.intValue()); + else if (op == Names.MOD) + value = new Integer(left.intValue() % right.intValue()); + else if (op == Names.EQ) + value = new Boolean(left.intValue() == right.intValue()); + else if (op == Names.NE) + value = new Boolean(left.intValue() != right.intValue()); + else if (op == Names.LT) + value = new Boolean(left.intValue() < right.intValue()); + else if (op == Names.GT) + value = new Boolean(left.intValue() > right.intValue()); + else if (op == Names.LE) + value = new Boolean(left.intValue() <= right.intValue()); + else if (op == Names.GE) + value = new Boolean(left.intValue() >= right.intValue()); + else if (op == Names.OR) + value = new Integer(left.intValue() | right.intValue()); + else if (op == Names.AND) + value = new Integer(left.intValue() & right.intValue()); + else if (op == Names.XOR) + value = new Integer(left.intValue() ^ right.intValue()); + else if (op == Names.LSL) + value = new Integer(left.intValue() << right.intValue()); + else if (op == Names.LSR) + value = new Integer(left.intValue() >>> right.intValue()); + else if (op == Names.ASR) + value = new Integer(left.intValue() >> right.intValue()); + + case Type$UnboxedType(LONG) => + if (op == Names.ADD) + value = new Long(left.longValue() + right.longValue()); + else if (op == Names.SUB) + value = new Long(left.longValue() - right.longValue()); + else if (op == Names.MUL) + value = new Long(left.longValue() * right.longValue()); + else if (op == Names.DIV) + value = new Long(left.longValue() / right.longValue()); + else if (op == Names.MOD) + value = new Long(left.longValue() % right.longValue()); + else if (op == Names.EQ) + value = new Boolean(left.longValue() == right.longValue()); + else if (op == Names.NE) + value = new Boolean(left.longValue() != right.longValue()); + else if (op == Names.LT) + value = new Boolean(left.longValue() < right.longValue()); + else if (op == Names.GT) + value = new Boolean(left.longValue() > right.longValue()); + else if (op == Names.LE) + value = new Boolean(left.longValue() <= right.longValue()); + else if (op == Names.GE) + value = new Boolean(left.longValue() >= right.longValue()); + else if (op == Names.OR) + value = new Long(left.longValue() | right.longValue()); + else if (op == Names.AND) + value = new Long(left.longValue() & right.longValue()); + else if (op == Names.XOR) + value = new Long(left.longValue() ^ right.longValue()); + else if (op == Names.LSL) + value = new Long(left.longValue() << right.intValue()); + else if (op == Names.LSR) + value = new Long(left.longValue() >>> right.intValue()); + else if (op == Names.ASR) + value = new Long(left.longValue() >> right.intValue()); + + case Type$UnboxedType(FLOAT) => + if (op == Names.ADD) + value = new Float(left.floatValue() + right.floatValue()); + else if (op == Names.SUB) + value = new Float(left.floatValue() - right.floatValue()); + else if (op == Names.MUL) + value = new Float(left.floatValue() * right.floatValue()); + else if (op == Names.DIV) + value = new Float(left.floatValue() / right.floatValue()); + else if (op == Names.MOD) + value = new Float(left.floatValue() % right.floatValue()); + else if (op == Names.EQ) + value = new Boolean(left.floatValue() == right.floatValue()); + else if (op == Names.NE) + value = new Boolean(left.floatValue() != right.floatValue()); + else if (op == Names.LT) + value = new Boolean(left.floatValue() < right.floatValue()); + else if (op == Names.GT) + value = new Boolean(left.floatValue() > right.floatValue()); + else if (op == Names.LE) + value = new Boolean(left.floatValue() <= right.floatValue()); + else if (op == Names.GE) + value = new Boolean(left.floatValue() >= right.floatValue()); + + case Type$UnboxedType(DOUBLE) => + if (op == Names.ADD) + value = new Double(left.doubleValue() + right.doubleValue()); + else if (op == Names.SUB) + value = new Double(left.doubleValue() - right.doubleValue()); + else if (op == Names.MUL) + value = new Double(left.doubleValue() * right.doubleValue()); + else if (op == Names.DIV) + value = new Double(left.doubleValue() / right.doubleValue()); + else if (op == Names.MOD) + value = new Double(left.doubleValue() % right.doubleValue()); + else if (op == Names.EQ) + value = new Boolean(left.doubleValue() == right.doubleValue()); + else if (op == Names.NE) + value = new Boolean(left.doubleValue() != right.doubleValue()); + else if (op == Names.LT) + value = new Boolean(left.doubleValue() < right.doubleValue()); + else if (op == Names.GT) + value = new Boolean(left.doubleValue() > right.doubleValue()); + else if (op == Names.LE) + value = new Boolean(left.doubleValue() <= right.doubleValue()); + else if (op == Names.GE) + value = new Boolean(left.doubleValue() >= right.doubleValue()); + + case Type$UnboxedType(BOOLEAN) => + if (op == Names.EQ) + value = new Boolean(left.booleanValue() == right.booleanValue()); + else if (op == Names.NE) + value = new Boolean(left.booleanValue() != right.booleanValue()); + else if (op == Names.OR || op == Names.ZOR) + value = new Boolean(left.booleanValue() | right.booleanValue()); + else if (op == Names.AND || op == Names.ZAND) + value = new Boolean(left.booleanValue() & right.booleanValue()); + else if (op == Names.XOR) + value = new Boolean(left.booleanValue() ^ right.booleanValue()); + + case _ => + if (optype.symbol() == ana.definitions.JAVA_STRING_CLASS && + op == Names.ADD) + value = left.stringValue() + right.stringValue(); + } + if (value != null) Type.constantType(value) else Type.NoType; + } catch { + case e: ArithmeticException => + ana.unit.warning(pos, e.toString()); + Type.NoType + } + } + + /** fold unary operation. + */ + def foldUnary(pos: int, od: Type$ConstantType, op: Name): Type = { + try { + var value: Object = null; + od.deconst().unbox() match { + case Type$UnboxedType(INT) => + if (op == Names.ADD) + value = new Integer(od.intValue()); + else if (op == Names.SUB) + value = new Integer(-od.intValue()); + else if (op == Names.NOT) + value = new Integer(~od.intValue()); + + case Type$UnboxedType(LONG) => + if (op == Names.ADD) + value = new Long(od.longValue()); + else if (op == Names.SUB) + value = new Long(-od.longValue()); + else if (op == Names.NOT) + value = new Long(~od.longValue()); + + case Type$UnboxedType(FLOAT) => + if (op == Names.ADD) + value = new Float(od.floatValue()); + else if (op == Names.SUB) + value = new Float(-od.floatValue()); + + case Type$UnboxedType(DOUBLE) => + if (op == Names.ADD) + value = new Double(od.doubleValue()); + else if (op == Names.SUB) + value = new Double(-od.doubleValue()); + + case Type$UnboxedType(BOOLEAN) => + if (op == Names.ZNOT) + value = new Boolean(!od.booleanValue()); + + case _ => + } + if (value != null) Type.constantType(value) else Type.NoType; + } catch { + case e: ArithmeticException => + ana.unit.warning(pos, e.toString()); + Type.NoType + } + } + + /** fold cast operation + */ + def foldAsInstanceOf(pos: int, od: Type$ConstantType, argtype: Type): Type = { + try { + var value: Object = null; + argtype.unbox() match { + case Type$UnboxedType(BYTE) => + value = new Byte(od.intValue().asInstanceOf[byte]); + + case Type$UnboxedType(CHAR) => + value = new Character(od.intValue().asInstanceOf[char]); + + case Type$UnboxedType(SHORT) => + value = new Short(od.intValue().asInstanceOf[short]); + + case Type$UnboxedType(INT) => + value = new Integer(od.intValue()); + + case Type$UnboxedType(LONG) => + value = new Long(od.longValue()); + + case Type$UnboxedType(FLOAT) => + value = new Float(od.longValue()); + + case Type$UnboxedType(DOUBLE) => + value = new Double(od.doubleValue()); + + case Type$UnboxedType(BOOLEAN) => + value = new Boolean(od.booleanValue()); + + case _ => + } + if (value != null) new Type$ConstantType(argtype, value) else Type.NoType; + } catch { + case e: ClassCastException => + ana.unit.warning(pos, e.toString()); + Type.NoType + } + } + + /** attempt to constant fold tree. + */ + def tryToFold(tree: Tree): Tree = { + var ctp: Type = Type.NoType; + tree match { + case Tree$Apply(Tree$Select(qual, op), args) => + if (qual.getType().isInstanceOf[Type$ConstantType]) { + if (args.length == 0) + ctp = foldUnary( + tree.pos, qual.getType().asInstanceOf[Type$ConstantType], op); + else if (args.length == 1 && + args(0).getType().isInstanceOf[Type$ConstantType]) + ctp = foldBinary( + tree.pos, + qual.getType().asInstanceOf[Type$ConstantType], + args(0).getType().asInstanceOf[Type$ConstantType], + op); + } + + case Tree$TypeApply(Tree$Select(qual, op), targs) => + qual.getType() match { + case ct: Type$ConstantType if (op == Names.asInstanceOf) => + ctp = foldAsInstanceOf(tree.pos, ct, targs(0).getType()); + case _ => + } + + case _ => + } + ctp match { + case Type$ConstantType(base, value) => + ana.make.Literal(tree.pos, value).setType(ctp); + case _ => + tree + } + } +} + + + + + + diff --git a/sources/scala/tools/scalac/typechecker/Context.scala b/sources/scala/tools/scalac/typechecker/Context.scala new file mode 100644 index 0000000000..e281ce649f --- /dev/null +++ b/sources/scala/tools/scalac/typechecker/Context.scala @@ -0,0 +1,64 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** +** $Id$ +\* */ +package scala.tools.scalac.typechecker; + +import scalac.symtab._; +import scalac.ast.Tree; +import scalac.ast._; + +object Context { + val NONE = new Context(); +} + +class Context { + + var tree: Tree = _; // Tree associated with this context + var owner: Symbol = _; // The current owner + var scope: Scope = _; // The current scope + var imports: ImportList = _; // The current import list + var outer: Context = _; // The next outer context + var enclClass: Context = this; // The next outer context whose tree + // is a class template + var variance: int = _; // Variance relative to enclosing class. + var constructorClass: Symbol = _; // Class for auxiliary constructor + + def this(tree: Tree, owner: Symbol, scope: Scope, outer: Context) = { + this(); + this.tree = tree; + this.owner = owner; + this.scope = scope; + this.imports = outer.imports; + this.enclClass = if (tree.isInstanceOf[Tree$Template] || + tree.isInstanceOf[Tree$CompoundType]) this + else outer.enclClass; + this.variance = outer.variance; + this.constructorClass = outer.constructorClass; + this.outer = outer; + } + + def this(tree: Tree, outer: Context) = + this(tree, outer.owner, outer.scope, outer); + + def outerContext(clazz: Symbol): Context = { + var c = this; + while (c != Context.NONE && c.owner != clazz) c = c.outer; + c + } + + def isTopLevel(): boolean = tree match { + case Tree$Block(_) => + false + case Tree$Template(_, _) => + outer.tree.isInstanceOf[Tree$PackageDef] + case Tree.Empty => + true + case _ => + outer.isTopLevel() + } +} + diff --git a/sources/scala/tools/scalac/typechecker/DeSugarize.scala b/sources/scala/tools/scalac/typechecker/DeSugarize.scala new file mode 100644 index 0000000000..e22751e057 --- /dev/null +++ b/sources/scala/tools/scalac/typechecker/DeSugarize.scala @@ -0,0 +1,575 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ +package scala.tools.scalac.typechecker; + +import java.io._; +import java.util.ArrayList; +import java.lang.Object; + +import scalac._; +import scalac.util._; +import scalac.symtab._; +import scalac.ast._; +import scalac.typechecker.Infer; + +import scala.tools.scalac.ast.printer.TextTreePrinter; +import scala.tools.scalac.util.NewArray; + +/** A transformer for removing syntactic sugar. This transformer does + * not need any type or symbol-table information. + * + * @author Martin Odersky + * @version 2.0 + */ +class DeSugarize(make: TreeFactory, copy: TreeCopier, gen: TreeGen, infer: Infer, global: Global) { + + import Kinds._, Modifiers._; + + protected final val freshNameCreator = global.freshNameCreator; + + def this(analyzer: Analyzer, global: Global) = + this(analyzer.make, analyzer.copy, analyzer.gen, analyzer.infer, global); + +// Auxiliary definitions and functions ------------------------------------------- + + /** introduce fresh variable of the form "ds$56" + */ + def getvar(): Name = freshNameCreator.newName("ds", '$'); + + def setterName(name: Name): Name = name.append(Names._EQ); + + def parameterName(i: int): Name = Name.fromString("x$" + i); + + def tupleSelectorName(i: int): Name = Name.fromString("_" + i); + + /** extract variables from a pattern */ + def getVariables(tree: Tree, vars: ArrayList): unit = tree match { + case Tree$Ident(name) => + if (name.isVariable() && name != Names.PATTERN_WILDCARD) vars.add(name); + + case Tree$Typed(expr, _) => + getVariables(expr, vars); + + case Tree$Apply(fn, args) => + fn match { + case Tree$Apply(_, _) => getVariables(fn, vars); + case _ => + } + for (val i <- Iterator.range(0, args.length)) + getVariables(args(i), vars); + + case Tree$Sequence(elems) => + for (val i <- Iterator.range(0, elems.length)) + getVariables(elems(i), vars); + + case Tree$Literal( _ ) => + + case Tree$Bind(name, t) => + if (name.isVariable() && name != Names.PATTERN_WILDCARD) vars.add(name); + getVariables(t, vars); + + case Tree$Alternative(ts) => + for (val i <- Iterator.range(0, ts.length)) + getVariables(ts(i), vars); + } + +// Transform functions ----------------------------------------------------- + + /** (T_1, ..., T_N) => T ==> scala.FunctionN[T_1, ..., T_N, +T] + */ + def FunType(tree: Tree): Tree = tree match { + case Tree$FunType(argtpes, restpe) => + val types = new Array[Tree](argtpes.length + 1); + System.arraycopy(argtpes.asInstanceOf[Array[Object]], 0, + types.asInstanceOf[Array[Object]], 0, argtpes.length); + types(argtpes.length) = restpe; + make.AppliedType( + tree.pos, + make.Select( + tree.pos, + make.Ident(tree.pos, Names.scala), + Name.fromString("Function" + argtpes.length).toTypeName()), + types); + } + + def mkTuple(pos: int, trees: Array[Tree]): Tree = + if (trees.length == 0) + make.Block(pos, trees); + else + make.Apply( + pos, + make.Select( + pos, + make.Ident(pos, Names.scala), + Name.fromString("Tuple" + trees.length)), + trees); + + /** Convert method to function type. + */ + def meth2fun(tp: Type): Type = tp match { + case Type$MethodType(params, restype) => + global.definitions.FUNCTION_TYPE( + Symbol.getType(params), meth2fun(restype)); + case _ => + tp + } + + /** If `pt' is a matching function type insert missing parameters + * in `vparams' from it, return: and result type, + * else return AnyType. + */ + def preFunction(vparams: Array[Tree$ValDef], pt: Type): Type = pt match { + case Type$TypeRef(pre, psym, ptargs) + if (psym.fullName().startsWith(Names.scala_Function) && + ptargs.length == vparams.length + 1) => + + def assignType(vparam: Tree$ValDef, pt: Type): unit = + if (vparam.tpe == Tree.Empty && infer.isFullyDefined(pt)) + vparam.tpe = gen.mkType(vparam.pos, pt); + + for (val i <- Iterator.range(0, vparams.length)) + assignType(vparams(i), ptargs(i)); + + ptargs(vparams.length); + + case _ => + Type.AnyType + } + + def isDefinedAtVisitor(tree: Tree): Tree = tree match { + case Tree$Visitor(cases) => + val lastCase = cases(cases.length - 1); + lastCase match { + case Tree$CaseDef(Tree$Ident(name), Tree.Empty, expr) if (name.isVariable()) => + make.Visitor( + tree.pos, + NewArray.CaseDef( + make.CaseDef( + lastCase.pos, + lastCase.pat.duplicate(), + Tree.Empty, + gen.mkBooleanLit(lastCase.body.pos, true)))); + case _ => + val cases1 = new Array[Tree$CaseDef](cases.length + 1); + for (val i <- Iterator.range(0, cases.length)) { + cases(i) match { + case Tree$CaseDef(pat, guard, _) => + cases1(i) = make.CaseDef( + cases(i).pos, + pat.duplicate(), + guard.duplicate(), + gen.mkBooleanLit(tree.pos, true)); + } + } + cases1(cases.length) = make.CaseDef( + tree.pos, + gen.Ident(tree.pos, global.definitions.PATTERN_WILDCARD), + Tree.Empty, + gen.mkBooleanLit(tree.pos, false)); + make.Visitor(tree.pos, cases1); + } + } + + /** match => this.match + * match[targs] => this.match[targs] + * IMPORTANT: tree is already attributed and attributes need to be preserved. + */ + def postMatch(tree: Tree, currentclazz: Symbol): Tree = tree match { + case Tree$Ident(name) => + make.Select( + tree.pos, + gen.This(tree.pos, currentclazz), + name).setSymbol(tree.symbol()).setType(tree.getType()); + case Tree$TypeApply(fn, args) => + copy.TypeApply(tree, postMatch(fn, currentclazz), args); + case _ => + tree + } + + /** { cases } ==> (x => x.match {cases}) + * only called when match has to be added + * no type for parameter x + */ + def Visitor(tree: Tree): Tree = tree match { + case Tree$Visitor(cases) => + val x: Name = getvar(); + val param: Tree$ValDef = make.ValDef( + tree.pos, PARAM, x, Tree.Empty, Tree.Empty); + val xuse: Tree = make.Ident(tree.pos, x); + // x.match {cases} + val body: Tree = make.Apply( + tree.pos, + make.Select(tree.pos, xuse, Names.match), + NewArray.Tree(tree)); + make.Function(tree.pos, NewArray.ValDef(param), body); + } + + /** e = e' ==> e_=(e') + */ + def Assign(pos: int, lhs: Tree, rhs: Tree): Tree = { + val lhs1 = lhs match { + case Tree$Ident(name) => + make.Ident(lhs.pos, setterName(name)); + case Tree$Select(qual, name) => + make.Select(lhs.pos, qual, setterName(name)); + } + make.Apply(pos, lhs1, NewArray.Tree(rhs)); + } + + /** e(args) = e' ==> e.update(args ; e') + */ + def Update(tree: Tree): Tree = tree match { + case Tree$Assign(Tree$Apply(fn, args), rhs) => + // e.update + val update: Tree = make.Select(fn.pos, fn, Names.update); + val args1 = new Array[Tree](args.length + 1); + System.arraycopy(args.asInstanceOf[Array[Object]], 0, + args1.asInstanceOf[Array[Object]], 0, args.length); + args1(args.length) = rhs; + make.Apply(tree.pos, update, args1); + } + + /** make a set of trees share the same documentation comment as a + * given tree (used for pattern and val definitions) + */ + def shareComment(trees: Array[Tree], tree: Tree): Array[Tree] = { + val comment: String = global.mapTreeComment.get(tree).asInstanceOf[String]; + if (comment != null) + for (val i <- Iterator.range(0, trees.length)) + global.mapTreeComment.put(trees(i), comment); + trees; + } + + /** expand pattern definitions and variable definitions in templates. + */ + def Statements(stats: Array[Tree], isLocal: boolean): Array[Tree] = { + var change: boolean = false; + var i = 0; + while (i < stats.length && !change) { + stats(i) match { + case Tree$PatDef(_, _, _) => + change = true; + case Tree$ValDef(_, _, _, _) => + change = !isLocal; + case _ => + } + i = i + 1 + } + if (change) { + val ts: TreeList = new TreeList(); + for (val i <- Iterator.range(0, stats.length)) { + stats(i) match { + case Tree$PatDef(_, _, _) => + ts.append(Statements(this.PatDef(stats(i)), isLocal)); + case Tree$ValDef(_, _, _, _) => + if (isLocal) ts.append(stats(i)) + else ts.append(this.ValDef(stats(i))); + case _ => + ts.append(stats(i)); + } + } + ts.toArray() + } else { + stats; + } + } + + /** expands pattern definitions + * in case pattern is a simple (typed) identifier: + * val x = e ==> val x = e + * val x: T = e ==> val x: T = e + * + * in case there are no variables in pattern + * val p = e ==> e.match (case p => ()) + * + * in case there is exactly one variable in pattern + * val x_1 = e.match (case p => (x_1)) + * + * in case there are more variables in pattern + * val p = e ==> private synthetic val t$ = e.match (case p => (x_1, ..., x_N)) + * val x_1 = t$._1 + * ... + * val x_N = t$._N + * + */ + def PatDef(tree: Tree): Array[Tree] = tree match { + case Tree$PatDef(mods, Tree$Ident(name), rhs) => + // val x = e ==> val x = e + shareComment( + NewArray.Tree(make.ValDef(tree.pos, mods, name, Tree.Empty, rhs)), + tree); + + case Tree$PatDef(mods, Tree$Typed(Tree$Ident(name), tpe), rhs) => + // val x: T = e ==> val x: T = e + shareComment( + NewArray.Tree(make.ValDef(tree.pos, mods, name, tpe, rhs)), + tree); + + case Tree$PatDef(mods, pat, rhs) => + val pos: int = tree.pos; + val varlist: ArrayList = new ArrayList(); + getVariables(pat, varlist); + val vars = new Array[Name](varlist.size()); + varlist.toArray(vars.asInstanceOf[Array[Object]]); + + // Tuple_N(x_1, ..., x_N) + val vtree = new Array[Tree](vars.length); + for (val i <- Iterator.range(0, vars.length)) { + vtree(i) = make.Ident(pos, vars(i)); + } + val tuple: Tree = if (vars.length == 1) vtree(0) + else mkTuple(tree.pos, vtree); + + // e.match (case p => Tuple_N(x_1, ..., x_N)) + val cases = NewArray.CaseDef(make.CaseDef(pos, pat, Tree.Empty, tuple)); + val match: Tree = make.Apply( + pos, + make.Select(pos, rhs, Names.match), + NewArray.Tree(make.Visitor(pos, cases))); + + if (vars.length == 0) { + // e.match (case p => ()) + print(pat, "patdef", match); + NewArray.Tree(match); + } else if (vars.length == 1) { + // val x_1 = e.match (case p => x_1) + val valdef: Tree = make.ValDef(pos, mods, vars(0), Tree.Empty, match); + print(pat, "patdef", valdef); + shareComment(NewArray.Tree(valdef), tree); + } else { + // t$ + val vble: Name = getvar(); + + // private synthetic val t$ = e.match (case p => (x_1, ..., x_N)) + val res = new Array[Tree](vars.length + 1); + res(0) = make.ValDef(pos, PRIVATE | SYNTHETIC, vble, Tree.Empty, match); + for (val i <- Iterator.range(0, vars.length)) { + // val x_i = t$._i + res(i + 1) = make.ValDef( + pos, mods, vars(i), Tree.Empty, + make.Select(pos, make.Ident(pos, vble), tupleSelectorName(i + 1))); + } + print(pat, "patdef", new Tree$Block(res));//debug + shareComment(res, tree); + } + } + + def ValDef(tree: Tree): Array[Tree] = tree match { + case Tree$ValDef(mods, name, tpe, rhs) => + val valname: Name = Name.fromString("" + name + "$"); + val valdef1: Tree = copy.ValDef( + tree, (mods & (DEFERRED | MUTABLE | CASEACCESSOR | MODUL)) | PRIVATE, + valname, tpe, rhs).setType(null); + var mods1: int = mods | ACCESSOR; + if ((mods1 & MUTABLE) == 0) mods1 = mods1 | STABLE; + val getter: Tree = make.DefDef( + tree.pos, mods1, name, + Tree.AbsTypeDef_EMPTY_ARRAY, Tree.ValDef_EMPTY_ARRAY_ARRAY, + tpe.duplicate(), + if ((mods & DEFERRED) != 0) Tree.Empty + else make.Ident(tree.pos, valname)); + if ((mods1 & MUTABLE) == 0) { + if ((mods1 & DEFERRED) != 0) + shareComment(NewArray.Tree(getter), tree); + else + shareComment(NewArray.Tree(valdef1, getter), tree); + } else { + val setter: Tree = make.DefDef( + tree.pos, mods1, setterName(name), + Tree.AbsTypeDef_EMPTY_ARRAY, + NewArray.ValDefArray( + NewArray.ValDef( + make.ValDef( + tree.pos, SYNTHETIC | PARAM, parameterName(0), + tpe.duplicate(), Tree.Empty))), + gen.mkType(tree.pos, global.definitions.UNIT_TYPE()), + if ((mods1 & DEFERRED) != 0) Tree.Empty + else make.Assign( + tree.pos, + make.Ident(tree.pos, valname), + make.Ident(tree.pos, parameterName(0)))); + if ((mods1 & DEFERRED) != 0) + shareComment(NewArray.Tree(getter, setter), tree); + else + shareComment(NewArray.Tree(valdef1, getter, setter), tree); + } + } + + /** Expand partial function applications of type `type'. + * + * p.f(es_1)...(es_n) + * ==> { + * private synthetic val eta$f = p.f // if p is not stable + * ... + * private synthetic val eta$e_i = e_i // if e_i is not stable + * ... + * + * (ps_1 => ... => ps_m => eta$f([es_1])...([es_m])(ps_1)...(ps_m)) + * } + * tree is already attributed + */ + def etaExpand(tree: Tree, tpe: Type): Tree = { + val defs: TreeList = new TreeList(); + val lambda: Tree = + toFunction(toApply(liftoutPrefix(tree, defs), tpe), tpe); + defs.append(lambda); + val result: Tree = make.Block(tree.pos, defs.toArray()); + print(tree, "eta", result);//debug + result + } + + private val preName = "eta$"; + + /** Append to `defs' value definitions for all non-stable subexpressions + * of the function application `tree' + */ + def liftoutPrefix(tree: Tree, defs: TreeList): Tree = { + + def liftoutList(trees: Array[Tree], defs: TreeList): Array[Tree] = { + var trees1 = trees; + for (val i <- Iterator.range(0, trees.length)) { + val tree: Tree = trees(i); + val tree1: Tree = liftout(tree, defs); + if (tree1 != tree && trees1 == trees) { + trees1 = new Array[Tree](trees.length); + System.arraycopy(trees.asInstanceOf[Array[Object]], 0, + trees1.asInstanceOf[Array[Object]], 0, trees.length); + } + trees1(i) = tree1; + } + trees1; + } + + def liftout(tree: Tree, defs: TreeList): Tree = + if (TreeInfo.isPureExpr(tree)) tree + else { + val vname: Name = Name.fromString(preName + defs.length()); + defs.append( + make.ValDef( + tree.pos, SYNTHETIC, vname, Tree.Empty, tree)); + make.Ident(tree.pos, vname) + } + + tree match { + case Tree$Ident(_) => + tree; + case Tree$Select(qual, _) => + copy.Select(tree, liftout(qual, defs)).setType(null); + case Tree$TypeApply(fn, args) => + copy.TypeApply(tree, liftoutPrefix(fn, defs), args).setType(null); + case Tree$Apply(fn, args) => + copy.Apply(tree, liftoutPrefix(fn, defs), liftoutList(args, defs)).setType(null); + } + } + + /** in patterns x => x @ _ + * precondition: name != '_' + * post: returns *unattributed* Bind tree + */ + + def IdentPattern(tree: Tree): Tree = tree match { + case Tree$Ident(name) => + if (name == Names.PATTERN_WILDCARD) + throw new ApplicationError("nothing to desugarize"); + make.Bind( + tree.pos, + name, + gen.Ident(tree.pos, global.definitions.PATTERN_WILDCARD)) + .setType(tree.getType()); + } + + /** in patterns x:T => x @ _ : T + * pre: t is a typed variable. + * post: returns *unattributed* Bind tree + */ + def TypedPattern(t: Tree$Typed): Tree = t match { + case Tree$Typed(Tree$Ident(name), tpe) => + make.Bind( + t.pos, + name, + make.Typed( + t.pos, + gen.Ident(t.pos, global.definitions.PATTERN_WILDCARD), + tpe)); + } + + /** f, (syms_1)...(syms_n)T ==> f(ps_1)...(ps_n) + */ + def toApply(tree: Tree, tpe: Type): Tree = tpe match { + case Type$MethodType(vparams, restpe) => + val res: Tree = make.Apply(tree.pos, tree, toIdents(vparams)); + toApply(res, restpe); + case _ => + tree + } + + /** e, (syms_1)...(syms_n)T ==> (ps_1 => ... => ps_n => e) + */ + def toFunction(tree: Tree, tpe: Type): Tree = tpe match { + case Type$MethodType(vparams, restpe) => + make.Function(tree.pos, toVparams(vparams), toFunction(tree, restpe)); + case _ => + tree + } + + /** Extract value parameters from type. + */ + def toVparams(symbols: Array[Symbol]): Array[Tree$ValDef] = { + val vpars = new Array[Tree$ValDef](symbols.length); + for (val i <- Iterator.range(0, symbols.length)) { + vpars(i) = make.ValDef( + symbols(i).pos, 0, symbols(i).name, + gen.mkType(symbols(i).pos, symbols(i).getType()), + Tree.Empty); + } + vpars + } + + /** Extract value identifiers from method type. + * It is assumed that all symbols are term symbols ==> make.Ident(). + */ + def toIdents(symbols: Array[Symbol]): Array[Tree] = { + val idents = new Array[Tree$Ident](symbols.length); + for (val i <- Iterator.range(0, symbols.length)) { + idents(i) = make.Ident(symbols(i).pos, symbols(i).name); + } + idents.asInstanceOf[Array[Tree]]; + } + + /** Build value element definition name for case parameter. + */ + def addCaseElement(ts: TreeList, vparam: Tree$ValDef): unit = { + //vparam.symbol().initialize(); + ts.append( + make.ValDef( + vparam.pos, CASEACCESSOR, vparam.name, Tree.Empty, + make.Ident(vparam.pos, vparam.name) + .setSymbol(vparam.symbol()))); + } + + /** add case constructor, defintiions value and access functions. + */ + def addCaseElements(body: Array[Tree], vparams: Array[Tree$ValDef]): Array[Tree] = { + val stats: TreeList = new TreeList(); + for (val i <- Iterator.range(0, vparams.length)) { + addCaseElement(stats, vparams(i)); + } + stats.append(body); + stats.toArray(); + } + + //debug + def print(tree: Tree, conv: String, result: Tree): unit = { + if (global.log()) { + new TextTreePrinter() + .print(tree).println() + .print(" --" + conv + "--> ").println() + .print(result).println().end(); + } + } +} diff --git a/sources/scala/tools/scalac/typechecker/ImportList.scala b/sources/scala/tools/scalac/typechecker/ImportList.scala new file mode 100644 index 0000000000..e0e1b7969b --- /dev/null +++ b/sources/scala/tools/scalac/typechecker/ImportList.scala @@ -0,0 +1,65 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** +** $Id$ +\* */ + +package scala.tools.scalac.typechecker; + +import scalac._; +import scalac.util._; +import scalac.symtab._; +import scalac.ast._; + +///////////////////////////////////////////////////////////////////////////// +// Import Lists +///////////////////////////////////////////////////////////////////////////// + +/** A class for import expressions +* @param tree The import definition +* @param enclScope The scope in which the import occurs. +* @param prev The previous active import list. +*/ +case class ImportList(tree: Tree, enclScope: Scope, prev: ImportList) { + + override def toString(): String = { + var str = tree.symbol().toString(); + if (prev != null) str = "" + prev + "; " + str; + str + } + + def importPrefix(): Tree = tree match { + case Tree$Import(expr, _) => expr + } + + def importType(): Type = + tree.symbol().getType(); + + def sameImport(that: ImportList): boolean = + this.importType().isSameAs(that.importType()); + + def importedSymbol(name: Name): Symbol = { + val t = this.importType(); + var renamed = false; + tree match { + case Tree$Import(expr, selectors) => + var i = 0; + while (i < selectors.length) { + if (i + 1 < selectors.length && name.toTermName() == selectors(i+1)) { + if (name.isTypeName()) + return t.lookupNonPrivate(selectors(i).toTypeName()); + else + return t.lookupNonPrivate(selectors(i)); + } else if (name.toTermName() == selectors(i)) { + renamed = true; + } else if (selectors(i) == Names.IMPORT_WILDCARD && !renamed) { + return t.lookupNonPrivate(name); + } + i = i + 2 + } + Symbol.NONE + } + } +} diff --git a/sources/scala/tools/scalac/typechecker/Infer.scala b/sources/scala/tools/scalac/typechecker/Infer.scala new file mode 100644 index 0000000000..1886a42822 --- /dev/null +++ b/sources/scala/tools/scalac/typechecker/Infer.scala @@ -0,0 +1,889 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +\* */ + +// $Id$ + +package scala.tools.scalac.typechecker; + +import java.lang.Object; + +import scalac.Global; +import scalac.ApplicationError; +import scalac.util._; +import scalac.ast._; +import scalac.symtab._; + +import scala.tools.scalac.util.NewArray; + +class Infer(global: Global, gen: TreeGen, make: TreeFactory) { + + import Modifiers._, Kinds._; + + val definitions: Definitions = global.definitions; + val substituter: Substituter = new Substituter(global, gen); + + def this(trans: Transformer) = this(trans.global, trans.gen, trans.make); + +// Error messages ------------------------------------------------------------- + + def applyErrorMsg(msg1: String, fn: Tree, msg2: String, argtypes: Array[Type], pt: Type): String = + msg1 + toString(fn.symbol(), fn.getType()) + msg2 + + ArrayApply.toString(argtypes.asInstanceOf[Array[Object]], "(", ",", ")") + + (if (pt == Type.AnyType) "" else " with expected result type " + pt); + + def typeErrorMsg(msg: String, found: Type, req: Type): String = + msg + ";\n found : " + found.toLongString() + "\n required: " + req; + + def overloadResolveErrorMsg(sym1: Symbol, tpe1: Type, sym2: Symbol, tpe2: Type): String = + "ambiguous reference to overloaded definition,\n" + + "both " + sym1 + ": " + tpe1 + "\n" + + "and " + sym2 + ": " + tpe2 + "\nmatch"; + + /** Give a string representation of symbol `sym' with type `tp' + * for error diagnostics. `sym' may be null. + */ + def toString(sym: Symbol, tp: Type): String = + (if (tp.isInstanceOf[Type$OverloadedType]) "overloaded " else "") + + (if (sym == null) "expression" else sym) + " of type " + tp; + +// Variance calculation ---------------------------------------------------------- + + private def flip(v: int): int = { + if (v == COVARIANT) CONTRAVARIANT; + else if (v == CONTRAVARIANT) COVARIANT; + else v + } + + private def cut(v: int): int = { + if (v == VARIANCES) v + else 0 + } + + /** Compute variances of all type parameters `tparams' in type `tp'. + * A variance is taken from the four point lattice + * + * 0, Modifiers.COVARIANT, Modifiers.CONTRAVARIANT, Modifiers.VARIANCES. + */ + private def variance(tparams: Array[Symbol], tp: Type): Array[int] = { + val vs: Array[int] = new Array[int](tparams.length); + for (val i <- Iterator.range(0, vs.length)) + vs(i) = variance(tparams(i), tp); + vs + } + + /** Compute variances of all type parameters `tparams' in types `tps'. + */ + private def variance(tparams: Array[Symbol], tps: Array[Type]): Array[int] = { + val vs: Array[int] = new Array[int](tparams.length); + for (val i <- Iterator.range(0, vs.length)) + vs(i) = variance(tparams(i), tps); + vs + } + + /** Compute variance of type parameter `tparam' in types of all symbols `sym'. + */ + private def variance(tparam: Symbol, syms: Array[Symbol]): int = { + var v: int = VARIANCES; + for (val i <- Iterator.range(0, syms.length)) { + v = v & variance(tparam, syms(i)); + } + v + } + + /** Compute variance of type parameter `tparam' in type of symbol `sym'. + */ + private def variance(tparam: Symbol, sym: Symbol): int = sym.kind match { + case ERROR => + VARIANCES + case VAL => + variance(tparam, sym.info()) + case TYPE => + variance(tparam, sym.info()) & flip(variance(tparam, sym.loBound())) + case ALIAS => + cut(variance(tparam, sym.info())) + case _ => + 0 + } + + /** Compute variance of type parameter `tparam' in all types `tps'. + */ + private def variance(tparam: Symbol, tps: Array[Type]): int = { + var v: int = VARIANCES; + for (val i <- Iterator.range(0, tps.length)) { + v = v & variance(tparam, tps(i)); + } + v + } + + /** Compute variance of type parameter `tparam' in all type arguments + * `tps' which correspond to formal type parameters `tparams'. + */ + private def varianceInArgs(tvar: Symbol, tps: Array[Type], tparams: Array[Symbol]): int = { + var v: int = VARIANCES; + for (val i <- Iterator.range(0, tps.length)) { + if ((tparams(i).flags & COVARIANT) != 0) { + v = v & variance(tvar, tps(i)); + } else if ((tparams(i).flags & CONTRAVARIANT) != 0) { + v = v & flip(variance(tvar, tps(i))); + } else { + v = v & cut(variance(tvar, tps(i))); + } + } + v + } + + /** Does given `tparam' occur with variance `v' in type? + */ + private def variance(tparam: Symbol, tp: Type): int = tp match { + case Type.ErrorType | Type.AnyType | Type.NoType | + Type$ThisType(_) | Type$ConstantType(_, _) => + VARIANCES + case Type$TypeRef(pre, sym, args) => + if (sym == tparam) COVARIANT + else variance(tparam, pre) & varianceInArgs(tparam, args, sym.typeParams()) + case Type$SingleType(pre, sym) => + cut(variance(tparam, pre)) + case Type$CompoundType(parts, members) => + variance(tparam, parts) & variance(tparam, members.elements()) + case Type$MethodType(params, restype) => + flip(variance(tparam, params)) & variance(tparam, restype) + case Type$PolyType(tparams, restype) => + flip(variance(tparam, tparams)) & variance(tparam, restype) + } + +// Type parameter inference ----------------------------------------------------- + + private class NoInstance(msg: String) extends RuntimeException(msg); + + /** map every TypeVar to its constraint.inst field. + * throw a NoInstance exception if a NoType or AnyType is encountered. + */ + private val instantiateMap: Type$Map = new Type$Map() { + def apply(t: Type): Type = instantiate(t) + } + + private def instantiate(tp: Type): Type = tp match { + case Type.AnyType | Type.NoType => + throw new NoInstance("undetermined type"); + case Type$TypeVar(origin, constr) => + if (constr.inst != Type.NoType) instantiate(constr.inst) + else throw new NoInstance("no unique instantiation of type variable " + + origin + " could be found"); + case _ => + instantiateMap.map(tp) + } + + /** Map type variable to its instance, or, if `covariant' is true, + * to its upper bound; + */ + private def instantiateToBound(tp: Type, variance: int): Type = tp match { + case Type$TypeVar(origin, constr) => + try { + if (constr.inst != Type.NoType) { + instantiate(constr.inst) + } else if ((variance & COVARIANT) != 0 && constr.hibounds != Type$List.EMPTY) { + maximizeVar(tp); + instantiate(constr.inst) + } else if ((variance & CONTRAVARIANT) != 0 && constr.lobounds != Type$List.EMPTY) { + minimizeVar(tp); + instantiate(constr.inst) + } else { + Type.AnyType; + } + } catch { + case ex: NoInstance => Type.AnyType + } + } + + /** The formal parameter types corresponding to `params'. + * If `params' is a repeated parameter, a list of `length' copies + * of its type is returned. + */ + def formalTypes(params: Array[Symbol], length: int): Array[Type] = { + if (params.length == 1 && (params(0).flags & REPEATED) != 0) { + val formals: Array[Type] = new Array[Type](length); + val args: Array[Type] = params(0).getType().typeArgs(); + if (args.length == 1) { + val ft: Type = args(0); + // params(0) has type Seq[T], we need T here + for (val i <- Iterator.range(0, length)) + formals(i) = ft; + return formals; + } + } + Symbol.getType(params); + } + + /** Is type fully defined, i.e. no embedded anytypes or typevars in it? + */ + def isFullyDefined(tp: Type): boolean = { + try { + instantiate(tp); + true + } catch { + case ex: NoInstance => false + } + } + + /** Do type arguments `targs' conform to formal parameters `tparams'? + */ + private def isWithinBounds(tparams: Array[Symbol], targs: Array[Type]): boolean = { + var i = 0; + while (i < targs.length) { + val hibound: Type = tparams(i).info().subst(tparams, targs); + if (!targs(i).isSubType(hibound)) { + var j = 0; + while (j < tparams.length) { + if (hibound.symbol() == tparams(j)) + return isWithinBounds( + tparams, + Type.subst( + targs, + NewArray.Symbol(tparams(j)), + NewArray.Type(targs(i)))); + j = j + 1 + } + return false; + } + val lobound: Type = tparams(i).loBound().subst(tparams, targs); + if (!lobound.isSubType(targs(i))) { + var j = 0; + while (j < tparams.length) { + if (lobound.symbol() == tparams(j)) + return isWithinBounds( + tparams, + Type.subst( + targs, + NewArray.Symbol(tparams(j)), + NewArray.Type(targs(i)))); + j = j + 1 + } + return false + } + i = i + 1 + } + true + } + + /** throw a type error if arguments not within bounds. + */ + def checkBounds(tparams: Array[Symbol], targs: Array[Type], prefix: String): unit = + if (!isWithinBounds(tparams, targs)) + throw new Type$Error( + prefix + "type arguments " + + ArrayApply.toString(targs.asInstanceOf[Array[Object]], "[", ",", "]") + + " do not conform to " + + tparams(0).owner() + "'s type parameter bounds " + + ArrayApply.toString(Symbol.defString(tparams).asInstanceOf[Array[Object]], "[", ",", "]")); + + /** Instantiate variable to glb of its high bounds. + */ + private def maximizeVar(tp: Type): unit = tp match { + case Type$TypeVar(origin, constr) => + if (constr.inst == Type.NoType) + constr.inst = Type.glb(constr.hibounds.toArray()); + } + + /** Instantiate variable to lub of its low bounds. + */ + private def minimizeVar(tp: Type): unit = tp match { + case Type$TypeVar(origin, constr) => + if (constr.inst == Type.NoType) + constr.inst = Type.lub(constr.lobounds.toArray()); + } + + /** Solve constraint collected in types `tvars', instantiating `tvars(i)' + * in the process. + * @param tparams The type parameters corresponding to `tvars' + * @param upper When `true' search for max solution else min. + * @param variances The variances of type parameters; need to reverse + * solution direction for all contravariant variables. + * @param tvars All type variables to be instantiated. + * @param i The index of the type variable to be instantiated. + */ + private def solve(tparams: Array[Symbol], upper: boolean, variances: Array[int], tvars: Array[Type], i: int): unit = { + if (tvars(i) != Type.NoType) { + tvars(i) match { + case Type$TypeVar(origin, constr) => + if (constr.inst != Type.NoType) { + constr.inst = instantiate(constr.inst); + tvars(i) = constr.inst; + } else { + val tvar: Type = tvars(i); + val up: boolean = if (variances(i) != CONTRAVARIANT) upper + else !upper; + tvars(i) = Type.NoType; + val bound: Type = if (up) tparams(i).info() else tparams(i).loBound(); + var cyclic: boolean = false; + for (val j <- Iterator.range(0, tvars.length)) { + if (bound.contains(tparams(j)) || + up && tparams(j).loBound().isSameAs(tparams(i).getType()) || + !up && tparams(j).info().isSameAs(tparams(i).getType())) { + cyclic = cyclic | tvars(j) == Type.NoType; + solve(tparams, upper, variances, tvars, j); + } + } + if (!cyclic) { + if (up) { + if (bound.symbol() != Global.instance.definitions.ANY_CLASS) + constr.hibounds = new Type$List( + bound.subst(tparams, tvars), constr.hibounds); + for (val j <- Iterator.range(0, tvars.length)) { + if (tparams(j).loBound().isSameAs( + tparams(i).getType())) { + constr.hibounds = new Type$List( + tparams(j).getType().subst(tparams, tvars), + constr.hibounds); + } + } + } else { + if (bound.symbol() != Global.instance.definitions.ALL_CLASS) + constr.lobounds = new Type$List( + bound.subst(tparams, tvars), constr.lobounds); + for (val j <- Iterator.range(0, tvars.length)) { + if (tparams(j).info().isSameAs( + tparams(i).getType())) { + constr.lobounds = new Type$List( + tparams(j).getType().subst(tparams, tvars), + constr.lobounds); + } + } + } + } + if (up) maximizeVar(tvar); + else minimizeVar(tvar); + tvars(i) = tvar.asInstanceOf[Type$TypeVar].constr.inst; + } + case _ => + } + } + } + + /** Generate an array of fresh type variables corresponding to parameters + * `tparams' + */ + private def freshVars(tparams: Array[Symbol]): Array[Type] = { + val tvars: Array[Type] = new Array[Type](tparams.length); + for (val i <- Iterator.range(0, tvars.length)) { + tvars(i) = new Type$TypeVar(tparams(i).getType(), new Type$Constraint()); + } + tvars + } + + private val freshInstanceMap: Type$Map = new Type$Map() { + def apply(t: Type): Type = t match { + case Type$PolyType(tparams, restp) => + val restp1: Type = apply(restp); + var tparams1: Array[Symbol] = Symbol.EMPTY_ARRAY; + var newparams1: Array[Symbol] = Symbol.EMPTY_ARRAY; + restp1 match { + case Type$PolyType(_, _) => + // If there is a nested polytype, we need to + // substitute also its new type parameters for its old ones + // here. Reason: The outer polytype may refer to type + // variables of the inner one. + tparams1 = restp.typeParams(); + newparams1 = restp1.typeParams(); + case _ => + } + val newparams: Array[Symbol] = new Array[Symbol](tparams.length); + for (val i <- Iterator.range(0, tparams.length)) + newparams(i) = tparams(i).cloneSymbol(); + for (val i <- Iterator.range(0, tparams.length)) { + newparams(i).setInfo( + newparams(i).info() + .subst(tparams, newparams) + .subst(tparams1, newparams1)); + newparams(i).setLoBound( + newparams(i).loBound() + .subst(tparams, newparams) + .subst(tparams1, newparams1)); + } + new Type$PolyType(newparams, restp1.subst(tparams, newparams)) + + case Type$OverloadedType(_, _) => + map(t) + + case _ => + t + } + } + + def freshInstance(tp: Type): Type = freshInstanceMap.apply(tp); + + /** Automatically perform the following conversions on expression types: + * A method type becomes the corresponding function type. + * A nullary method type becomes its result type. + */ + private def normalize(tp: Type): Type = tp match { + case Type$MethodType(params, restype) => + global.definitions.FUNCTION_TYPE( + Symbol.getType(params), normalize(restype)); + case Type$PolyType(tparams, restype) if (tparams.length == 0) => + normalize(restype); + case _ => + tp + } + + /** Is normalized type `tp' a subtype of prototype `pt'? + */ + def isCompatible(tp: Type, pt: Type): boolean = + normalize(tp).isSubType(pt); + + /** Type arguments mapped to `scala.All' are taken to be uninstantiated. + * Map all those type arguments to their corresponding type parameters + * and return all these type parameters as result. + */ + private def normalizeArgs(targs: Array[Type], tparams: Array[Symbol]): Array[Symbol] = { + var uninstantiated: Type$List = Type$List.EMPTY; + for (val i <- Iterator.range(0, targs.length)) { + if (targs(i).symbol() == Global.instance.definitions.ALL_CLASS) { + targs(i) = tparams(i).getType(); + uninstantiated = Type$List.append(uninstantiated, targs(i)); + } + } + Type.symbol(uninstantiated.toArray()); + } + + /** Return inferred type arguments of polymorphic expression, given + * its type parameters and result type and a prototype `pt'. + * If no minimal type variables exist that make the + * instantiated type a subtype of `pt', return `null'. + */ + private def exprTypeArgs(tparams: Array[Symbol], restype: Type, pt: Type): Array[Type] = { + val tvars: Array[Type] = freshVars(tparams); + val insttype: Type = restype.subst(tparams, tvars); + if (isCompatible(insttype, pt)) { + try { + val restype1 = normalize(restype); + for (val i <- Iterator.range(0, tvars.length)) { + solve(tparams, false, variance(tparams, restype1), tvars, i); + } + tvars + } catch { + case ex: NoInstance => null + } + } else { + null + } + } + + /** Return inferred proto-type arguments of function, given + * its type and value parameters and result type, and a + * prototype `pt' for the function result. + * Type arguments need to be either determined precisely by + * the prototype, or they are maximized, if they occur only covariantly + * in the value parameter list. + * If instantiation of a type parameter fails, + * take Type.AnyType for the proto-type argument. + */ + def protoTypeArgs(tparams: Array[Symbol], restype: Type, pt: Type, params: Array[Symbol]): Array[Type] = { + val tvars: Array[Type] = freshVars(tparams); + val insttype: Type = restype.subst(tparams, tvars); + val targs: Array[Type] = new Array[Type](tvars.length); + for (val i <- Iterator.range(0, tvars.length)) + targs(i) = Type.AnyType; + if (isCompatible(insttype, pt)) { + try { + for (val i <- Iterator.range(0, tvars.length)) { + targs(i) = instantiateToBound( + tvars(i), variance(tparams(i), params)); + } + } catch { + case ex: NoInstance => + for (val i <- Iterator.range(0, tvars.length)) + targs(i) = Type.AnyType; + } + } + targs + } + + /** Return inferred type arguments, given type parameters, formal parameters, + * argument types, result type and expected result type. + * If this is not possible, throw a `NoInstance' exception, or, if + * `needToSucceed' is false alternatively return `null'. + * Undetermined type arguments are represented by `definitions.ALL_TYPE'. + * No check that inferred parameters conform to their bounds is made here. + */ + private def methTypeArgs(tparams: Array[Symbol], params: Array[Symbol], argtypes: Array[Type], restp: Type, pt: Type, needToSucceed: boolean): Array[Type] = { + //System.out.println("methTypeArgs, tparams = " + ArrayApply.toString(tparams) + ", params = " + ArrayApply.toString(params) + ", type(params) = " + ArrayApply.toString(Symbol.type(params)) + ", argtypes = " + ArrayApply.toString(argtypes));//DEBUG + + val tvars: Array[Type] = freshVars(tparams); + val formals: Array[Type] = formalTypes(params, argtypes.length); + if (formals.length != argtypes.length) { + if (needToSucceed) + throw new NoInstance("parameter lists differ in length"); + return null; + } + + // check first whether type variables can be fully defined from + // expected result type. + if (!isCompatible(restp.subst(tparams, tvars), pt)) { + if (needToSucceed) + throw new NoInstance("result type " + restp + + " is incompatible with expected type " + pt); + return null; + } + for (val i <- Iterator.range(0, tvars.length)) { + val tvar: Type$TypeVar = tvars(i).asInstanceOf[Type$TypeVar]; + if (!isFullyDefined(tvar)) tvar.constr.inst = Type.NoType; + } + + // Then define remaining type variables from argument types. + var i = 0; + while (i < argtypes.length) { + if (!isCompatible(argtypes(i).widen().subst(tparams, tvars), formals(i).subst(tparams, tvars))) { + if (needToSucceed) { + if (global.explaintypes) { + Type.explainSwitch = true; + argtypes(i).widen().subst(tparams, tvars).isSubType( + formals(i).subst(tparams, tvars)); + Type.explainSwitch = false; + } + throw new NoInstance( + typeErrorMsg( + "argument expression's type is not compatible with formal parameter type", + argtypes(i).widen().subst(tparams, tvars), + formals(i).subst(tparams, tvars))); + } + return null; + } + i = i + 1; + } + for (val i <- Iterator.range(0, tvars.length)) { + solve(tparams, false, variance(tparams, formals), tvars, i); + } + //System.out.println(" = " + ArrayApply.toString(tvars));//DEBUG + tvars + } + + /** Create and attribute type application node. Pass arguments for that + * `tparams' prefix which is owned by the tree's symbol. If there are remaining + * type parameters, substitute corresponding type arguments for them in the + * tree. Such remaining type parameters always come from an inferred PolyType. + */ + def mkTypeApply(tree: Tree, tparams: Array[Symbol], restype: Type, targs: Array[Type]): Tree = { + var tree1: Tree = tree; + val sym: Symbol = tree.symbol(); + var i: int = 0; + while (i < tparams.length && tparams(i).owner() == sym) + i = i + 1; + if (i < tparams.length) { + //System.out.println("tpar " + tparams(i) + " of " + tparams(i).owner() + " <> " + sym);//DEBUG + //new Printer().print(tree1);//DEBUG + //System.out.println(ArrayApply.toString(targs) + "/" + i + "/" + ArrayApply.toString(tparams));//DEBUG + val tparams1: Array[Symbol] = new Array[Symbol](tparams.length - i); + System.arraycopy(tparams.asInstanceOf[Array[Object]], i, + tparams1.asInstanceOf[Array[Object]], 0, tparams1.length); + val targs1: Array[Type] = new Array[Type](tparams.length - i); + System.arraycopy(targs.asInstanceOf[Array[Object]], i, + targs1.asInstanceOf[Array[Object]], 0, targs1.length); + tree1 = substituter.apply(tree1, tparams1, targs1); + } + if (0 < i) { + val argtrees: Array[Tree] = new Array[Tree](i); + for (val j <- Iterator.range(0, i)) + argtrees(j) = gen.mkType(tree.pos, targs(j)); + tree1 = make.TypeApply(tree.pos, tree1, argtrees); + } + //System.out.println(Sourcefile.files[Position.file(tree1.pos)] + ": "); + tree1.setType(restype.subst(tparams, targs)) + } + + /** Return the instantiated and normalized type of polymorphic expression + * with type `[tparams]restype', given two prototypes `pt1', and `pt2'. + * `pt1' is the strict first attempt prototype where type parameters + * are left unchanged. `pt2' is the fall-back prototype where type parameters + * are replaced by `AnyType's. We try to instantiate first to `pt1' and then, + * if this fails, to `pt2'. If both attempts fail, a Type.Error is thrown. + */ + def argumentTypeInstance(tparams: Array[Symbol], restype: Type, pt1: Type, pt2: Type): Type = { + restype match { + case Type$PolyType(tparams1, restype1) => + val tparams2: Array[Symbol] = new Array[Symbol](tparams.length + tparams1.length); + System.arraycopy(tparams.asInstanceOf[Array[Object]], 0, + tparams2.asInstanceOf[Array[Object]], 0, tparams.length); + System.arraycopy(tparams1.asInstanceOf[Array[Object]], 0, + tparams2.asInstanceOf[Array[Object]], tparams.length, tparams1.length); + argumentTypeInstance(tparams2, restype1, pt1, pt2); + + case _ => + if (tparams.length != 0) { + var targs: Array[Type] = exprTypeArgs(tparams, restype, pt1); + if (targs == null) + targs = exprTypeArgs(tparams, restype, pt2); + if (targs == null) + throw new Type$Error( + typeErrorMsg( + "polymorphic argument cannot be instantiated to formal parameter type", + new Type$PolyType(tparams, restype), pt2)); + checkBounds(tparams, targs, "inferred "); + restype.subst(tparams, targs); + } else { + normalize(restype); + } + } + } + + /** Instantiate expression `tree' of polymorphic type [tparams]restype, + * using prototype `pt'. + */ + def exprInstance(tree: Tree, tparams: Array[Symbol], restype: Type, pt: Type): Tree = { + restype match { + case Type$PolyType(tparams1, restype1) => + val tparams2: Array[Symbol] = new Array[Symbol](tparams.length + tparams1.length); + System.arraycopy(tparams.asInstanceOf[Array[Object]], 0, + tparams2.asInstanceOf[Array[Object]], 0, tparams.length); + System.arraycopy(tparams1.asInstanceOf[Array[Object]], 0, + tparams2.asInstanceOf[Array[Object]], tparams.length, tparams1.length); + exprInstance(tree, tparams2, restype1, pt) + case _ => + val targs: Array[Type] = exprTypeArgs(tparams, restype, pt); + if (targs == null) + throw new Type$Error( + "polymorphic expression of type " + tree.getType() + + " cannot be instantiated from expected type " + pt); + checkBounds(tparams, targs, "inferred "); + mkTypeApply(tree, tparams, restype, targs) + } + } + + /** Instantiate method `tree' of polymorphic type [tparams]restype, + * so that resulting method type can be applied to arguments with + * types `argtypes' and its result type is compatible with `pt'. + */ + def methodInstance(tree: Tree, tparams: Array[Symbol], restype: Type, argtypes: Array[Type], pt: Type): Tree = { + restype match { + case Type$PolyType(tparams1, restype1) => + val tparams2: Array[Symbol] = new Array[Symbol](tparams.length + tparams1.length); + System.arraycopy(tparams.asInstanceOf[Array[Object]], 0, + tparams2.asInstanceOf[Array[Object]], 0, tparams.length); + System.arraycopy(tparams1.asInstanceOf[Array[Object]], 0, + tparams2.asInstanceOf[Array[Object]], tparams.length, tparams1.length); + methodInstance(tree, tparams2, restype1, argtypes, pt) + + case Type$MethodType(params, restpe) => + var targs: Array[Type] = _; + try { + targs = methTypeArgs(tparams, params, argtypes, restpe, pt, true); + } catch { + case ex: NoInstance => + throw new Type$Error( + applyErrorMsg( + "no type parameters for ", tree, + " exist so that it can be applied to arguments ", + Type.widen(argtypes), Type.AnyType) + + "\n --- because ---\n" + ex.getMessage()); + } + val uninstantiated: Array[Symbol] = normalizeArgs(targs, tparams); + checkBounds(tparams, targs, "inferred "); + val restype1: Type = + if (uninstantiated.length == 0) restype + else new Type$MethodType( + params, new Type$PolyType(uninstantiated, restpe)); + mkTypeApply(tree, tparams, restype1, targs); + case _ => + tree + } + } + + /** Instantiate constructor `tree' of polymorphic type [tparams]restype', + * so that its the result type of `restype' matches prototype `pt'. + * If constructor is polymorphic, maximize all type variables under this + * condition. + */ + def constructorInstance(tree: Tree, tparams: Array[Symbol], restype: Type, pt: Type): unit = { + restype match { + case Type$PolyType(tparams1, restype1) => + val tparams2: Array[Symbol] = new Array[Symbol](tparams.length + tparams1.length); + System.arraycopy(tparams.asInstanceOf[Array[Object]], 0, + tparams2.asInstanceOf[Array[Object]], 0, tparams.length); + System.arraycopy(tparams1.asInstanceOf[Array[Object]], 0, + tparams2.asInstanceOf[Array[Object]], tparams.length, tparams1.length); + constructorInstance(tree, tparams2, restype1, pt) + + case _ => + val tvars: Array[Type] = freshVars(tparams); + val restype1: Type = restype.subst(tparams, tvars); + val ctpe1: Type = restype1.resultType(); + if (ctpe1.isSubType(pt)) { + try { + for (val i <- Iterator.range(0, tvars.length)) { + solve(tparams, true, variance(tparams, restype.resultType()), + tvars, i); + } + checkBounds(tparams, tvars, "inferred "); + tree.setType(restype.subst(tparams, tvars)); + //System.out.println("inferred constructor type: " + tree.getType());//DEBUG + } catch { + case ex: NoInstance => + throw new Type$Error( + "constructor of type " + ctpe1 + + " can be instantiated in more than one way to expected type " + + pt + + "\n --- because ---\n" + ex.getMessage()); + } + } else { + throw new Type$Error( + typeErrorMsg( + "constructor cannot be instantiated to expected type", + ctpe1, pt)); + } + } + } + +// Overload Resolution ------------------------------------------------------------- + + /** Is function type `ftpe' applicable to `argtypes' and + * does its result conform to `pt'? + */ + def isApplicable(ftpe: Type, argtypes: Array[Type], pt: Type): boolean = ftpe match { + case Type$MethodType(params, restpe) => + // sequences ? List( a* ) + val formals: Array[Type] = formalTypes(params, argtypes.length); + isCompatible(restpe, pt) && + formals.length == argtypes.length && + Type.isSubType(argtypes, formals); + case Type$PolyType(tparams, Type$MethodType(params, restpe)) => + try { + val targs: Array[Type] = methTypeArgs( + tparams, params, argtypes, restpe, pt, false); + if (targs != null) { + val uninstantiated: Array[Symbol] = normalizeArgs(targs, tparams); + isWithinBounds(tparams, targs) && + exprTypeArgs(uninstantiated, restpe.subst(tparams, targs), pt) != null; + } else { + false + } + } catch { + case ex: NoInstance => false + } + case _ => + false + } + + /** Does function type `ftpe1' specialize function type `ftpe2' + * when both are alternatives in an overloaded function? + */ + def specializes(ftpe1: Type, ftpe2: Type): boolean = ftpe1 match { + case Type$MethodType(params, _) => + isApplicable(ftpe2, Symbol.getType(params), Type.AnyType) + case Type$PolyType(_, Type$MethodType(params, _)) => + isApplicable(ftpe2, Symbol.getType(params), Type.AnyType); + case _ => + false + } + + /** Assign `tree' the type of the alternative which matches + * prototype `pt', if it exists. + * If several alternatives match `pt', take unique parameterless one. + * Throw a Type.Error if several such alternatives exist. + * If no alternative matches, leave `tree' unchanged. + */ + def exprAlternative(tree: Tree, alts: Array[Symbol], alttypes: Array[Type], pt: Type): unit = { + + def improves(tp1: Type, tp2: Type): boolean = + tp2.isParameterized() && + (!tp1.isParameterized() || specializes(tp1, tp2)); + + // first, catch the case of a missing parameter + // list for an overloaded constructor. + if (alts.length > 0) { + var i: int = 0; + while (i < alts.length && alts(i).isConstructor() && alttypes(i).isInstanceOf[Type$MethodType]) + i = i + 1; + if (i == alts.length) + throw new Type$Error("missing arguments for " + alts(0)); + } + // second, do the normal case. + var best: int = -1; + for (val i <- Iterator.range(0, alttypes.length)) { + if (isCompatible(alttypes(i), pt) && (best < 0 || improves(alttypes(i), alttypes(best)))) { + best = i; + } + } + if (best >= 0) { + for (val i <- Iterator.range(0, alttypes.length)) { + if (isCompatible(alttypes(i), pt) && best != i && !improves(alttypes(best), alttypes(i))) { + throw new Type$Error( + overloadResolveErrorMsg( + alts(best), alttypes(best), alts(i), alttypes(i)) + + " expected type " + pt); + } + } + tree.setSymbol(alts(best)).setType(alttypes(best)); + } + } + + /** Assign `tree' the type of an alternative + * which is applicable to `argtypes', and whose result type is + * a subtype of `pt' if it exists. + * If several applicable alternatives exist, take the + * most specialized one, or throw an error if no + * most specialized applicable alternative exists. + * If no alternative matches, leave `tree' unchanged, + * try to select method with pt = AnyType. + * If pt is AnyType, leave tree unchanged. + */ + def methodAlternative(tree: Tree, alts: Array[Symbol], alttypes: Array[Type], argtypes: Array[Type], pt: Type): unit = { + if (alts.length == 1) { + tree.setSymbol(alts(0)).setType(alttypes(0)); + return; + } + var best: int = -1; + for (val i <- Iterator.range(0, alttypes.length)) { + if (isApplicable(alttypes(i), argtypes, pt) && + (best < 0 || specializes(alttypes(i), alttypes(best)))) + best = i; + } + if (best >= 0) { + for (val i <- Iterator.range(0, alttypes.length)) { + if (i != best && + isApplicable(alttypes(i), argtypes, pt) && + !(specializes(alttypes(best), alttypes(i)) && + !specializes(alttypes(i), alttypes(best)))) + throw new Type$Error( + overloadResolveErrorMsg( + alts(best), alttypes(best), alts(i), alttypes(i)) + + " argument types " + + ArrayApply.toString(argtypes.asInstanceOf[Array[Object]], "(", ",", ")") + + (if (pt == Type.AnyType) "" else " and expected result type " + pt)); + } + tree.setSymbol(alts(best)).setType(alttypes(best)); + } else if (pt != Type.AnyType) { + methodAlternative(tree, alts, alttypes, argtypes, Type.AnyType); + } + } + + /** Assign `tree' the type of unique polymorphic alternative with `nparams' + * as the number of type parameters, if it exists. + * Throw error if several such polymorphic alternatives exist. + * If no alternative matches, leave `tree' unchanged. + */ + def polyAlternative(tree: Tree, alts: Array[Symbol], alttypes: Array[Type], nparams: int): unit = { + if (alts.length == 1) { + tree.setSymbol(alts(0)).setType(alttypes(0)); + return; + } + var i: int = 0; + while (i < alttypes.length && + !(alts(i).isValue() && + alttypes(i).typeParams().length == nparams)) + i = i + 1; + + if (i < alttypes.length) { + for (val j <- Iterator.range(i + 1, alttypes.length)) { + if (alts(j).isValue() && + alttypes(j).typeParams().length == nparams) + throw new Type$Error( + overloadResolveErrorMsg(alts(i), alttypes(i), alts(j), alttypes(j)) + + " polymorphic function with " + nparams + " parameters"); + } + tree.setSymbol(alts(i)).setType(alttypes(i)); + } + } +} + diff --git a/sources/scala/tools/scalac/typechecker/Substituter.scala b/sources/scala/tools/scalac/typechecker/Substituter.scala new file mode 100644 index 0000000000..407876c1f8 --- /dev/null +++ b/sources/scala/tools/scalac/typechecker/Substituter.scala @@ -0,0 +1,95 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +\* */ + +// $Id$ + +package scala.tools.scalac.typechecker; + +import scalac.Global; +import scalac.ApplicationError; +import scalac.util._; +import scalac.ast._; +import scalac.symtab._; + +// Tree Substitution ------------------------------------------------------------- + +class Substituter(global: Global, gen: TreeGen) extends Transformer(global) { + + var tparams: Array[Symbol] = _; + var targs: Array[Type] = _; + var typeSubstituter: Type$SubstTypeMap = _; + + def apply(tree: Tree, tparams: Array[Symbol], targs: Array[Type]): Tree = { + this.tparams = tparams; + this.targs = targs; + this.typeSubstituter = new Type$SubstTypeMap(tparams, targs) { + override def matches(sym1: Symbol, sym2: Symbol): boolean = { + sym1.name == sym2.name && sym1.owner() == sym2.owner(); + } + } + transform(tree); + } + + val elimInferredPolyMap: Type$Map = new Type$Map() { + def apply(t: Type): Type = { + t match { + case Type$PolyType(tparams1: Array[Symbol], restp: Type) => + if (tparams1.length == tparams.length && tparams1(0) == tparams(0)) { + for (val i <- Iterator.range(1, tparams.length)) + assert(tparams1(i) == tparams(i)); + return apply(restp); + } + case _ => + } + map(t) + } + }; + + override def transform(trees: Array[Tree]): Array[Tree] = + super.transform(trees); + + override def transform(tree: Tree): Tree = { + // System.out.println("[" + ArrayApply.toString(targs,"",",","") + "/" + ArrayApply.toString(tparams,"",",","") + "]" + tree + "@" + tree.symbol());//DEBUG + if (tree.getType() != null) { + tree.setType( + typeSubstituter.apply(elimInferredPolyMap.apply(tree.getType()))); + } + tree match { + case Tree$Ident(name) => + if (name.isTypeName()) { + val sym: Symbol = tree.symbol(); + var i = 0; + while (i < tparams.length) { + if (typeSubstituter.matches(tparams(i), sym)) { + return gen.mkType(tree.pos, targs(i)); + } + i = i + 1; + } + } + tree + + case Tree$TypeApply(fun, targs) => + var proceed: boolean = true; + fun.getType() match { + case Type$PolyType(tparams1, _) => + if (tparams1.length == tparams.length && tparams1(0) == tparams(0) && targs.length == tparams.length) { + proceed = false; + for (val i <- Iterator.range(0, tparams.length)) + if (!typeSubstituter.matches(targs(i).getType().symbol(), tparams(i))) + proceed = true; + } + case _ => + } + val fun1: Tree = if (proceed) transform(fun) else fun; + val targs1: Array[Tree] = transform(targs); + copy.TypeApply(tree, fun1, targs1); + + case _ => + super.transform(tree); + } + } +} + diff --git a/sources/scala/tools/scalac/util/NewArray.scala b/sources/scala/tools/scalac/util/NewArray.scala new file mode 100644 index 0000000000..ac7f272a74 --- /dev/null +++ b/sources/scala/tools/scalac/util/NewArray.scala @@ -0,0 +1,99 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +\* */ + +// $Id: + +package scala.tools.scalac.util; + +import scalac.ast._; +import scalac.util.Name; +import scalac.symtab.Symbol; +import scalac.symtab.Type; +import scalac.checkers.Checker; + +object NewArray { + + def Tree(xs: Tree*): Array[Tree] = { + val arr = new Array[Tree](xs.length); + var i = 0; + for (val t <- xs.elements) { + arr(i) = t; i = i + 1; + } + arr + } + + def ValDef(xs: Tree$ValDef*): Array[Tree$ValDef] = { + val arr = new Array[Tree$ValDef](xs.length); + var i = 0; + for (val t <- xs.elements) { + arr(i) = t; i = i + 1; + } + arr + } + + def ValDefArray(xs: Array[Tree$ValDef]*): Array[Array[Tree$ValDef]] = { + val arr = new Array[Array[Tree$ValDef]](xs.length); + var i = 0; + for (val t <- xs.elements) { + arr(i) = t; i = i + 1; + } + arr + } + + def CaseDef(xs: Tree$CaseDef*): Array[Tree$CaseDef] = { + val arr = new Array[Tree$CaseDef](xs.length); + var i = 0; + for (val t <- xs.elements) { + arr(i) = t; i = i + 1; + } + arr + } + + def Name(xs: Name*): Array[Name] = { + val arr = new Array[Name](xs.length); + var i = 0; + for (val t <- xs.elements) { + arr(i) = t; i = i + 1; + } + arr + } + + def Symbol(xs: Symbol*): Array[Symbol] = { + val arr = new Array[Symbol](xs.length); + var i = 0; + for (val t <- xs.elements) { + arr(i) = t; i = i + 1; + } + arr + } + + def SymbolArray(xs: Array[Symbol]*): Array[Array[Symbol]] = { + val arr = new Array[Array[Symbol]](xs.length); + var i = 0; + for (val t <- xs.elements) { + arr(i) = t; i = i + 1; + } + arr + } + + def Type(xs: Type*): Array[Type] = { + val arr = new Array[Type](xs.length); + var i = 0; + for (val t <- xs.elements) { + arr(i) = t; i = i + 1; + } + arr + } + + def Checker(xs: Checker*): Array[Checker] = { + val arr = new Array[Checker](xs.length); + var i = 0; + for (val t <- xs.elements) { + arr(i) = t; i = i + 1; + } + arr + } +} |