diff options
author | Martin Odersky <odersky@gmail.com> | 2006-03-08 17:38:19 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2006-03-08 17:38:19 +0000 |
commit | 3d41a873e2b40d56ec60cfca7fb2cb9cef71f7fb (patch) | |
tree | 58bdd381e98cf426d642f8e16e0349d348eb8227 /src | |
parent | d969657ce2bbcfeffdfd15a97f3f7ca33d877737 (diff) | |
download | scala-3d41a873e2b40d56ec60cfca7fb2cb9cef71f7fb.tar.gz scala-3d41a873e2b40d56ec60cfca7fb2cb9cef71f7fb.tar.bz2 scala-3d41a873e2b40d56ec60cfca7fb2cb9cef71f7fb.zip |
Some changes to make arrays work better
Diffstat (limited to 'src')
16 files changed, 243 insertions, 146 deletions
diff --git a/src/compiler/scala/tools/nsc/Interpreter.scala b/src/compiler/scala/tools/nsc/Interpreter.scala index b7b8f05b54..37eec3b5f9 100644 --- a/src/compiler/scala/tools/nsc/Interpreter.scala +++ b/src/compiler/scala/tools/nsc/Interpreter.scala @@ -402,7 +402,7 @@ class Interpreter(val compiler: Global, output: (String => Unit)) { } val names1 = getTypes(valAndVarNames, n=>compiler.nme.getterToLocal(n)) - val names2 = getTypes(defNames, id) + val names2 = getTypes(defNames, identity) names1.incl(names2) } diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala index 910b6d0f2a..3b1a0867d7 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala @@ -49,19 +49,18 @@ abstract class TreeInfo { } - /** Is tree a pure definition? + /** Is tree a pure (i.e. non-side-effecting) definition? */ def isPureDef(tree: Tree): boolean = tree match { case EmptyTree | ClassDef(_, _, _, _, _) - | ModuleDef(_, _, _) | AbsTypeDef(_, _, _, _) | AliasTypeDef(_, _, _, _) | Import(_, _) | DefDef(_, _, _, _, _, _) => true case ValDef(mods, _, _, rhs) => - mods.hasFlag(MUTABLE) && isPureExpr(rhs) + !mods.hasFlag(MUTABLE) && isPureExpr(rhs) case DocDef(_, definition) => isPureDef(definition) case Attributed(_, definition) => diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index 663eda6758..e95d41bdd6 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -334,7 +334,7 @@ mixin class Trees requires Global { !vparamss1.head.isEmpty && (vparamss1.head.head.mods.flags & IMPLICIT) != 0) vparamss1 = List() :: vparamss1; val superRef: Tree = Select(Super(nme.EMPTY.toTypeName, nme.EMPTY.toTypeName), nme.CONSTRUCTOR); - val superCall = (superRef /: argss) (Apply); + val superCall = posAssigner.atPos(parents.head.pos) { (superRef /: argss) (Apply) }; val constr: Tree = DefDef(NoMods, nme.CONSTRUCTOR, List(), vparamss1, TypeTree(), superCall); Template(parents, List.flatten(vparamss) ::: constr :: body) } diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 133c432aef..c02d59ce86 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -146,18 +146,18 @@ mixin class Parsers requires SyntaxAnalyzer { /////// TOKEN CLASSES ////////////////////////////////////////////////////// def isModifier: boolean = in.token match { - case ABSTRACT | FINAL | SEALED | MIXIN | PRIVATE | PROTECTED | OVERRIDE | IMPLICIT => true + case ABSTRACT | FINAL | SEALED | PRIVATE | PROTECTED | OVERRIDE | IMPLICIT => true case _ => false } def isLocalModifier: boolean = in.token match { - case ABSTRACT | FINAL | SEALED | MIXIN => true + case ABSTRACT | FINAL | SEALED => true case _ => false } def isDefIntro: boolean = in.token match { case VAL | VAR | DEF | TYPE | OBJECT | - CASEOBJECT | CLASS | CASECLASS | TRAIT => true + CASEOBJECT | CLASS | CASECLASS | MIXIN | TRAIT => true case _ => false } @@ -615,14 +615,15 @@ mixin class Parsers requires SyntaxAnalyzer { * | try `{' block `}' [catch `{' caseClauses `}'] [finally Expr] * | while `(' Expr `)' [NewLine] Expr * | do Expr [StatementSeparator] while `(' Expr `)' - * | for (`(' Enumerators `)' | '{' Enumerators '}') [NewLine] (yield) Expr + * | for (`(' Enumerators `)' | '{' Enumerators '}') [NewLine] [yield] Expr * | throw Expr * | return [Expr] * | [SimpleExpr `.'] Id `=' Expr * | SimpleExpr ArgumentExprs `=' Expr * | `.' SimpleExpr * | PostfixExpr [`:' Type1] - * | PostfixExpr match `{' caseClauses `}' + * | PostfixExpr match `{' CaseClauses `}' + * | MethodClosure * Bindings ::= Id [`:' Type1] * | `(' [Binding {`,' Binding}] `)' * Binding ::= Id [`:' Type] @@ -916,7 +917,7 @@ mixin class Parsers requires SyntaxAnalyzer { ts.toList } - /** caseClause : =>= case Pattern [if PostfixExpr] `=>' Block + /** CaseClause : =>= case Pattern [if PostfixExpr] `=>' Block */ def caseClause(): CaseDef = atPos(accept(CASE)) { @@ -1053,7 +1054,7 @@ mixin class Parsers requires SyntaxAnalyzer { /** SimplePattern ::= varid * | `_' * | literal - * | `<' xLiteralPattern + * | XmlPattern * | StableId [ `(' Patterns `)' ] * | `(' [Pattern] `)' * SimpleSeqPattern ::= varid @@ -1118,8 +1119,6 @@ mixin class Parsers requires SyntaxAnalyzer { def loop(mods: int): int = in.token match { case ABSTRACT => loop(addMod(mods, Flags.ABSTRACT)) - case MIXIN => - loop(addMod(mods, Flags.MIXIN)) case FINAL => loop(addMod(mods, Flags.FINAL)) case SEALED => @@ -1155,8 +1154,6 @@ mixin class Parsers requires SyntaxAnalyzer { def loop(mods: int): int = in.token match { case ABSTRACT => loop(addMod(mods, Flags.ABSTRACT)) - case MIXIN => - loop(addMod(mods, Flags.MIXIN)) case FINAL => loop(addMod(mods, Flags.FINAL)) case SEALED => @@ -1204,7 +1201,15 @@ mixin class Parsers requires SyntaxAnalyzer { } val name = ident(); accept(COLON); - val bynamemod = if (in.token == ARROW) Flags.BYNAMEPARAM else 0; + val bynamemod = + if (in.token == ARROW) { + if (owner.isTypeName && !mods.hasFlag(Flags.LOCAL)) + syntaxError( + in.currentPos, + (if (mods.hasFlag(Flags.MUTABLE)) "`var'" else "`val'") + + " parameters may not be call-by-name", false) + Flags.BYNAMEPARAM + } else 0; ValDef(mods | implicitmod | bynamemod, name, paramType(), EmptyTree) } } @@ -1521,7 +1526,7 @@ mixin class Parsers requires SyntaxAnalyzer { /** ConstrExpr ::= SelfInvocation * | `{' SelfInvocation {StatementSeparator BlockStat} `}' - * SelfInvocation ::= this ArgumentExpr + * SelfInvocation ::= this ArgumentExprs {ArgumentExprs} */ def constrExpr(): Tree = if (in.token == LBRACE) { @@ -1537,10 +1542,14 @@ mixin class Parsers requires SyntaxAnalyzer { } } else selfInvocation(); - /** SelfInvocation ::= this ArgumentExprs + /** SelfInvocation ::= this ArgumentExprs {ArgumentExprs} */ def selfInvocation(): Tree = - atPos(accept(THIS)) { Apply(Ident(nme.CONSTRUCTOR), argumentExprs()) } + atPos(accept(THIS)) { + var t = Apply(Ident(nme.CONSTRUCTOR), argumentExprs()) + while (in.token == LPAREN) t = Apply(t, argumentExprs()) + t + } /** TypeDef ::= Id [TypeParamClause] `=' Type * TypeDcl ::= Id TypeBounds @@ -1564,37 +1573,39 @@ mixin class Parsers requires SyntaxAnalyzer { } } - /** TmplDef ::= ([case] class | trait) ClassDef - * | [case] object ObjectDef + /** TmplDef ::= [case] class ClassDef + * | [case] object ObjectDef + * | ([mixin class | trait]) MixinClassDef */ - def tmplDef(mods: Modifiers): Tree = { - val mods1 = if (mods.hasFlag(Flags.MIXIN)) mods | Flags.ABSTRACT else mods; - in.token match { - case TRAIT => - classDef(mods1 | Flags.MIXIN | Flags.ABSTRACT); - case CLASS => - classDef(mods1); - case CASECLASS => - classDef(mods1 | Flags.CASE); - case OBJECT => - objectDef(mods1); - case CASEOBJECT => - objectDef(mods1 | Flags.CASE); - case _ => - syntaxError("illegal start of definition", true); - EmptyTree - } + def tmplDef(mods: Modifiers): Tree = in.token match { + case TRAIT => + classDef(mods | Flags.MIXIN | Flags.ABSTRACT); + case MIXIN => + in.nextToken(); + if (in.token != CLASS) accept(CLASS); + classDef(mods | Flags.MIXIN | Flags.ABSTRACT); + case CLASS => + classDef(mods); + case CASECLASS => + classDef(mods | Flags.CASE); + case OBJECT => + objectDef(mods); + case CASEOBJECT => + objectDef(mods | Flags.CASE); + case _ => + syntaxError("illegal start of definition", true); + EmptyTree } - /** ClassDef ::= ClassSig RequiresTypeOpt ClassTemplate - * ClassSig ::= Id [TypeParamClause] ClassParamClauses + /** ClassDef ::= Id [TypeParamClause] ClassParamClauses RequiresTypeOpt ClassTemplate + * MixinClassDef ::= Id [TypeParamClause] RequiresTypeOpt MixinClassTemplate */ - def classDef(mods: Modifiers): Tree = + def classDef(mods: Modifiers): ClassDef = atPos(in.skipToken()) { val name = ident().toTypeName; val implicitViews = new ListBuffer[Tree]; val tparams = typeParamClauseOpt(name, implicitViews); - if (mods.hasFlag(Flags.CASE) && in.token != LPAREN) accept(LPAREN); + //if (mods.hasFlag(Flags.CASE) && in.token != LPAREN) accept(LPAREN); val vparamss = paramClauses(name, implicitViews.toList, mods.hasFlag(Flags.CASE)); val thistpe = requiresTypeOpt(); val template = classTemplate(mods, name, vparamss); @@ -1613,8 +1624,10 @@ mixin class Parsers requires SyntaxAnalyzer { ModuleDef(mods, name, template) } - /** ClassTemplate ::= [`extends' TemplateParents] [[NewLine] TemplateBody] - * TemplateParents ::= SimpleType {`(' [Exprs] `)'} {`with' SimpleType} + /** ClassTemplate ::= [`extends' TemplateParents] [[NewLine] TemplateBody] + * TemplateParents ::= SimpleType {`(' [Exprs] `)'} {`with' SimpleType} + * MixinClassTemplate ::= [`extends' MixinParents] [[NewLine] TemplateBody] + * MixinParents ::= SimpleType {`with' SimpleType} */ def classTemplate(mods: Modifiers, name: Name, vparamss: List[List[ValDef]]): Template = atPos(in.currentPos) { @@ -1708,6 +1721,7 @@ mixin class Parsers requires SyntaxAnalyzer { } else if (in.token == CLASS || in.token == CASECLASS || in.token == TRAIT || + in.token == MIXIN || in.token == OBJECT || in.token == CASEOBJECT || in.token == LBRACKET || @@ -1811,11 +1825,11 @@ mixin class Parsers requires SyntaxAnalyzer { stats.toList } - /** BlockStatSeq ::= { BlockStat StatementSeparator } [Expr] + /** BlockStatSeq ::= { BlockStat StatementSeparator } [ResultExpr] * BlockStat ::= Import * | Def * | LocalModifiers TmplDef - * | Expr + * | Expr1 * | */ def blockStatSeq(stats: ListBuffer[Tree]): List[Tree] = { diff --git a/src/compiler/scala/tools/nsc/doc/DocUtil.scala b/src/compiler/scala/tools/nsc/doc/DocUtil.scala index c71c1f4477..c88b1cac35 100644 --- a/src/compiler/scala/tools/nsc/doc/DocUtil.scala +++ b/src/compiler/scala/tools/nsc/doc/DocUtil.scala @@ -26,7 +26,7 @@ object DocUtil { nodes.concat(x) } - mixin abstract class UrlContext { + mixin class UrlContext { def relative: String def aref(href0: String, target: String, text: String): NodeSeq = { diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala index 5875373d73..bbcc6cc776 100644 --- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala +++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala @@ -389,6 +389,7 @@ mixin class Definitions requires SymbolTable { AnyClass, "asInstanceOf", tparam => tparam.typeConstructor) setFlag FINAL; Any_isInstanceOfErased = newPolyMethod( AnyClass, "isInstanceOf$erased", tparam => BooleanClass.typeConstructor) setFlag FINAL; + //todo: do we need this? Any_asInstanceOfErased = newPolyMethod( AnyClass, "asInstanceOf$erased", tparam => tparam.typeConstructor) setFlag FINAL; diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala index 2d019b8c3c..3bf7478a49 100644 --- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala +++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala @@ -221,6 +221,7 @@ mixin class StdNames requires SymbolTable { val asInstanceOfErased = newTermName("asInstanceOf$erased"); val booleanValue = newTermName("booleanValue"); val box = newTermName("box"); + val boxArray = newTermName("boxArray"); val caseArity = newTermName("caseArity"); val caseElement = newTermName("caseElement"); val caseName = newTermName("caseName"); diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala index 11cc204e1d..ea85974721 100644 --- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala +++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala @@ -631,6 +631,13 @@ mixin class Symbols requires SymbolTable { final def overridingSymbol(ofclazz: Symbol): Symbol = matchingSymbol(ofclazz, ofclazz.thisType); + final def allOverriddenSymbols: List[Symbol] = + if (owner.isClass) + for (val bc <- owner.info.baseClasses; + val s = overriddenSymbol(bc); + s != NoSymbol) yield s + else List(); + /** The symbol accessed by a super in the definition of this symbol when seen from * class `base'. This symbol is always concrete. * pre: `this.owner' is in the base class sequence of `base'. diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index b715886dc5..2b4be691c9 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -1408,29 +1408,6 @@ mixin class Types requires SymbolTable { } } - object freeTypeParams extends TypeTraverser { - private var result: List[Symbol] = _; - private def includeIfAbstract(sym: Symbol): unit = { - if (sym.isAbstractType && !result.contains(sym)) result = sym :: result; - } - override def traverse(tp: Type): TypeTraverser = { - tp match { - case TypeRef(NoPrefix, sym, _) => - includeIfAbstract(sym) - case TypeRef(ThisType(_), sym, _) => - includeIfAbstract(sym) - case _ => - } - mapOver(tp); - this - } - def collect(tp: Type): List[Symbol] = { - result = List(); - traverse(tp); - result - } - } - // Helper Methods ------------------------------------------------------------- final def isValid(p: Phase): boolean = diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 2dfd93b63f..4519d2fcd6 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -54,6 +54,10 @@ abstract class ClassfileParser { } def parse(file: AbstractFile, root: Symbol): unit = { + def handleError(e: Exception) = { + if (settings.debug.value) e.printStackTrace();//debug + throw new IOException("class file '" + in.file + "' is broken") + } assert(!busy); busy = true; this.in = new AbstractFileReader(file); @@ -71,10 +75,8 @@ abstract class ClassfileParser { this.pool = new ConstantPool; parseClass() } catch { - case e: RuntimeException => - e.printStackTrace(); - if (settings.debug.value) - throw new IOException("class file '" + in.file + "' is broken") + case e: FatalError => handleError(e) + case e: RuntimeException => handleError(e) } busy = false } diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index bd84f6ed6f..7bd622cdcf 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -160,6 +160,14 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { } } + /** generate ScalaRuntime.boxArray(tree) */ + private def boxArray(tree: Tree): Tree = + typed { + atPos(tree.pos) { + runtimeCall(nme.boxArray, List(tree)) + } + } + /** The method-name xxxValue, where Xxx is a numeric value class name */ def unboxOp(tp: Type): Name = { val clazzName = tp.symbol.name.toString(); @@ -217,12 +225,28 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { pt)) } } + else if (pt.symbol.isSubClass(BoxedArrayClass) && tree.tpe.symbol == ObjectClass) + typed { + atPos(tree.pos) { + evalOnce(tree, x => + gen.cast( + If( + Apply( + TypeApply( + Select(x(), Object_isInstanceOf), + List(TypeTree(BoxedArrayClass.tpe))), + List()), + x(), + boxArray(x())), + pt)) + } + } else gen.cast(tree, pt); /** Is symbol a member of unboxed arrays (which will be expanded directly later)? */ private def isUnboxedArrayMember(sym: Symbol) = ( sym.name == nme.apply || sym.name == nme.length || sym.name == nme.update || - sym.owner == ObjectClass + sym.owner == ObjectClass && sym.name != nme.toString ); /** Is symbol a member of a boxed value class (which will not be expanded later)? */ diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index f2513bd789..ba35ebbb4b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -137,7 +137,9 @@ mixin class Contexts requires Analyzer { } def makeConstructorContext = { - val baseContext = enclClass.outer; + var baseContext = enclClass.outer; + //todo: find out why we need next line + while (baseContext.tree.isInstanceOf[Template]) baseContext = baseContext.outer; val argContext = baseContext.makeNewScope(tree, owner); for (val sym <- scope.toList) argContext.scope enter sym; argContext @@ -246,7 +248,7 @@ mixin class Contexts requires Analyzer { def restoreTypeBounds: unit = { for (val Pair(sym, info) <- savedTypeBounds) { - System.out.println("resetting " + sym + " to " + info); + if (settings.debug.value) log("resetting " + sym + " to " + info); sym.setInfo(info); } savedTypeBounds = List() diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 659f8ffe3d..467b7b7465 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -239,9 +239,9 @@ mixin class Infer requires Analyzer { val sym1 = sym filter (alt => context.isAccessible(alt, pre, site.isInstanceOf[Super])); if (sym1 == NoSymbol) { if (settings.debug.value) { - System.out.println(context);//debug - System.out.println(tree);//debug - System.out.println("" + pre + " " + sym.owner + " " + context.owner + " " + context.outer.enclClass.owner + " " + sym.owner.thisType + (pre =:= sym.owner.thisType));//debug + System.out.println(context); + System.out.println(tree); + System.out.println("" + pre + " " + sym.owner + " " + context.owner + " " + context.outer.enclClass.owner + " " + sym.owner.thisType + (pre =:= sym.owner.thisType)); } errorTree(tree, sym.toString() + " cannot be accessed in " + (if (sym.isClassConstructor) context.enclClass.owner else pre.widen)) @@ -489,11 +489,13 @@ mixin class Infer requires Analyzer { /** Substitite free type variables `undetparams' of type constructor `tree' in pattern, * given prototype `pt'. - * return type substitution for type parameters. */ def inferConstructorInstance(tree: Tree, undetparams: List[Symbol], pt: Type): unit = { - var restpe = skipImplicit(tree.tpe.resultType); + var restpe = tree.tpe.finalResultType; var tvars = undetparams map freshVar; + + /** Compute type arguments for undetermined params and substitute them in given tree. + */ def computeArgs = try { val targs = solve(tvars, undetparams, undetparams map varianceInType(restpe), true); @@ -506,7 +508,7 @@ mixin class Infer requires Analyzer { "\n --- because ---\n" + ex.getMessage()); } def instError = { - System.out.println("ici " + tree + " " + undetparams + " " + pt);//debug + if (settings.debug.value) System.out.println("ici " + tree + " " + undetparams + " " + pt); if (settings.explaintypes.value) explainTypes(restpe.subst(undetparams, tvars), pt); errorTree(tree, "constructor cannot be instantiated to expected type" + foundReqMsg(restpe, pt)) @@ -514,15 +516,15 @@ mixin class Infer requires Analyzer { if (restpe.subst(undetparams, tvars) <:< pt) { computeArgs } else if (isFullyDefined(pt)) { - System.out.println("infer constr " + tree + ":" + restpe + ", pt = " + pt);//debug + if (settings.debug.value) log("infer constr " + tree + ":" + restpe + ", pt = " + pt); val ptparams = freeTypeParams.collect(pt); - System.out.println("free type params = " + ptparams);//debug + if (settings.debug.value) log("free type params = " + ptparams); val ptWithWildcards = pt.subst(ptparams, ptparams map (ptparam => WildcardType)); tvars = undetparams map freshVar; if (restpe.subst(undetparams, tvars) <:< ptWithWildcards) { computeArgs; restpe = skipImplicit(tree.tpe.resultType); - System.out.println("new tree = " + tree + ":" + restpe);//debug + if (settings.debug.value) log("new tree = " + tree + ":" + restpe); val ptvars = ptparams map freshVar; if (restpe <:< pt.subst(ptparams, ptvars)) { for (val tvar <- ptvars) { @@ -537,7 +539,7 @@ mixin class Infer requires Analyzer { tparam setInfo TypeBounds( lub(tparam.info.bounds.lo :: loBounds), glb(tparam.info.bounds.hi :: hiBounds)); - System.out.println("new bounds of " + tparam + " = " + tparam.info);//debug + if (settings.debug.value) log("new bounds of " + tparam + " = " + tparam.info); } } } else { if (settings.debug.value) System.out.println("no instance: "); instError } @@ -545,6 +547,33 @@ mixin class Infer requires Analyzer { } else { if (settings.debug.value) System.out.println("not fuly defined: " + pt); instError } } + /** A traverser to collect type parameters referred to in a type + */ + object freeTypeParams extends TypeTraverser { + private var result: List[Symbol] = _; + private def includeIfTypeParam(sym: Symbol): unit = { + if (sym.isAbstractType && sym.owner.isTerm && !result.contains(sym)) + result = sym :: result; + } + override def traverse(tp: Type): TypeTraverser = { + tp match { + case TypeRef(NoPrefix, sym, _) => + includeIfTypeParam(sym) + case TypeRef(ThisType(_), sym, _) => + includeIfTypeParam(sym) + case _ => + } + mapOver(tp); + this + } + /** Collect all abstract type symbols referred to by type `tp' */ + def collect(tp: Type): List[Symbol] = { + result = List(); + traverse(tp); + result + } + } + /* -- Overload Resolution ----------------------------------------------------------- */ /** Assign `tree' the symbol and type of the alternative which matches @@ -571,11 +600,13 @@ mixin class Infer requires Analyzer { if (improves(alt, best)) alt else best); val competing = alts1 dropWhile (alt => best == alt || improves(best, alt)); if (best == NoSymbol) { - tree match {//debug - case Select(qual, _) => - System.out.println("qual: " + qual + ":" + qual.tpe + " with decls " + qual.tpe.decls + " with members " + qual.tpe.members + " with members " + qual.tpe.member(newTermName("$minus"))); - case _ => - } + if (settings.debug.value) { + tree match { + case Select(qual, _) => + System.out.println("qual: " + qual + ":" + qual.tpe + " with decls " + qual.tpe.decls + " with members " + qual.tpe.members + " with members " + qual.tpe.member(newTermName("$minus"))); + case _ => + } + } typeErrorTree(tree, tree.symbol.tpe, pt) } else if (!competing.isEmpty) { if (!pt.isError) @@ -598,7 +629,7 @@ mixin class Infer requires Analyzer { */ def inferMethodAlternative(tree: Tree, undetparams: List[Symbol], argtpes: List[Type], pt: Type): unit = tree.tpe match { case OverloadedType(pre, alts) => tryTwice { - if (settings.debug.value) log("infer method alt " + tree.symbol + " with alternatives " + (alts map pre.memberType) + ", argtpes = " + argtpes + ", pt = " + pt);//debug + if (settings.debug.value) log("infer method alt " + tree.symbol + " with alternatives " + (alts map pre.memberType) + ", argtpes = " + argtpes + ", pt = " + pt); val alts1 = alts filter (alt => isApplicable(undetparams, pre.memberType(alt), argtpes, pt)); def improves(sym1: Symbol, sym2: Symbol) = ( sym2 == NoSymbol || sym2.isError || diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index a775008ab2..8668afae91 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -189,7 +189,7 @@ mixin class Namers requires Analyzer { tskolems } - def skolemize(tparams: List[AbsTypeDef]): unit = if (settings.Xgadt.value) { + def skolemize(tparams: List[AbsTypeDef]): unit = { val tskolems = newTypeSkolems(tparams map (.symbol)); for (val Pair(tparam, tskolem) <- tparams zip tskolems) tparam.symbol = tskolem } @@ -208,7 +208,7 @@ mixin class Namers requires Analyzer { if (!tparams.isEmpty) { new Namer(context.makeNewScope(tree, tree.symbol)).enterSyms(tparams); ltype = new LazyPolyType(tparams map (.symbol), ltype); - skolemize(tparams); + if (tree.symbol.isTerm || settings.Xgadt.value) skolemize(tparams); } tree.symbol.setInfo(ltype); } @@ -486,12 +486,9 @@ mixin class Namers requires Analyzer { } else { val typer1 = - if (false && sym.hasFlag(PARAM) && sym.owner.isConstructor && !phase.erasedTypes) { - //todo: find out instead why Template contexts can be nested in Template contexts? - var c = context.enclClass; - while (c.tree.isInstanceOf[Template]) c = c.outer; - newTyper(c) - } else typer; + if (sym.hasFlag(PARAM) && sym.owner.isConstructor && !phase.erasedTypes) + newTyper(context.makeConstructorContext) + else typer; typer1.typedType(tpt).tpe } @@ -584,7 +581,7 @@ mixin class Namers requires Analyzer { } /* Type `elemtp' is contained in type `tp' is one of the following holds: - * - elemtp and tp are the same + * - elemtp is the same as some part of tp * - tp is a function type and elemtp is not * - tp and elemtp are function types, and arity of tp is greater than arity of elemtp * - tp and elemtp are both parameterized types with same type constructor and prefix, diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index d4628fd27d..5af2caf977 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -297,8 +297,8 @@ abstract class RefChecks extends InfoTransform { // check that case classes do not inherit from case classes if (baseClass hasFlag CASE) { if (seenCaseClass != NoSymbol && seenCaseClass != baseClass) - unit.error(clazz.pos, "illegal combination of case " + - seenCaseClass + " and case " + baseClass + " in one object"); + unit.error(clazz.pos, "implementation restriction: case " + + seenCaseClass + " and case " + baseClass + " cannot be combined in one object"); seenCaseClass = baseClass } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 2a2458ceec..1722b0ce1c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -81,8 +81,8 @@ mixin class Typers requires Analyzer { val PATTERNmode = 0x002 val TYPEmode = 0x004 - val INCONSTRmode = 0x008; // orthogonal to above. When set we are - // in the body of a constructor + val SCCmode = 0x008; // orthogonal to above. When set we are + // in the this or super constructor call of a constructor. val FUNmode = 0x10; // orthogonal to above. When set // we are looking for a method or constructor @@ -123,7 +123,7 @@ mixin class Typers requires Analyzer { } if (settings.debug.value) ex.printStackTrace() if (context.reportGeneralErrors) error(pos, msg) - else throw new Error(msg) + else throw new TypeError(msg) } /** Check that tree is a stable expression. @@ -177,6 +177,16 @@ mixin class Typers requires Analyzer { } } + def checkParamsConvertible(pos: int, tpe: Type): unit = tpe match { + case MethodType(formals, restpe) => + if (formals exists (.symbol.==(ByNameParamClass))) + error(pos, "methods with `=>'-parameters cannot be converted to function values"); + if (formals exists (.symbol.==(RepeatedParamClass))) + error(pos, "methods with `*'-parameters cannot be converted to function values"); + checkParamsConvertible(pos, restpe) + case _ => + } + /** Check that type of given tree does not contain local or private components */ object checkNoEscaping extends TypeMap { @@ -353,6 +363,7 @@ mixin class Typers requires Analyzer { if (!tree.symbol.isConstructor && pt != WildcardType && isCompatible(mt, pt) && (pt <:< functionType(mt.paramTypes map (t => WildcardType), WildcardType))) { // (4.2) if (settings.debug.value) log("eta-expanding "+tree+":"+tree.tpe+" to "+pt) + checkParamsConvertible(tree.pos, tree.tpe); typed(etaExpand(tree), mode, pt) } else if (!tree.symbol.isConstructor && mt.paramTypes.isEmpty) { // (4.3) adapt(typed(Apply(tree, List()) setPos tree.pos), mode, pt) @@ -375,22 +386,20 @@ mixin class Typers requires Analyzer { clazz.initialize if (clazz.hasFlag(CASE)) { // (5.1) val tree1 = TypeTree(clazz.primaryConstructor.tpe.asSeenFrom(tree.tpe.prefix, clazz.owner)) setOriginal tree - - // tree.tpe.prefix.memberType(clazz.primaryConstructor); //!!! - try { - inferConstructorInstance(tree1, clazz.unsafeTypeParams, pt) - } catch { - case npe : NullPointerException => - logError("CONTEXT: " + context . unit . source .dbg(tree.pos), npe); - throw npe; - case fe : FatalError => - logError("CONTEXT: " + context . unit . source .dbg(tree.pos), fe); - throw fe; - case t : Throwable => - logError("CONTEXT: " + context . unit . source .dbg(tree.pos), t); - throw t; - } - tree1 + try { + inferConstructorInstance(tree1, clazz.unsafeTypeParams, pt) + } catch { + case npe : NullPointerException => + logError("CONTEXT: " + context . unit . source .dbg(tree.pos), npe); + throw npe; + case fe : FatalError => + logError("CONTEXT: " + context . unit . source .dbg(tree.pos), fe); + throw fe; + case t : Throwable => + logError("CONTEXT: " + context . unit . source .dbg(tree.pos), t); + throw t; + } + tree1 } else if (clazz.isSubClass(SeqClass)) { // (5.2) pt.baseType(clazz).baseType(SeqClass) match { case TypeRef(pre, seqClass, args) => @@ -721,11 +730,23 @@ mixin class Typers requires Analyzer { } } - def typedSuperCall(tree: Tree): Tree = - typed(tree, EXPRmode | INCONSTRmode, UnitClass.tpe) - def typedDefDef(ddef: DefDef): DefDef = { val meth = ddef.symbol + + def checkPrecedes(tree: Tree): unit = tree match { + case Block(stat :: _, _) => checkPrecedes(stat) + case Apply(fun, _) => + if (fun.symbol.isConstructor && + fun.symbol.owner == meth.owner && fun.symbol.pos >= meth.pos) + error(fun.pos, "called constructor must precede calling constructor"); + case _ => + } + def typedSuperCall(tree: Tree): Tree = { + val result = typed(tree, EXPRmode | SCCmode, UnitClass.tpe) + checkPrecedes(result) + result + } + reenterTypeParams(ddef.tparams) reenterValueParams(ddef.vparamss) val tparams1 = List.mapConserve(ddef.tparams)(typedAbsTypeDef) @@ -806,7 +827,7 @@ mixin class Typers requires Analyzer { val block1 = copy.Block(block, stats1, expr1) .setType(if (treeInfo.isPureExpr(block)) expr1.tpe else expr1.tpe.deconst) if (isFullyDefined(pt)) block1 - else { + else { //todo: correct? if (block1.tpe.symbol.isAnonymousClass) block1 setType intersectionType(block1.tpe.parents, block1.tpe.symbol.owner) checkNoEscaping.locals(context.scope, pt, block1) @@ -890,20 +911,35 @@ mixin class Typers requires Analyzer { typedStats(stats, NoSymbol) } - def typedStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = - List.mapConserve(stats) { stat => - if (context.owner.isRefinementClass && !treeInfo.isDeclaration(stat)) - errorTree(stat, "only declarations allowed here") - stat match { - case imp @ Import(_, _) => - context = context.makeNewImport(imp) - stat.symbol.initialize - EmptyTree - case _ => - (if (exprOwner != context.owner && (!stat.isDef || stat.isInstanceOf[LabelDef])) - newTyper(context.make(stat, exprOwner)) else this).typed(stat) - } + def typedStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = { + val inBlock = exprOwner == context.owner + val result = + List.mapConserve(stats) { stat => + if (context.owner.isRefinementClass && !treeInfo.isDeclaration(stat)) + errorTree(stat, "only declarations allowed here") + stat match { + case imp @ Import(_, _) => + context = context.makeNewImport(imp) + stat.symbol.initialize + EmptyTree + case _ => + (if (!inBlock && (!stat.isDef || stat.isInstanceOf[LabelDef])) + newTyper(context.make(stat, exprOwner)) else this).typed(stat) + } + } + val scope = if (inBlock) context.scope else context.owner.info.decls; + var e = scope.elems; + while (e != null && e.owner == scope) { + var e1 = scope.lookupNextEntry(e); + while (e1 != null && e1.owner == scope) { + if (e.sym.isType || inBlock || (e.sym.tpe matches e1.sym.tpe)) + error(e.sym.pos, ""+e1.sym+" is defined twice"); + e1 = scope.lookupNextEntry(e1); + } + e = e.next } + result + } protected def typed1(tree: Tree, mode: int, pt: Type): Tree = { @@ -930,7 +966,7 @@ mixin class Typers requires Analyzer { } def typedArg(arg: Tree, pt: Type): Tree = { - val argTyper = if ((mode & INCONSTRmode) != 0) newTyper(context.makeConstructorContext) + val argTyper = if ((mode & SCCmode) != 0) newTyper(context.makeConstructorContext) else this argTyper.typed(arg, mode & stickyModes, pt) } @@ -1345,11 +1381,11 @@ mixin class Typers requires Analyzer { // if function is overloaded, filter all alternatives that match // number of arguments and expected result type. if (settings.debug.value) log("trans app "+fun1+":"+fun1.symbol+":"+fun1.tpe+" "+args);//DEBUG - if (fun1.hasSymbol && fun1.symbol.hasFlag(OVERLOADED)) { + if (fun1.hasSymbol && (fun1.symbol hasFlag OVERLOADED)) { val argtypes = args map (arg => AllClass.tpe) val pre = fun1.symbol.tpe.prefix val sym = fun1.symbol filter (alt => - isApplicable(context.undetparams, pre.memberType(alt), argtypes, pt)) + isApplicable(context.undetparams, pre.memberType(alt), argtypes, pt)) if (sym != NoSymbol) fun1 = adapt(fun1 setSymbol sym setType pre.memberType(sym), funmode, WildcardType) } @@ -1549,8 +1585,14 @@ mixin class Typers requires Analyzer { case _ => tp } + private def containsError(tp: Type): boolean = tp match { + case PolyType(tparams, restpe) => containsError(restpe) + case MethodType(formals, restpe) => (formals exists (.isError)) || containsError(restpe) + case _ => tp.isError + } + private def typedImplicit(pos: int, info: ImplicitInfo, pt: Type, local: boolean): Tree = - if (isCompatible(depoly(info.tpe), pt)) { + if (isCompatible(depoly(info.tpe), pt) && !containsError(info.tpe)) { var tree: Tree = EmptyTree def fail(reason: String, sym1: Symbol, sym2: Symbol): Tree = { if (settings.debug.value) @@ -1628,7 +1670,7 @@ mixin class Typers requires Analyzer { } def implicitsOfClass(clazz: Symbol): List[ImplicitInfo] = ( - clazz.initialize.linkedModule.moduleClass.info.decls.toList.filter(.hasFlag(IMPLICIT)) map + clazz.initialize.linkedModule.moduleClass.info.members.toList.filter(.hasFlag(IMPLICIT)) map (sym => ImplicitInfo(sym.name, clazz.linkedModule.tpe.memberType(sym), sym)) ) |