summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2006-03-08 17:38:19 +0000
committerMartin Odersky <odersky@gmail.com>2006-03-08 17:38:19 +0000
commit3d41a873e2b40d56ec60cfca7fb2cb9cef71f7fb (patch)
tree58bdd381e98cf426d642f8e16e0349d348eb8227
parentd969657ce2bbcfeffdfd15a97f3f7ca33d877737 (diff)
downloadscala-3d41a873e2b40d56ec60cfca7fb2cb9cef71f7fb.tar.gz
scala-3d41a873e2b40d56ec60cfca7fb2cb9cef71f7fb.tar.bz2
scala-3d41a873e2b40d56ec60cfca7fb2cb9cef71f7fb.zip
Some changes to make arrays work better
-rw-r--r--src/compiler/scala/tools/nsc/Interpreter.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeInfo.scala5
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala98
-rw-r--r--src/compiler/scala/tools/nsc/doc/DocUtil.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala1
-rw-r--r--src/compiler/scala/tools/nsc/symtab/StdNames.scala1
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala7
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala23
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala10
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala26
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Contexts.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala63
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala15
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala124
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))
)