summaryrefslogtreecommitdiff
path: root/sources
diff options
context:
space:
mode:
Diffstat (limited to 'sources')
-rw-r--r--sources/meta/scalac/Phase.java1
-rw-r--r--sources/meta/scalac/ast/Tree.java10
-rw-r--r--sources/scala/tools/scalai/Environment.java2
-rw-r--r--sources/scalac/ast/TreeGen.java87
-rw-r--r--sources/scalac/ast/printer/TextTreePrinter.java6
-rw-r--r--sources/scalac/symtab/Symbol.java3
-rw-r--r--sources/scalac/symtab/SymbolTablePrinter.java5
-rw-r--r--sources/scalac/symtab/Type.java72
-rw-r--r--sources/scalac/transformer/LambdaLift.java1
-rw-r--r--sources/scalac/transformer/PatternMatcher.java110
-rw-r--r--sources/scalac/transformer/matching/PatternMatcher.java110
-rw-r--r--sources/scalac/typechecker/Analyzer.java1088
-rw-r--r--sources/scalac/typechecker/Context.java2
-rw-r--r--sources/scalac/typechecker/DeSugarize.java44
-rw-r--r--sources/scalac/typechecker/Infer.java29
-rw-r--r--sources/scalac/typechecker/RefCheck.java557
-rw-r--r--sources/scalac/util/Names.java2
17 files changed, 1146 insertions, 983 deletions
diff --git a/sources/meta/scalac/Phase.java b/sources/meta/scalac/Phase.java
index eeeb32aa58..023ec454e2 100644
--- a/sources/meta/scalac/Phase.java
+++ b/sources/meta/scalac/Phase.java
@@ -19,6 +19,7 @@ public class Phase {
PARSER = new Phase("parser", "PARSER"),
ANALYZER = new Phase("analyzer", "ANALYZER"),
DESUGARIZER = new Phase("desugarizer", "ANALYZER"),
+ REFCHECK = new Phase("refcheck", "REFCHECK"),
UNCURRY = new Phase("uncurry", "UNCURRY"),
LAMBDALIFT = new Phase("lambdalift", "LAMBDALIFT"),
TRANSMATCH = new Phase("transmatch", "TRANSMATCH"),
diff --git a/sources/meta/scalac/ast/Tree.java b/sources/meta/scalac/ast/Tree.java
index 43a50fe3d4..0774958f12 100644
--- a/sources/meta/scalac/ast/Tree.java
+++ b/sources/meta/scalac/ast/Tree.java
@@ -315,30 +315,30 @@ public class Tree {
n_SingletonType.
setDescription("Singleton type").
- setRange(Phase.PARSER, Phase.ANALYZER).
+ setRange(Phase.PARSER, Phase.REFCHECK).
addField(t_TermTree, "ref");
n_SelectFromType.
setDescription("Type selection").
- setRange(Phase.PARSER, Phase.ANALYZER).
+ setRange(Phase.PARSER, Phase.REFCHECK).
addField(t_TypeTree, "qualifier").
addField(t_TypeName, "selector", SymName);
n_FunType.
setDescription("Function type").
- setRange(Phase.PARSER, Phase.ANALYZER).
+ setRange(Phase.PARSER, Phase.REFCHECK).
addField(t_TypeTrees, "argtpes").
addField(t_TypeTree, "restpe");
n_CompoundType.
setDescription("Object type (~ Template)").
- setRange(Phase.PARSER, Phase.ANALYZER).
+ setRange(Phase.PARSER, Phase.REFCHECK).
addField(t_TypeTrees, "parents").
addField(t_Trees, "refinements");
n_AppliedType.
setDescription("Applied type").
- setRange(Phase.PARSER, Phase.ANALYZER).
+ setRange(Phase.PARSER, Phase.REFCHECK).
addField(t_TypeTree, "tpe").
addField(t_TypeTrees, "args");
diff --git a/sources/scala/tools/scalai/Environment.java b/sources/scala/tools/scalai/Environment.java
index 1cb4c240fa..3214be29c1 100644
--- a/sources/scala/tools/scalai/Environment.java
+++ b/sources/scala/tools/scalai/Environment.java
@@ -151,7 +151,7 @@ public class Environment {
private void loadOwner(String what, Symbol symbol) {
assert Debug.log("search ", what, ": ", symbol);
- assert symbol.owner().isType() : Debug.show(symbol);
+ assert symbol.owner().isType() : Debug.show(symbol) + " " + symbol.owner();
assert!symbol.owner().isJava() : Debug.show(symbol);
loadTemplate(symbol.owner());
}
diff --git a/sources/scalac/ast/TreeGen.java b/sources/scalac/ast/TreeGen.java
index 7fef0be2b8..6a6c4903d5 100644
--- a/sources/scalac/ast/TreeGen.java
+++ b/sources/scalac/ast/TreeGen.java
@@ -540,6 +540,8 @@ public class TreeGen implements Kinds, Modifiers {
return ClassDef(clazz.pos, clazz, constrs, body);
}
+
+
/** Generate class definition from class symbol and body.
* All parents must by parameterless, or take unit parameters.
*/
@@ -555,44 +557,105 @@ public class TreeGen implements Kinds, Modifiers {
}
/** Build the expansion of (() => expr)
- * This is:
- * { class $anon() extends scala.Function0 { def apply() = expr } ; new $anon() }
*/
public Tree mkUnitFunction(Tree expr, Type tp, Symbol owner) {
- int pos = expr.pos;
- Type f0t = definitions.functionType(Type.EMPTY_ARRAY, tp);
+ return mkFunction(expr.pos, Tree.ValDef_EMPTY_ARRAY, expr, tp, owner);
+ }
+
+ /** Build the expansion of ((vparams_1, ..., vparams_n) => body)
+ * with result type `restype', where `owner' is the previous owner
+ * of `body'.
+ * This is:
+ * { class $anon() extends scala.Object with
+ * scala.Function_N[T_1, ..., T_n, restype] {
+ * def apply(vparams_1, ..., vparams_n) = body1
+ * }
+ * new $anon()
+ * }
+ * where
+ * vparams_i: T_i
+ * `body1' results from `body' by changing owner of all defined
+ * symbols in `body' from `owner' to the apply method.
+ */
+ public Tree mkFunction(int pos, ValDef[] vparams, Tree body, Type restype,
+ Symbol owner) {
+ int n = vparams.length;
+ Symbol[] params = new Symbol[n];
+ Type[] argtypes = new Type[n];
+ for (int i = 0; i < n; i++) {
+ params[i] = vparams[i].symbol();
+ argtypes[i] = params[i].type();
+ }
+ Type ft = definitions.functionType(argtypes, restype);
ClassSymbol clazz = new ClassSymbol(
pos, Names.ANON_CLASS_NAME.toTypeName(), owner, 0);
- clazz.setInfo(Type.compoundType(new Type[]{definitions.OBJECT_TYPE, f0t},
+ clazz.setInfo(Type.compoundType(new Type[]{definitions.OBJECT_TYPE, ft},
new Scope(), clazz));
clazz.constructor().setInfo(
Type.MethodType(Symbol.EMPTY_ARRAY, clazz.typeConstructor()));
Symbol applyMeth = new TermSymbol(pos, Names.apply, clazz, FINAL)
- .setInfo(Type.MethodType(Symbol.EMPTY_ARRAY, tp));
+ .setInfo(Type.MethodType(params, restype));
clazz.info().members().enter(applyMeth);
- Tree applyDef = DefDef(applyMeth, changeOwner(expr, owner, applyMeth));
+ for (int i = 0; i < params.length; i++) {
+ params[i].setOwner(applyMeth);
+ }
+ changeOwner(body, owner, applyMeth);
+ Tree applyDef = DefDef(applyMeth, body);
Tree classDef = ClassDef(clazz, new Tree[]{applyDef});
Tree alloc = New(pos, Type.localThisType, clazz, Tree.EMPTY_ARRAY);
return Block(new Tree[]{classDef, alloc});
}
+ public Tree mkPartialFunction(int pos, Tree applyVisitor, Tree isDefinedAtVisitor,
+ Type pattype, Type restype, Symbol owner) {
+ Type pft = definitions.partialFunctionType(pattype, restype);
+ ClassSymbol clazz = new ClassSymbol(
+ pos, Names.ANON_CLASS_NAME.toTypeName(), owner, 0);
+ clazz.setInfo(Type.compoundType(new Type[]{definitions.OBJECT_TYPE, pft},
+ new Scope(), clazz));
+ clazz.constructor().setInfo(
+ Type.MethodType(Symbol.EMPTY_ARRAY, clazz.typeConstructor()));
+
+ Tree classDef = ClassDef(clazz, new Tree[]{
+ makeVisitorMethod(pos, Names.apply, applyVisitor,
+ pattype, restype, clazz, owner),
+ makeVisitorMethod(pos, Names.isDefinedAt, isDefinedAtVisitor,
+ pattype, definitions.BOOLEAN_TYPE, clazz, owner)});
+ Tree alloc = New(pos, Type.localThisType, clazz, Tree.EMPTY_ARRAY);
+ return Block(new Tree[]{classDef, alloc});
+ }
+ //where
+ private Tree makeVisitorMethod(int pos, Name name, Tree visitor,
+ Type pattype, Type restype,
+ Symbol clazz, Symbol prevOwner) {
+ Symbol meth = new TermSymbol(pos, name, clazz, FINAL);
+ Symbol param = new TermSymbol(pos, Name.fromString("x$"), meth, PARAM)
+ .setInfo(pattype);
+ meth.setInfo(Type.MethodType(new Symbol[]{param}, restype));
+ clazz.info().members().enter(meth);
+ changeOwner(visitor, prevOwner, meth);
+ Tree body = Apply(
+ Select(Ident(param), definitions.MATCH), new Tree[]{visitor});
+ return DefDef(meth, body);
+ }
+
/** Change owner of all defined symbols from `prevOwner' to `newOwner'
*/
- public Tree changeOwner(Tree tree, final Symbol prevOwner, final Symbol newOwner) {
- Transformer lifter = new Transformer(global) {
- public Tree transform(Tree tree) {
+ public void changeOwner(Tree tree, final Symbol prevOwner, final Symbol newOwner) {
+ Traverser lifter = new Traverser() {
+ public void traverse(Tree tree) {
if (TreeInfo.isDefinition(tree)) {
Symbol sym = tree.symbol();
if (sym != null && sym.owner() == prevOwner) {
sym.setOwner(newOwner);
}
}
- return super.transform(tree);
+ super.traverse(tree);
}
};
- return lifter.transform(tree);
+ lifter.traverse(tree);
}
}
diff --git a/sources/scalac/ast/printer/TextTreePrinter.java b/sources/scalac/ast/printer/TextTreePrinter.java
index 6ed0e0d9b7..39e8f1edcf 100644
--- a/sources/scalac/ast/printer/TextTreePrinter.java
+++ b/sources/scalac/ast/printer/TextTreePrinter.java
@@ -415,13 +415,13 @@ public class TextTreePrinter implements TreePrinter {
break;
case Function(Tree.ValDef[] vparams, Tree body):
- print(TXT_LEFT_BRACE);
+ print(TXT_LEFT_PAREN);
printParams(vparams);
print(Text.Space);
print(TXT_RIGHT_ARROW);
print(Text.Space);
print(body);
- print(TXT_RIGHT_BRACE);
+ print(TXT_RIGHT_PAREN);
break;
case Assign(Tree lhs, Tree rhs):
@@ -564,7 +564,7 @@ public class TextTreePrinter implements TreePrinter {
break;
case Template(Tree[] parents, Tree[] body):
- Debug.abort("unexpected case", tree);
+ Debug.abort("unexpected case: template");
break;
default:
diff --git a/sources/scalac/symtab/Symbol.java b/sources/scalac/symtab/Symbol.java
index 65184b2134..57e85283a4 100644
--- a/sources/scalac/symtab/Symbol.java
+++ b/sources/scalac/symtab/Symbol.java
@@ -771,7 +771,8 @@ public abstract class Symbol implements Modifiers, Kinds {
/** String representation of location.
*/
public String locationString() {
- if (owner.kind == CLASS && !owner.isAnonymousClass() ||
+ if (owner.kind == CLASS &&
+ !owner.isAnonymousClass() && !owner.isCompoundSym() ||
Global.instance.debug)
return " in " + owner;
else
diff --git a/sources/scalac/symtab/SymbolTablePrinter.java b/sources/scalac/symtab/SymbolTablePrinter.java
index fdfeb0d95a..5b829d4722 100644
--- a/sources/scalac/symtab/SymbolTablePrinter.java
+++ b/sources/scalac/symtab/SymbolTablePrinter.java
@@ -513,14 +513,15 @@ public class SymbolTablePrinter {
case ThisType(Symbol sym):
if (sym == Symbol.NONE) return print("<local>.this");
if (sym.isRoot()) return print("<root>.this");
- if (sym.isAnonymousClass()) return print("this");
+ if ((sym.isAnonymousClass() || sym.isCompoundSym()) && !global.debug)
+ return print("this");
return printSymbolName(sym).print(".this");
case TypeRef(Type pre, Symbol sym, Type[] args):
if (sym.isRoot()) return print("<root>");
if (!global.debug) {
if (type.isFunctionType())
return printFunctionType(args);
- if (sym.isAnonymousClass())
+ if (sym.isAnonymousClass() || sym.isCompoundSym())
return printTemplateType(pre.memberInfo(sym).parents());
}
printPrefix(pre).printSymbolName(sym);
diff --git a/sources/scalac/symtab/Type.java b/sources/scalac/symtab/Type.java
index 62db7526e9..7fa877dc82 100644
--- a/sources/scalac/symtab/Type.java
+++ b/sources/scalac/symtab/Type.java
@@ -22,21 +22,76 @@ public class Type implements Modifiers, Kinds, TypeTags {
public case AnyType; // not used after analysis
public case NoType;
+ /** C.this.type
+ */
public case ThisType(Symbol sym);
- public case TypeRef(Type pre, Symbol sym, Type[] args) {
- assert pre.isLegalPrefix() || pre == ErrorType : pre + "#" + sym;
- }
-
+ /** pre.sym.type
+ * sym represents a value
+ */
public case SingleType(Type pre, Symbol sym) {
assert this instanceof ExtSingleType;
}
+ /** pre.sym[args]
+ * sym represents a type
+ * for example: scala.List[java.lang.String] is coded as
+ *
+ * TypeRef(
+ * SingleType(ThisType(definitions.ROOT_CLASS), definitions.SCALA),
+ * <List>,
+ * new Type[]{
+ * TypeRef(
+ * SingleType(
+ * SingleType(ThisType(definitions.ROOT_CLASS), definitions.JAVA),
+ * definitions.LANG),
+ * definitions.STRING,
+ * new Type[]{})}).
+ *
+ */
+ public case TypeRef(Type pre, Symbol sym, Type[] args) {
+ assert pre.isLegalPrefix() || pre == ErrorType : pre + "#" + sym;
+ }
+
+ /** parts_1 with ... with parts_n { members }
+ */
public case CompoundType(Type[] parts, Scope members) {
assert this instanceof ExtCompoundType;
}
+
+ /** synthetic type of a method def ...(vparams): result = ...
+ */
public case MethodType(Symbol[] vparams, Type result);
+
+ /** synthetic type of a method def ...[tparams]result
+ * For instance, given def f[a](x: a): a
+ * f has type PolyType(new Symbol[]{<a>},
+ * MethodType(new Symbol[]{<x>}, <a>.type()))
+ *
+ * if tparams is empty, this is the type of a parameterless method
+ * def ... =
+ * For instance, given def f = 1
+ * f has type PolyType(new Symbol[]{}, <scala.Int>.type())
+ */
public case PolyType(Symbol[] tparams, Type result);
+
+ /** synthetic type of an overloaded value whose alternatives are
+ * alts_1, ..., alts_n, with respective types alttypes_1, ..., alttypes_n
+ *
+ * For instance, if there are two definitions of `f'
+ * def f: int
+ * def f: String
+ * then there are three symbols:
+ * ``f1'' corresponding to def f: int
+ * ``f2'' corresponding to def f: String
+ * ``f3'' corresponding to both
+ * f3 has type
+ * OverloadedType(
+ * new Symbol[]{<f1>, <f2>},
+ * new Type[]{PolyType(new Symbol[]{}, <int>),
+ * PolyType(new Symbol[]{}, <String>),
+ *
+ */
public case OverloadedType(Symbol[] alts, Type[] alttypes);
/** Hidden case to implement delayed evaluation of types.
@@ -2528,6 +2583,15 @@ public class Type implements Modifiers, Kinds, TypeTags {
super(msg);
}
}
+
+ public static void explainTypes(Type found, Type required) {
+ if (Global.instance.explaintypes) {
+ boolean s = explainSwitch;
+ explainSwitch = true;
+ found.isSubType(required);
+ explainSwitch = s;
+ }
+ }
}
/* A standard pattern match:
diff --git a/sources/scalac/transformer/LambdaLift.java b/sources/scalac/transformer/LambdaLift.java
index fd89c3c260..1e90f95624 100644
--- a/sources/scalac/transformer/LambdaLift.java
+++ b/sources/scalac/transformer/LambdaLift.java
@@ -197,6 +197,7 @@ public class LambdaLift extends OwnerTransformer
public Tree transform(Tree tree) {
//if (global.debug) global.debugPrinter.print("free ").print(tree).println().end();//DEBUG
+ assert tree.type != null : tree;
traverseTypeMap.apply(tree.type.widen());
Symbol sym = tree.symbol();
switch(tree) {
diff --git a/sources/scalac/transformer/PatternMatcher.java b/sources/scalac/transformer/PatternMatcher.java
index d15a6d22a1..3426a52424 100644
--- a/sources/scalac/transformer/PatternMatcher.java
+++ b/sources/scalac/transformer/PatternMatcher.java
@@ -345,7 +345,7 @@ public class PatternMatcher {
protected Tree[] patternArgs(Tree tree) {
switch (tree) {
case Apply(_, Tree[] args):
- if (args.length == 1)
+ if (args.length == 1 && (tree.type.symbol().flags & Modifiers.CASE) == 0)
switch (args[0]) {
case Sequence(Tree[] ts):
return ts;
@@ -378,60 +378,62 @@ public class PatternMatcher {
protected PatternNode patternNode(Tree tree, Header header, CaseEnv env) {
switch (tree) {
- case Apply(Tree fn, Tree[] args): // pattern with args
- if (args.length == 1)
- switch (args[0]) {
- case Sequence(Tree[] ts):
- return makeSequencePat(tree.pos, tree.type, ts.length);
- }
- return makeConstrPat(tree.pos, getConstrType(tree.type));
- case Typed(Ident(Name name), Tree tpe): // variable pattern
- PatternNode node =
- (header.type.isSubType(getConstrType(tpe.type))) ?
- makeDefaultPat(tree.pos, getConstrType(tpe.type))
- : makeConstrPat(tree.pos, getConstrType(tpe.type));
- if ((env != null) && (name != WILDCARD_N))
- switch (node) {
- case ConstrPat(Symbol casted):
- env.newBoundVar(
- tree.pos,
- ((Tree.Typed)tree).expr.symbol(),
- getConstrType(tpe.type),
- make.Ident(tree.pos, casted.name).
- setType(typeOf(casted)).
- setSymbol(casted));
- break;
- default:
- env.newBoundVar(
- tree.pos,
- ((Tree.Typed)tree).expr.symbol(),
- getConstrType(tpe.type),
- header.selector);
- }
- return node;
- case Ident(Name name): // pattern without args or variable
- if (tree.symbol().isPrimaryConstructor())
- return makeConstrPat(tree.pos, getConstrType(tree.type));
- else if (name.isVariable()) {
- if ((env != null) && (name != WILDCARD_N))
- env.newBoundVar(
- tree.pos,
- tree.symbol(),
- getConstrType(tree.type),
- header.selector);
- return makeDefaultPat(tree.pos, getConstrType(header.type));
- } else
+ case Apply(Tree fn, Tree[] args): // pattern with args
+ if (args.length == 1 && (tree.type.symbol().flags & Modifiers.CASE) == 0)
+ switch (args[0]) {
+ case Sequence(Tree[] ts):
+ return makeSequencePat(tree.pos, tree.type, ts.length);
+ }
+ return makeConstrPat(tree.pos, getConstrType(tree.type));
+ case Typed(Ident(Name name), Tree tpe): // variable pattern
+ PatternNode node =
+ (header.type.isSubType(getConstrType(tpe.type))) ?
+ makeDefaultPat(tree.pos, getConstrType(tpe.type))
+ : makeConstrPat(tree.pos, getConstrType(tpe.type));
+ if ((env != null) && (name != WILDCARD_N))
+ switch (node) {
+ case ConstrPat(Symbol casted):
+ env.newBoundVar(
+ tree.pos,
+ ((Tree.Typed)tree).expr.symbol(),
+ getConstrType(tpe.type),
+ make.Ident(tree.pos, casted.name).
+ setType(typeOf(casted)).
+ setSymbol(casted));
+ break;
+ default:
+ env.newBoundVar(
+ tree.pos,
+ ((Tree.Typed)tree).expr.symbol(),
+ getConstrType(tpe.type),
+ header.selector);
+ }
+ return node;
+ case Ident(Name name): // pattern without args or variable
+ if (tree.symbol().isPrimaryConstructor())
+ return makeConstrPat(tree.pos, getConstrType(tree.type));
+ else if (name.isVariable()) {
+ if ((env != null) && (name != WILDCARD_N))
+ env.newBoundVar(
+ tree.pos,
+ tree.symbol(),
+ getConstrType(tree.type),
+ header.selector);
+ return makeDefaultPat(tree.pos, getConstrType(header.type));
+ } else
return makeVariablePat(tree.pos, tree);
- case Select(_, Name name): // variable
- if (tree.symbol().isPrimaryConstructor())
- return makeConstrPat(tree.pos, getConstrType(tree.type));
- else
- return makeVariablePat(tree.pos, tree);
- case Literal(Object value):
- return makeConstantPat(tree.pos, getConstrType(tree.type), value);
- default:
- new scalac.ast.printer.TextTreePrinter().print(tree).flush();
- throw new ApplicationError(tree);
+ case Select(_, Name name): // variable
+ if (tree.symbol().isPrimaryConstructor())
+ return makeConstrPat(tree.pos, getConstrType(tree.type));
+ else
+ return makeVariablePat(tree.pos, tree);
+ case Literal(Object value):
+ return makeConstantPat(tree.pos, getConstrType(tree.type), value);
+ case Sequence(Tree[] ts):
+ return makeSequencePat(tree.pos, tree.type, ts.length);
+ default:
+ new scalac.ast.printer.TextTreePrinter().print(tree).flush();
+ throw new ApplicationError(tree);
}
}
diff --git a/sources/scalac/transformer/matching/PatternMatcher.java b/sources/scalac/transformer/matching/PatternMatcher.java
index d15a6d22a1..3426a52424 100644
--- a/sources/scalac/transformer/matching/PatternMatcher.java
+++ b/sources/scalac/transformer/matching/PatternMatcher.java
@@ -345,7 +345,7 @@ public class PatternMatcher {
protected Tree[] patternArgs(Tree tree) {
switch (tree) {
case Apply(_, Tree[] args):
- if (args.length == 1)
+ if (args.length == 1 && (tree.type.symbol().flags & Modifiers.CASE) == 0)
switch (args[0]) {
case Sequence(Tree[] ts):
return ts;
@@ -378,60 +378,62 @@ public class PatternMatcher {
protected PatternNode patternNode(Tree tree, Header header, CaseEnv env) {
switch (tree) {
- case Apply(Tree fn, Tree[] args): // pattern with args
- if (args.length == 1)
- switch (args[0]) {
- case Sequence(Tree[] ts):
- return makeSequencePat(tree.pos, tree.type, ts.length);
- }
- return makeConstrPat(tree.pos, getConstrType(tree.type));
- case Typed(Ident(Name name), Tree tpe): // variable pattern
- PatternNode node =
- (header.type.isSubType(getConstrType(tpe.type))) ?
- makeDefaultPat(tree.pos, getConstrType(tpe.type))
- : makeConstrPat(tree.pos, getConstrType(tpe.type));
- if ((env != null) && (name != WILDCARD_N))
- switch (node) {
- case ConstrPat(Symbol casted):
- env.newBoundVar(
- tree.pos,
- ((Tree.Typed)tree).expr.symbol(),
- getConstrType(tpe.type),
- make.Ident(tree.pos, casted.name).
- setType(typeOf(casted)).
- setSymbol(casted));
- break;
- default:
- env.newBoundVar(
- tree.pos,
- ((Tree.Typed)tree).expr.symbol(),
- getConstrType(tpe.type),
- header.selector);
- }
- return node;
- case Ident(Name name): // pattern without args or variable
- if (tree.symbol().isPrimaryConstructor())
- return makeConstrPat(tree.pos, getConstrType(tree.type));
- else if (name.isVariable()) {
- if ((env != null) && (name != WILDCARD_N))
- env.newBoundVar(
- tree.pos,
- tree.symbol(),
- getConstrType(tree.type),
- header.selector);
- return makeDefaultPat(tree.pos, getConstrType(header.type));
- } else
+ case Apply(Tree fn, Tree[] args): // pattern with args
+ if (args.length == 1 && (tree.type.symbol().flags & Modifiers.CASE) == 0)
+ switch (args[0]) {
+ case Sequence(Tree[] ts):
+ return makeSequencePat(tree.pos, tree.type, ts.length);
+ }
+ return makeConstrPat(tree.pos, getConstrType(tree.type));
+ case Typed(Ident(Name name), Tree tpe): // variable pattern
+ PatternNode node =
+ (header.type.isSubType(getConstrType(tpe.type))) ?
+ makeDefaultPat(tree.pos, getConstrType(tpe.type))
+ : makeConstrPat(tree.pos, getConstrType(tpe.type));
+ if ((env != null) && (name != WILDCARD_N))
+ switch (node) {
+ case ConstrPat(Symbol casted):
+ env.newBoundVar(
+ tree.pos,
+ ((Tree.Typed)tree).expr.symbol(),
+ getConstrType(tpe.type),
+ make.Ident(tree.pos, casted.name).
+ setType(typeOf(casted)).
+ setSymbol(casted));
+ break;
+ default:
+ env.newBoundVar(
+ tree.pos,
+ ((Tree.Typed)tree).expr.symbol(),
+ getConstrType(tpe.type),
+ header.selector);
+ }
+ return node;
+ case Ident(Name name): // pattern without args or variable
+ if (tree.symbol().isPrimaryConstructor())
+ return makeConstrPat(tree.pos, getConstrType(tree.type));
+ else if (name.isVariable()) {
+ if ((env != null) && (name != WILDCARD_N))
+ env.newBoundVar(
+ tree.pos,
+ tree.symbol(),
+ getConstrType(tree.type),
+ header.selector);
+ return makeDefaultPat(tree.pos, getConstrType(header.type));
+ } else
return makeVariablePat(tree.pos, tree);
- case Select(_, Name name): // variable
- if (tree.symbol().isPrimaryConstructor())
- return makeConstrPat(tree.pos, getConstrType(tree.type));
- else
- return makeVariablePat(tree.pos, tree);
- case Literal(Object value):
- return makeConstantPat(tree.pos, getConstrType(tree.type), value);
- default:
- new scalac.ast.printer.TextTreePrinter().print(tree).flush();
- throw new ApplicationError(tree);
+ case Select(_, Name name): // variable
+ if (tree.symbol().isPrimaryConstructor())
+ return makeConstrPat(tree.pos, getConstrType(tree.type));
+ else
+ return makeVariablePat(tree.pos, tree);
+ case Literal(Object value):
+ return makeConstantPat(tree.pos, getConstrType(tree.type), value);
+ case Sequence(Tree[] ts):
+ return makeSequencePat(tree.pos, tree.type, ts.length);
+ default:
+ new scalac.ast.printer.TextTreePrinter().print(tree).flush();
+ throw new ApplicationError(tree);
}
}
diff --git a/sources/scalac/typechecker/Analyzer.java b/sources/scalac/typechecker/Analyzer.java
index 1e8ec9daa9..c4b404cc9a 100644
--- a/sources/scalac/typechecker/Analyzer.java
+++ b/sources/scalac/typechecker/Analyzer.java
@@ -23,6 +23,8 @@ import scalac.symtab.*;
import Tree.*;
import java.util.HashMap;
+/** The main attribution phase.
+ */
public class Analyzer extends Transformer implements Modifiers, Kinds {
private final Definitions definitions;
@@ -131,39 +133,13 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
// expressions may be packages and
// Java statics modules.
- static final int baseModes = EXPRmode | PATTERNmode | CONSTRmode;
-
-// Helper definitions ---------------------------------------------------------
+ static final int SUPERmode = 0x080; // orthogonal to above. When set
+ // we are checking a superclass
+ // constructor invocation.
- /** The qualifier type of a potential application of the `match' method.
- * or NoType, if this is something else.
- */
- private Type matchQualType(Tree fn) {
- switch (fn) {
- case Select(Tree qual, _):
- if (fn.symbol() == definitions.OBJECT_TYPE.lookup(Names.match))
- return qual.type.widen();
- break;
- case TypeApply(Tree fn1, _):
- return matchQualType(fn1);
- case Ident(_):
- if (fn.symbol() == definitions.OBJECT_TYPE.lookup(Names.match))
- return context.enclClass.owner.typeOfThis();
- break;
- }
- return fn.type == Type.ErrorType ? Type.ErrorType : Type.NoType;
- }
+ static final int baseModes = EXPRmode | PATTERNmode | CONSTRmode;
- private Type value2Type(Object value) {
- if (value instanceof Character) return definitions.CHAR_TYPE;
- else if (value instanceof Integer) return definitions.INT_TYPE;
- else if (value instanceof Long) return definitions.LONG_TYPE;
- else if (value instanceof Float) return definitions.FLOAT_TYPE;
- else if (value instanceof Double) return definitions.DOUBLE_TYPE;
- else if (value instanceof String) return definitions.JAVA_STRING_TYPE;
- else if (value instanceof Boolean) return definitions.BOOLEAN_TYPE;
- else throw new ApplicationError();
- }
+// Diagnostics ----------------------------------------------------------------
Tree errorTree(int pos) {
return make.Bad(pos).setSymbol(Symbol.ERROR).setType(Type.ErrorType);
@@ -174,14 +150,6 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
return errorTree(pos);
}
- void explainTypes(Type found, Type required) {
- if (global.explaintypes) {
- Type.explainSwitch = true;
- found.isSubType(required);
- Type.explainSwitch = false;
- }
- }
-
void typeError(int pos, Type found, Type req) {
String msg = infer.typeErrorMsg("type mismatch", found, req);
Type foundResult = found.resultType();
@@ -266,7 +234,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
* - no conflicting modifiers
* - `abstract' modifier only for classes
* - `override' modifier never for classes
- * - def and `*' modifiers only in methods
+ * - `def' modifier never for parameters of case classes
* - declarations only in traits or abstract classes
* - symbols with `override' modifier override some other symbol.
*/
@@ -283,18 +251,23 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
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()) {
- error(sym.pos, "`def' modifier not allowed for class parameters");
+ if ((sym.flags & DEF) != 0 && sym.owner().isPrimaryConstructor() &&
+ (sym.owner().primaryConstructorClass().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, abstractVarNote(sym,
- "only classes can have declared but undefined members"));
+ error(sym.pos,
+ "only classes can have declared but undefined members" +
+ (((sym.flags & MUTABLE) == 0) ? ""
+ : "\n(Note that variables need to be initialized to be defined)"));
sym.flags &= ~DEFERRED;
}
}
@@ -571,206 +544,128 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
}
}
- /** Check all members of class `clazz' for overriding conditions.
- */
- void checkAllOverrides(Symbol clazz) {
- Type[] closure = clazz.closure();
- for (int i = 0; i < closure.length; i++) {
- for (Scope.SymbolIterator it = closure[i].members().iterator();
- it.hasNext();) {
- Symbol other = it.next();
- Symbol member = clazz.info().lookup(other.name);
- if (other != member && (other.flags & PRIVATE) == 0 &&
- member.kind != NONE)
- checkOverride(clazz, member, other);
- if ((member.flags & DEFERRED) != 0 &&
- clazz.kind == CLASS &&
- (clazz.flags & ABSTRACTCLASS) == 0) {
- if (clazz.isAnonymousClass())
- error(clazz.pos, "object creation impossible, since " +
- member + member.locationString() + " is not defined");
- else
- error(clazz.pos,
- clazz + abstractVarNote(
- member, " needs to be abstract; it does not define " +
- member + member.locationString()));
- clazz.flags |= ABSTRACTCLASS;
- }
- }
- }
- }
-
- /** Check that all conditions for overriding `other' by `member' are met.
+ /** Check that all subtrees have their types defined.
+ * Used for asserting an internal invariant
*/
- void checkOverride(Symbol clazz, Symbol member, Symbol other) {
- int pos;
- if (member.owner() == clazz) pos = member.pos;
- else if (!member.owner().isSubClass(other.owner())) pos = context.tree.pos;
- else return; // everything was already checked elsewhere
-
- if ((member.flags & PRIVATE) != 0) {
- overrideError(pos, member, other, "has weaker access privileges; it should not be private");
- } else if ((member.flags & PROTECTED) != 0 && (other.flags & PROTECTED) == 0) {
- overrideError(pos, member, other, "has weaker access privileges; it should not be protected");
- } else if ((other.flags & FINAL) != 0) {
- overrideError(pos, member, other, "cannot override final member");
- } else if ((other.flags & DEFERRED) == 0 && ((member.flags & OVERRIDE) == 0)) {
- overrideError(pos, member, other, "needs `override' modifier");
- } else if (other.isStable() && !member.isStable()) {
- overrideError(pos, member, other, "needs to be an immutable value");
- } else {
- Type self = clazz.thisType();
- switch (other.kind) {
- case CLASS:
- overrideError(pos, member, other, "cannot override a class");
- break;
- case ALIAS:
- if (!self.memberType(member).isSameAs(self.memberType(other)))
- overrideTypeError(pos, member, other, self, false);
- break;
- default:
- if (other.isConstructor())
- overrideError(pos, member, other,
- "cannot override a class constructor");
- Type selftype = normalizedInfo(self, member);
- Type othertype = normalizedInfo(self, other);
- if (!selftype.isSubType(othertype))
- overrideTypeError(pos, member, other, self, false);
- if (member.kind == TYPE &&
- !self.memberLoBound(other).isSubType(
- self.memberLoBound(member)))
- overrideTypeError(pos, member, other, self, true);
-
- }
+ private static class CheckDefined extends Traverser {
+ Tree all;
+ public void traverse(Tree tree) {
+ assert tree.type != null : tree + " in " + all;
+ if (tree.type != Type.ErrorType)
+ super.traverse(tree);
}
}
- void overrideError(int pos, Symbol member, Symbol other, String msg) {
- if (other.type() != Type.ErrorType && member.type() != Type.ErrorType)
- error(pos,
- "error overriding " + other + other.locationString() +
- ";\n " + member + member.locationString() + " " + msg);
- }
-
- void overrideTypeError(int pos, Symbol member, Symbol other, Type site,
- boolean lobound) {
- if (other.type() != Type.ErrorType && member.type() != Type.ErrorType) {
- Type memberInfo = lobound ? site.memberLoBound(member)
- : normalizedInfo(site, member);
- Type otherInfo = lobound ? site.memberLoBound(other)
- : normalizedInfo(site, other);
- error(pos,
- member + member.locationString() +
- infoString(member, memberInfo, lobound) +
- "\n cannot override " + other + other.locationString() +
- infoString(other, otherInfo, lobound));
- explainTypes(memberInfo, otherInfo);
- }
- }
+ private static CheckDefined checkDefined = new CheckDefined();
- Type normalizedInfo(Type site, Symbol sym) {
- Type tp = site.memberInfo(sym);
- if (sym.kind == VAL && (sym.flags & STABLE) != 0) tp = tp.resultType();
- return tp;
- }
+// Helper definitions for calculating types -----------------------------------------
- String infoString(Symbol sym, Type symtype, boolean lobound) {
- switch (sym.kind) {
- case ALIAS: return ", which equals " + symtype;
- case TYPE: return " bounded" + (lobound ? " from below" : "") + " by " + symtype;
- case VAL: return " of type " + symtype;
- default: return "";
+ /** The qualifier type of a potential application of the `match' method.
+ * or NoType, if this is something else.
+ */
+ private Type matchQualType(Tree fn) {
+ switch (fn) {
+ case Select(Tree qual, _):
+ if (fn.symbol() == definitions.OBJECT_TYPE.lookup(Names.match))
+ return qual.type.widen();
+ break;
+ case TypeApply(Tree fn1, _):
+ return matchQualType(fn1);
+ case Ident(_):
+ if (fn.symbol() == definitions.OBJECT_TYPE.lookup(Names.match))
+ return context.enclClass.owner.typeOfThis();
+ break;
}
+ return fn.type == Type.ErrorType ? Type.ErrorType : Type.NoType;
}
- String abstractVarNote(Symbol member, String msg) {
- String note = ((member.flags & MUTABLE) == 0) ? ""
- : "\n(Note that variables need to be initialized to be defined)";
- return msg + note;
+ private Type value2Type(Object value) {
+ if (value instanceof Character) return definitions.CHAR_TYPE;
+ else if (value instanceof Integer) return definitions.INT_TYPE;
+ else if (value instanceof Long) return definitions.LONG_TYPE;
+ else if (value instanceof Float) return definitions.FLOAT_TYPE;
+ else if (value instanceof Double) return definitions.DOUBLE_TYPE;
+ else if (value instanceof String) return definitions.JAVA_STRING_TYPE;
+ else if (value instanceof Boolean) return definitions.BOOLEAN_TYPE;
+ else throw new ApplicationError();
}
-// Variance Checking --------------------------------------------------------
-
- private final int
- ContraVariance = -1,
- NoVariance = 0,
- CoVariance = 1,
- AnyVariance = 2;
+// Contexts -------------------------------------------------------------------
- private String varianceString(int variance) {
- if (variance == 1) return "covariant";
- else if (variance == -1) return "contravariant";
- else return "invariant";
+ /** Push new context associated with given tree, owner, and scope on stack.
+ * Fields `imports' and, possibly, `enclClass' are inherited from parent.
+ */
+ void pushContext(Tree tree, Symbol owner, Scope scope) {
+ context = new Context(tree, owner, scope, context);
}
- /** The variance of symbol `base' relative to the class which defines `tvar'.
+ /** Pop context from stack.
*/
- int flip(Symbol base, Symbol tvar) {
- Symbol clazz = tvar.owner().primaryConstructorClass();
- Symbol sym = base;
- int flip = CoVariance;
- while (sym != clazz && flip != AnyVariance) {
- //System.out.println("flip: " + sym + " " + sym.isParameter());//DEBUG
- if (sym.isParameter()) flip = -flip;
- else if (sym.owner().kind != CLASS) flip = AnyVariance;
- else if (sym.kind == ALIAS) flip = NoVariance;
- sym = sym.owner();
- }
- return flip;
+ void popContext() {
+ context = context.outer;
}
- /** Check variance of type variables in this type
+// Lazy Types ------------------------------------------------------------------
+
+ /** A lazy type which, when forced returns the type of a symbol defined
+ * in `tree'.
*/
- void validateVariance(Symbol base, Type tp, int variance) {
- validateVariance(base, tp, tp, variance);
+ class LazyTreeType extends Type.LazyType {
+ Tree tree;
+ Unit u;
+ Context c;
+
+ LazyTreeType(Tree tree) {
+ this.tree = tree;
+ this.u = unit;
+ this.c = context;
+ }
+ public void complete(Symbol sym) {
+ //System.out.println("completing " + sym);//DEBUG
+ //if (sym.isConstructor()) sym.constructorClass().initialize();
+ //else if (sym.isModule()) sym.moduleClass().initialize();
+ defineSym(tree, u, c);
+ }
}
- void validateVariance(Symbol base, Type all, Type tp, int variance) {
- switch (tp) {
- case ErrorType:
- case AnyType:
- case NoType:
- case ThisType(Symbol sym):
- break;
- case SingleType(Type pre, Symbol sym):
- validateVariance(base, all, pre, variance);
- break;
- case TypeRef(Type pre, Symbol sym, Type[] args):
- if (sym.variance() != 0) {
- int f = flip(base, sym);
- if (f != AnyVariance && sym.variance() != f * variance) {
- //System.out.println("flip(" + base + "," + sym + ") = " + f);//DEBUG
- error(base.pos,
- varianceString(sym.variance()) + " " + sym +
- " occurs in " + varianceString(f * variance) +
- " position in type " + all + " of " + base);
+ /** 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 extends LazyTreeType {
+ LazyConstrMethodType(Tree tree) {
+ super(tree);
+ }
+ public void complete(Symbol sym) {
+ Type constrtype = tree.symbol().constructor().type().instanceType();
+ switch (tree) {
+ case ClassDef(_, _, _, ValDef[][] vparams, _, _):
+ if (vparams.length == 0) {
+ constrtype = removeMethod(constrtype);
}
}
- validateVariance(base, all, pre, variance);
- validateVariance(base, all, args, variance, sym.typeParams());
- break;
- case CompoundType(Type[] parts, Scope members):
- validateVariance(base, all, parts, variance);
- break;
- case MethodType(Symbol[] vparams, Type result):
- validateVariance(base, all, result, variance);
- break;
- case PolyType(Symbol[] tparams, Type result):
- validateVariance(base, all, result, variance);
- break;
- case OverloadedType(Symbol[] alts, Type[] alttypes):
- validateVariance(base, all, alttypes, variance);
+ sym.setInfo(constrtype);
+ }
+ private Type removeMethod(Type tp) {
+ switch (tp) {
+ case MethodType(_, Type restp):
+ return restp;
+ case PolyType(Symbol[] tparams, Type restp):
+ return Type.PolyType(tparams, removeMethod(restp));
+ default:
+ return tp;
+ }
}
}
- void validateVariance(Symbol base, Type all, Type[] tps, int variance) {
- for (int i = 0; i < tps.length; i++)
- validateVariance(base, all, tps[i], variance);
- }
-
- void validateVariance(Symbol base, Type all, Type[] tps, int variance, Symbol[] tparams) {
- for (int i = 0; i < tps.length; i++)
- validateVariance(base, all, tps[i], variance * tparams[i].variance());
+ /** A lazy type for self types
+ */
+ class LazySelfType extends LazyTreeType {
+ LazySelfType(Tree tree) {
+ super(tree);
+ }
+ public void complete(Symbol sym) {
+ defineSelfType(sym, tree, u, c);
+ }
}
// Entering Symbols ----------------------------------------------------------
@@ -966,6 +861,42 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
enterSym(stats[i]);
}
+ Symbol[] enterParams(Tree[] params) {
+ for (int i = 0; i < params.length; i++) {
+ enterSym(params[i]);
+ switch (params[i]) {
+ case ValDef(int mods, _, _, _):
+ if ((mods & REPEATED) != 0 && params.length > 1)
+ error(params[i].pos,
+ "`*' parameter must be the only parameter of a `('...`)' section");
+ }
+ }
+ return Tree.symbolOf(params);
+ }
+
+ Symbol[][] enterParams(Tree[][] vparams) {
+ Symbol[][] vparamSyms = new Symbol[vparams.length][];
+ for (int i = 0; i < vparams.length; i++) {
+ vparamSyms[i] = enterParams(vparams[i]);
+ }
+ return vparamSyms;
+ }
+
+ /** Re-enter type parameters in current scope.
+ */
+ void reenterParams(Tree[] params) {
+ for (int i = 0; i < params.length; i++) {
+ context.scope.enter(params[i].symbol());
+ }
+ }
+
+ /** Re-enter value parameters in current scope.
+ */
+ void reenterParams(Tree[][] vparams) {
+ for (int i = 0; i < vparams.length; i++)
+ reenterParams(vparams[i]);
+ }
+
// Definining Symbols -------------------------------------------------------
/** Define symbol associated with `tree' using given `unit' and `context'.
@@ -986,12 +917,6 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
Type owntype;
switch (tree) {
case ClassDef(int mods, Name name, Tree.TypeDef[] tparams, Tree.ValDef[][] vparams, Tree tpe, Tree.Template templ):
- // todo: check why this is necessary
- if ((mods & LOCKED) != 0 && !sym.isAnonymousClass()) {
- sym.setInfo(Type.ErrorType);
- throw new CyclicReference(sym, Type.NoType);
- }
- ((ClassDef) tree).mods |= LOCKED;
pushContext(tree, sym.constructor(), new Scope(context.scope));
Symbol[] tparamSyms = enterParams(tparams);
Symbol[][] vparamSyms = enterParams(vparams);
@@ -1021,12 +946,14 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
Symbol clazz = sym.moduleClass();
defineTemplate(templ, clazz);
clazz.setInfo(templ.type);
- if (tpe == Tree.Empty) owntype = clazz.type();
- else owntype = transform(tpe, TYPEmode).type;
+ ((ModuleDef) tree).tpe = tpe = transform(tpe, TYPEmode);
+ owntype = (tpe == Tree.Empty) ? clazz.type() : tpe.type;
break;
case ValDef(int mods, Name name, Tree tpe, Tree rhs):
- if (tpe == Tree.Empty) {
+ if (tpe != Tree.Empty) {
+ ((ValDef) tree).tpe = tpe = transform(tpe, TYPEmode);
+ } else {
pushContext(tree, sym, context.scope);
if (rhs == Tree.Empty) {
if ((sym.owner().flags & ACCESSOR) != 0) {
@@ -1039,20 +966,13 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
((ValDef) tree).tpe = tpe =
gen.mkType(tree.pos, Type.ErrorType);
}
- owntype = tpe.type;
} else {
- if ((mods & CASEACCESSOR) != 0) {
- //rhs was already attributed
- assert rhs.type != null;
- } else {
- ((ValDef) tree).rhs = rhs = transform(rhs, EXPRmode);
- }
- owntype = rhs.type;
+ ((ValDef) tree).rhs = rhs = transform(rhs, EXPRmode);
+ ((ValDef) tree).tpe = tpe = gen.mkType(tree.pos, rhs.type);
}
popContext();
- } else {
- owntype = transform(tpe, TYPEmode).type;
}
+ owntype = tpe.type;
checkNonCyclic(tree.pos, owntype);
break;
@@ -1060,43 +980,41 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
pushContext(tree, sym, new Scope(context.scope));
Symbol[] tparamSyms = enterParams(tparams);
Symbol[][] vparamSyms = enterParams(vparams);
- Type restpe;
- if (tpe == Tree.Empty) {
+ if (tpe != Tree.Empty) {
+ ((DefDef) tree).tpe = tpe = transform(tpe, TYPEmode);
+ } else {
int rhsmode = name.isConstrName() ? CONSTRmode : EXPRmode;
((DefDef) tree).rhs = rhs = transform(rhs, rhsmode);
- restpe = checkNoEscape(rhs.pos, rhs.type);
- } else {
- restpe = checkNoEscape(
- tpe.pos, transform(tpe, TYPEmode).type);
+ ((DefDef) tree).tpe = tpe = gen.mkType(tree.pos, rhs.type);
}
+ Type restype = checkNoEscape(tpe.pos, tpe.type);
popContext();
- checkNonCyclic(tree.pos, restpe);
- owntype = makeMethodType(tparamSyms, vparamSyms, restpe);
+ checkNonCyclic(tree.pos, restype);
+ owntype = makeMethodType(tparamSyms, vparamSyms, restype);
//System.out.println("methtype " + name + ":" + owntype);//DEBUG
break;
case TypeDef(int mods, Name name, Tree rhs, Tree lobound):
if (sym.kind == TYPE) {
- //can't have `sym' as onwer since checkNonCyclic would fail.
- pushContext(rhs, context.owner, context.scope);
- context.delayArgs = true;
- owntype = transform(rhs, TYPEmode).type;
- sym.setLoBound(transform(lobound, TYPEmode).type);
- owntype.symbol().initialize();//to detect cycles
- popContext();
+ //can't have `sym' as owner since checkNonCyclic would fail.
+ ((TypeDef) tree).rhs = rhs = transform(rhs, TYPEmode);
+ ((TypeDef) tree).lobound = lobound = transform(lobound, TYPEmode);
+ owntype = rhs.type;
+ sym.setLoBound(lobound.type);
+ owntype.symbol().initialize();//to detect cycles todo: needed?
} else { // sym.kind == ALIAS
pushContext(tree, sym, context.scope);
- owntype = transform(rhs, TYPEmode | FUNmode).type;
+ ((TypeDef) tree).rhs = rhs = transform(rhs, TYPEmode | FUNmode);
+ owntype = rhs.type;
popContext();
}
checkNonCyclic(tree.pos, owntype);
break;
case Import(Tree expr, Name[] selectors):
- Tree expr1 = transform(expr, EXPRmode | QUALmode);
- ((Import) tree).expr = expr1;
- checkStable(expr1);
- owntype = expr1.type;
+ ((Import) tree).expr = expr = transform(expr, EXPRmode | QUALmode);
+ checkStable(expr);
+ owntype = expr.type;
break;
default:
@@ -1122,13 +1040,8 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
*/
void defineTemplate(Tree.Template templ, Symbol clazz) {
// attribute parent constructors
- Tree[] constrs = transformConstrInvocations(
- templ.pos, templ.parents, true);
-
- Type[] parents = new Type[constrs.length];
- for (int i = 0; i < parents.length; i++) {
- parents[i] = constrs[i].type;
- }
+ Tree[] constrs = transformConstrInvocations(templ.pos, templ.parents);
+ Type[] parents = Tree.typeOf(constrs);
// enter all members
Scope members = new Scope();
@@ -1136,31 +1049,9 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
templ.body = desugarize.Statements(templ.body, false);
enterSyms(templ.body);
popContext();
-
templ.type = Type.compoundType(parents, members, clazz);
}
- Symbol[] enterParams(Tree[] params) {
- for (int i = 0; i < params.length; i++) {
- enterSym(params[i]);
- switch (params[i]) {
- case ValDef(int mods, _, _, _):
- if ((mods & REPEATED) != 0 && params.length > 1)
- error(params[i].pos,
- "`*' parameter must be the only parameter of a `('...`)' section");
- }
- }
- return Tree.symbolOf(params);
- }
-
- Symbol[][] enterParams(Tree[][] vparams) {
- Symbol[][] vparamSyms = new Symbol[vparams.length][];
- for (int i = 0; i < vparams.length; i++) {
- vparamSyms[i] = enterParams(vparams[i]);
- }
- return vparamSyms;
- }
-
Type makeMethodType(Symbol[] tparams, Symbol[][] vparams, Type restpe) {
if (tparams.length == 0 && vparams.length == 0) {
return Type.PolyType(tparams, restpe);
@@ -1174,7 +1065,6 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
}
}
-
Tree makeStableId(int pos, Type tp) {
if (tp.symbol().isCompoundSym())
return make.This(pos, Tree.Empty).setType(tp);
@@ -1182,21 +1072,6 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
return gen.mkStableId(pos, tp);
}
- /** Re-enter type parameters in current scope.
- */
- void reenterParams(Tree[] params) {
- for (int i = 0; i < params.length; i++) {
- context.scope.enter(params[i].symbol());
- }
- }
-
- /** Re-enter value parameters in current scope.
- */
- void reenterParams(Tree[][] vparams) {
- for (int i = 0; i < vparams.length; i++)
- reenterParams(vparams[i]);
- }
-
/** Define self type of class or module `sym'
* associated with `tree' using given `unit' and `context'.
*/
@@ -1214,6 +1089,147 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
// Attribution and Transform -------------------------------------------------
+ /** Adapt tree to given mode and given prototype
+ */
+ Tree adapt(Tree tree, int mode, Type pt) {
+ //new TextTreePrinter().Print(tree).print(" adapt " + pt).println().end();//DEBUG
+ switch (tree.type) {
+ case OverloadedType(Symbol[] alts, Type[] alttypes):
+ // resolve overloading
+ if ((mode & FUNmode) == 0) {
+ try {
+ infer.exprAlternative(tree, alts, alttypes, pt);
+ } catch (Type.Error ex) {
+ error(tree.pos, ex.msg);
+ }
+ switch (tree.type) {
+ case OverloadedType(_, _):
+ // overload resolution failed bcs no alternative matched prototype.
+ typeError(tree.pos, tree.type, pt);
+ tree.setSymbol(Symbol.ERROR).setType(Type.ErrorType);
+ break;
+ default:
+ return adapt(tree, mode, pt);
+ }
+ }
+ break;
+
+ case PolyType(Symbol[] tparams, Type restp):
+ // apply parameterless functions
+ // instantiate polymorphic expressions
+ if (tparams.length == 0) {
+ return adapt(tree.setType(restp), mode, pt);
+ } else if ((mode & (FUNmode | POLYmode)) == 0) {
+ try {
+ tree = infer.exprInstance(tree, tparams, restp, pt);
+ } catch (Type.Error ex) {
+ tree = error(tree.pos, ex.msg);
+ }
+ return adapt(tree, mode, pt);
+ }
+ break;
+
+ case MethodType(_, _):
+ // convert unapplied methods to functions.
+ if ((mode & (EXPRmode | FUNmode)) == EXPRmode &&
+ infer.isCompatible(tree.type, pt)) {
+ checkEtaExpandable(tree.pos, tree.type);
+ return transform(desugarize.etaExpand(tree, tree.type), mode, pt);
+ } else if ((mode & (CONSTRmode | FUNmode)) == CONSTRmode) {
+ return error(tree.pos, "missing arguments for class constructor");
+ }
+ }
+ if ((mode & PATTERNmode) != 0) {
+ if (tree.isType()) {
+ Symbol clazz = tree.type.unalias().symbol();
+ if (clazz.isCaseClass()) {
+ // set type to instantiated case class constructor
+ tree.type = clazz.constructor().type();
+ switch (tree.type) {
+ case PolyType(Symbol[] tparams, Type restp):
+ try {
+ infer.constructorInstance(tree, tparams, restp, pt);
+ } catch (Type.Error ex) {
+ if (pt != Type.ErrorType) error(tree.pos, ex.msg);
+ return tree.setType(Type.ErrorType);
+ }
+/*
+ if (!(tree.type instanceof Type.MethodType))
+ tree = make.Apply(tree.pos, tree, Tree.EMPTY_ARRAY)
+ .setType(tree.type);
+*/
+ }
+ } else if (clazz.isSubClass(definitions.SEQ_CLASS)) {
+ // set type to instantiated sequence class constructor
+ // todo: should we admit even supertypes of the target type?
+ Type seqtp = pt.baseType(clazz);
+ if (seqtp != Type.NoType) {
+ tree.type = seqConstructorType(seqtp, pt);
+ } else {
+ error(tree.pos, "expected pattern type " + pt +
+ " does not conform to sequence " + clazz);
+ }
+ } else if (tree.type != Type.ErrorType) {
+ error(tree.pos, tree.type.symbol() +
+ " is neither a case class constructor nor a sequence class constructor");
+ }
+ }
+ if ((mode & FUNmode) != 0) {
+ return tree;
+ } else {
+ Symbol sym = tree.symbol();
+ // check that idents or selects are stable.
+ switch (tree) {
+ case Ident(_):
+ case Select(_, _):
+ checkStable(tree);
+ }
+ }
+ } else if ((mode & EXPRmode) != 0) {
+ if ((mode & FUNmode) != 0) {
+ if (tree.type.isObjectType()) {
+ // insert apply method
+ Symbol applyMeth = tree.type.lookup(Names.apply);
+ if (applyMeth != Symbol.NONE && isAccessible(applyMeth, tree)) {
+ applyMeth.flags |= (ACCESSED | SELECTOR);
+ tree = make.Select(tree.pos, tree, Names.apply)
+ .setSymbol(applyMeth)
+ .setType(tree.type.memberType(applyMeth));
+ return adapt(tree, mode, pt);
+ }
+ }
+ } else if ((mode & QUALmode) == 0) {
+ // check that packages and static modules are not used as values
+ Symbol sym = tree.symbol();
+ if (tree.isTerm() &&
+ sym != null && sym.kind != ERROR && !sym.isValue()) {
+ error(tree.pos, tree.symbol() + " is not a value");
+ }
+ }
+ }
+
+ Type owntype = tree.type;
+ 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 instanceof Type.PolyType || owntype.isSubType(pt))) {
+ typeError(tree.pos, owntype, pt);
+ Type.explainTypes(owntype, pt);
+ tree.type = Type.ErrorType;
+ }
+ return tree;
+ }
+ //where
+ Type seqConstructorType(Type paramtp, Type resulttp) {
+ Symbol constr = resulttp.symbol().constructor();
+ Symbol param = new TermSymbol(
+ Position.NOPOS, Names.WILDCARD, constr, PARAM | REPEATED).setInfo(
+ paramtp.baseType(definitions.SEQ_CLASS));
+ return Type.MethodType(new Symbol[]{param}, resulttp);
+ }
+
/** 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.
@@ -1354,14 +1370,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
sym.isStable() && qual.type.isStable())
symtype = Type.singleType(qual.type, sym);
//System.out.println(qual.type + ".member: " + sym + ":" + symtype);//DEBUG
- switch (tree) {
- case Select(_, _):
- return copy.Select(tree, sym, qual).setType(symtype);
- case SelectFromType(_, _):
- return make.TypeTerm(tree.pos).setType(symtype);
- default:
- throw new ApplicationError();
- }
+ return copy.Select(tree, sym, qual).setType(symtype);
}
}
@@ -1412,7 +1421,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
}
Tree stat1;
int mode = TreeInfo.isDefinition(stat) ? NOmode : EXPRmode;
- if (exprOwner.kind != NONE && !TreeInfo.isOwnerDefinition(stat)) {
+ if (exprOwner.kind != NONE && !TreeInfo.isDefinition(stat)) {
pushContext(stat, exprOwner, context.scope);
stat1 = transform(stat, mode);
popContext();
@@ -1432,47 +1441,56 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
/** Attribute a sequence of constructor invocations.
*/
- Tree[] transformConstrInvocations(int pos, Tree[] constrs, boolean delayArgs) {
+ Tree[] transformConstrInvocations(int pos, Tree[] constrs) {
for (int i = 0; i < constrs.length; i++) {
- pushContext(constrs[i], context.owner, context.scope);
- context.delayArgs = delayArgs;
- constrs[i] = transform(constrs[i], CONSTRmode, Type.AnyType);
+ //!!!pushContext(constrs[i], context.owner, context.scope);
+ constrs[i] = transform(constrs[i], CONSTRmode | SUPERmode, Type.AnyType);
Symbol f = TreeInfo.methSymbol(constrs[i]);
if (f != null) {
Symbol c = f.primaryConstructorClass();
if (c.kind == CLASS) c.initialize();//to detect cycles
}
- popContext();
+ //!!!popContext();
}
return constrs;
}
+ void transformConstrInvocationArgs(Tree[] constrs) {
+ for (int i = 0; i < constrs.length; i++) {
+ switch (constrs[i]) {
+ case Apply(Tree fn, Tree[] args):
+ if (fn.type instanceof Type.MethodType)
+ transformArgs(
+ constrs[i].pos, TreeInfo.methSymbol(fn), Symbol.EMPTY_ARRAY,
+ fn.type, EXPRmode, args, Type.AnyType);
+ }
+ }
+ }
+
/** Attribute a template
*/
public Tree.Template transformTemplate(Tree.Template templ, Symbol owner) {
if (global.debug) global.log("transforming " + owner);//debug
//System.out.println(owner.info());//DEBUG
- Tree[] parents1 = transformConstrInvocations(
- templ.pos, templ.parents, false);
+ Tree[] parents = templ.parents;
+ transformConstrInvocationArgs(parents);
if (owner.kind != ERROR) {
- validateParentClasses(
- templ.parents, owner.info().parents(), owner.typeOfThis());
+ validateParentClasses(parents, owner.info().parents(), owner.typeOfThis());
validateBaseTypes(owner);
}
pushContext(templ, owner, owner.members());
templ.setSymbol(gen.localDummy(templ.pos, owner));
Tree[] body1 = transformStatSeq(templ.body, templ.symbol());
- checkAllOverrides(owner);
popContext();
if (owner.isTrait()) {
- for (int i = 0; i < templ.parents.length; i++) {
- checkPureConstr(parents1[i], owner);
- if (i >= 1) checkTrait(parents1[i], owner);
+ for (int i = 0; i < parents.length; i++) {
+ checkPureConstr(parents[i], owner);
+ if (i >= 1) checkTrait(parents[i], owner);
}
for (int i = 0; i < templ.body.length; i++)
checkPureDef(body1[i], owner);
}
- Tree.Template templ1 = copy.Template(templ, parents1, body1);
+ Tree.Template templ1 = copy.Template(templ, parents, body1);
templ1.setType(owner.type());
return templ1;
}
@@ -1582,142 +1600,6 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
return tree1;
}
- Tree adapt(Tree tree, int mode, Type pt) {
- //new TextTreePrinter().print(tree).print(" adapt " + pt).println().end();//DEBUG
- switch (tree.type) {
- case OverloadedType(Symbol[] alts, Type[] alttypes):
- // resolve overloading
- if ((mode & FUNmode) == 0) {
- try {
- infer.exprAlternative(tree, alts, alttypes, pt);
- } catch (Type.Error ex) {
- error(tree.pos, ex.msg);
- }
- switch (tree.type) {
- case OverloadedType(_, _):
- // overload resolution failed bcs no alternative matched prototype.
- typeError(tree.pos, tree.type, pt);
- tree.setSymbol(Symbol.ERROR).setType(Type.ErrorType);
- break;
- default:
- return adapt(tree, mode, pt);
- }
- }
- break;
-
- case PolyType(Symbol[] tparams, Type restp):
- // apply parameterless functions
- // instantiate polymorphic expressions
- if (tparams.length == 0) {
- return adapt(tree.setType(restp), mode, pt);
- } else if ((mode & (FUNmode | POLYmode)) == 0) {
- try {
- tree = infer.exprInstance(tree, tparams, restp, pt);
- } catch (Type.Error ex) {
- tree = error(tree.pos, ex.msg);
- }
- return adapt(tree, mode, pt);
- }
- break;
-
- case MethodType(_, _):
- // convert unapplied methods to functions.
- if ((mode & (EXPRmode | FUNmode)) == EXPRmode &&
- infer.isCompatible(tree.type, pt)) {
- checkEtaExpandable(tree.pos, tree.type);
- return transform(desugarize.etaExpand(tree, tree.type), mode, pt);
- } else if ((mode & (CONSTRmode | FUNmode)) == CONSTRmode) {
- return error(tree.pos, "missing arguments for class constructor");
- }
- }
- if ((mode & PATTERNmode) != 0) {
- if (tree.isType()) {
- Symbol clazz = tree.type.unalias().symbol();
- if (clazz.isCaseClass()) {
- // set type to instantiated case class constructor
- tree.type = clazz.constructor().type();
- switch (tree.type) {
- case PolyType(Symbol[] tparams, Type restp):
- try {
- infer.constructorInstance(tree, tparams, restp, pt);
- } catch (Type.Error ex) {
- if (pt != Type.ErrorType) error(tree.pos, ex.msg);
- return tree.setType(Type.ErrorType);
- }
-/*
- if (!(tree.type instanceof Type.MethodType))
- tree = make.Apply(tree.pos, tree, Tree.EMPTY_ARRAY)
- .setType(tree.type);
-*/
- }
- } else if (clazz.isSubClass(definitions.SEQ_CLASS)) {
- // set type to instantiated sequence class constructor
- // todo: should we admit even supertypes of the target type?
- Type seqtp = pt.baseType(clazz);
- if (seqtp != Type.NoType) {
- tree.type = seqConstructorType(seqtp, pt);
- } else {
- error(tree.pos, "expected pattern type " + pt +
- " does not conform to sequence " + clazz);
- }
- } else if (tree.type != Type.ErrorType) {
- error(tree.pos, tree.type.symbol() +
- " is neither a case class constructor nor a sequence class constructor");
- }
- }
- if ((mode & FUNmode) != 0) {
- return tree;
- } else {
- Symbol sym = tree.symbol();
- // check that idents or selects are stable.
- switch (tree) {
- case Ident(_):
- case Select(_, _):
- checkStable(tree);
- }
- }
- } else if ((mode & EXPRmode) != 0) {
- if ((mode & FUNmode) != 0) {
- if (tree.type.isObjectType()) {
- // insert apply method
- Symbol applyMeth = tree.type.lookup(Names.apply);
- if (applyMeth != Symbol.NONE && isAccessible(applyMeth, tree)) {
- applyMeth.flags |= (ACCESSED | SELECTOR);
- tree = make.Select(tree.pos, tree, Names.apply)
- .setSymbol(applyMeth)
- .setType(tree.type.memberType(applyMeth));
- return adapt(tree, mode, pt);
- }
- }
- } else if ((mode & QUALmode) == 0) {
- // check that packages and static modules are not used as values
- Symbol sym = tree.symbol();
- if (sym != null && sym.kind != ERROR && !sym.isValue() &&
- tree.isTerm()) {
- error(tree.pos, tree.symbol() + " is not a value");
- }
- }
- }
-
- Type owntype = tree.type;
- if ((mode & (CONSTRmode | FUNmode)) == (CONSTRmode))
- owntype = owntype.instanceType();
- if (!(owntype instanceof Type.PolyType || owntype.isSubType(pt))) {
- typeError(tree.pos, owntype, pt);
- explainTypes(owntype, pt);
- tree.type = Type.ErrorType;
- }
- return tree;
- }
- //where
- Type seqConstructorType(Type paramtp, Type resulttp) {
- Symbol constr = resulttp.symbol().constructor();
- Symbol param = new TermSymbol(
- Position.NOPOS, Names.WILDCARD, constr, PARAM | REPEATED).setInfo(
- paramtp);
- return Type.MethodType(new Symbol[]{param}, resulttp);
- }
-
/** Transform expression or type with a given mode.
*/
public Tree transform(Tree tree, int mode) {
@@ -1730,6 +1612,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
this.mode = savedMode;
if ((mode & TYPEmode) != 0) {
+ // todo: generalize to type constructors?
Symbol sym = tree1.symbol();
if ((mode & FUNmode) == 0 && sym != null && sym.typeParams().length != 0)
return error(tree.pos, sym + " takes type parameters.");
@@ -1748,7 +1631,11 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
/** The main attribution function
*/
public Tree transform(Tree tree) {
- //new TextTreePrinter().print("transforming ").print(tree).println().end();//DEBUG
+ //System.out.println("transforming " + tree);//DEBUG
+ if (tree.type != null) {
+ checkDefined.all = tree; checkDefined.traverse(tree);//debug
+ return tree;
+ }
Symbol sym = tree.symbol();
if (sym != null && !sym.isInitialized()) sym.initialize();
if (global.debug && TreeInfo.isDefinition(tree)) global.log("transforming " + sym);
@@ -1787,38 +1674,22 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
Tree tpe1 = transform(tpe);
Tree.Template templ1 = transformTemplate(templ, sym);
popContext();
- validateVariance(sym, sym.info(), CoVariance);
- validateVariance(sym, sym.typeOfThis(), CoVariance);
return copy.ClassDef(tree, sym, tparams1, vparams1, tpe1, templ1)
.setType(definitions.UNIT_TYPE);
case ModuleDef(_, _, Tree tpe, Tree.Template templ):
- Tree tpe1 = transform(tpe, TYPEmode);
Tree.Template templ1 = transformTemplate(templ, sym.moduleClass());
- validateVariance(sym.moduleClass(), sym.type(), CoVariance);
- validateVariance(sym.moduleClass(), sym.moduleClass().info(), CoVariance);
- return copy.ModuleDef(tree, sym, tpe1, templ1)
+ return copy.ModuleDef(tree, sym, tpe, templ1)
.setType(definitions.UNIT_TYPE);
case ValDef(_, _, Tree tpe, Tree rhs):
- Tree tpe1 = transform(tpe, TYPEmode);
Tree rhs1 = rhs;
- if (tpe1 == Tree.Empty) {
- tpe1 = gen.mkType(rhs.pos, rhs.type);
- // rhs already attributed by defineSym in this case
- } else if (rhs != Tree.Empty) {
- if ((sym.flags & CASEACCESSOR) != 0) {
- //rhs was already attributed
- } else {
- pushContext(tree, sym, context.scope);
- rhs1 = transform(rhs, EXPRmode, sym.type());
- popContext();
- }
+ if (rhs != Tree.Empty) {
+ pushContext(tree, sym, context.scope);
+ rhs1 = transform(rhs, EXPRmode, tpe.type);
+ popContext();
}
- validateVariance(
- sym, sym.type(),
- ((sym.flags & MUTABLE) != 0) ? NoVariance : CoVariance);
- return copy.ValDef(tree, sym, tpe1, rhs1)
+ return copy.ValDef(tree, sym, tpe, rhs1)
.setType(definitions.UNIT_TYPE);
case DefDef(_, _, Tree.TypeDef[] tparams, Tree.ValDef[][] vparams, Tree tpe, Tree rhs):
@@ -1827,34 +1698,15 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
Tree.TypeDef[] tparams1 = transform(tparams);
reenterParams(vparams);
Tree.ValDef[][] vparams1 = transform(vparams);
- Tree tpe1 = transform(tpe, TYPEmode);
Tree rhs1 = rhs;
- if (tpe1 == Tree.Empty) {
- tpe1 = gen.mkType(rhs1.pos, rhs1.type);
- //System.out.println("infer " + sym + ":" + rhs.type);//DEBUG
- //rhs already attributed by defineSym in this case
- } else if (rhs != Tree.Empty) {
- rhs1 = transform(rhs, EXPRmode,
- tpe1.type == Type.NoType ? Type.AnyType : tpe1.type);
- }
+ if (rhs != Tree.Empty)
+ rhs1 = transform(rhs, EXPRmode, tpe.type);
popContext();
- validateVariance(sym, sym.type(), CoVariance);
- return copy.DefDef(tree, sym, tparams1, vparams1, tpe1, rhs1)
+ return copy.DefDef(tree, sym, tparams1, vparams1, tpe, rhs1)
.setType(definitions.UNIT_TYPE);
- case TypeDef(_, _, Tree rhs, Tree lobound):
- pushContext(tree, sym, new Scope(context.scope));
- int mode = TYPEmode;
- int variance = CoVariance;
- if (sym.kind == ALIAS) {
- mode |= FUNmode;
- variance = NoVariance;
- }
- Tree rhs1 = transform(rhs, mode);
- Tree lobound1 = transform(lobound, TYPEmode);
- popContext();
- validateVariance(sym, sym.info(), variance);
- return copy.TypeDef(tree, sym, rhs1, lobound1)
+ case TypeDef(_, _, _, _):
+ return tree
.setType(definitions.UNIT_TYPE);
case Import(Tree expr, Name[] selectors):
@@ -1869,29 +1721,33 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
context.imports = context.outer.imports;
for (int i = 0; i < stats1.length - 1; i++)
stats1[i] = transform(stats1[i], EXPRmode);
- Type tp;
+ Type owntype;
if (stats1.length > 0) {
stats1[stats1.length - 1] =
transform(stats1[stats1.length - 1], lastmode, pt);
- tp = checkNoEscape(tree.pos, stats1[stats1.length - 1].type);
+ owntype = checkNoEscape(tree.pos, stats1[stats1.length - 1].type);
} else {
- tp = definitions.UNIT_TYPE;
+ owntype = definitions.UNIT_TYPE;
}
popContext();
return copy.Block(tree, stats1)
- .setType(tp);
+ .setType(owntype);
case Visitor(Tree.CaseDef[] cases):
if (pt.symbol().isSubClass(definitions.PARTIALFUNCTION_CLASS)) {
Type pft = pt.baseType(definitions.PARTIALFUNCTION_CLASS);
Type[] pftargs = pft.typeArgs();
- if (pft.typeArgs().length == 2 && infer.isFullyDefined(pftargs[0])) {
- Type pattpe = pftargs[0];
- Type restpe = pftargs[1];
- Tree tree1 = transformVisitor(tree, pattpe, restpe);
- if (!infer.isFullyDefined(restpe)) restpe = tree1.type;
- return transform(
- desugarize.partialFunction(tree, pattpe, restpe));
+ if (pftargs.length == 2 && infer.isFullyDefined(pftargs[0])) {
+ Type pattype = pftargs[0];
+ Type restype = pftargs[1];
+ Tree isDefinedAtVisitor = transformVisitor(
+ desugarize.isDefinedAtVisitor(tree),
+ pattype, definitions.BOOLEAN_TYPE);
+ Tree applyVisitor = transformVisitor(tree, pattype, restype);
+ if (!infer.isFullyDefined(restype)) restype = applyVisitor.type;
+ return gen.mkPartialFunction(
+ tree.pos, applyVisitor, isDefinedAtVisitor,
+ pattype, restype, context.owner);
} else {
return error(tree.pos, "expected pattern type of cases could not be determined");
}
@@ -1899,7 +1755,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
return transform(desugarize.Visitor(tree));
}
- case Assign(Apply(Tree funarray, Tree[] vparam), Tree rhs):
+ case Assign(Apply(_, _), _):
return transform(desugarize.Update(tree));
case Assign(Tree lhs, Tree rhs):
@@ -1917,29 +1773,27 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
case If(Tree cond, Tree thenp, Tree elsep):
Tree cond1 = transform(cond, EXPRmode, definitions.BOOLEAN_TYPE);
+ Tree thenp1, elsep1;
if (elsep == Tree.Empty) {
- Tree thenp1 =
- transform(thenp, EXPRmode, definitions.UNIT_TYPE);
- Tree elsep1 = make.Block(tree.pos, Tree.EMPTY_ARRAY)
- .setType(definitions.UNIT_TYPE);
- return copy.If(tree, cond1, thenp1, elsep1)
+ thenp1 = transform(thenp, EXPRmode, definitions.UNIT_TYPE);
+ elsep1 = make.Block(tree.pos, Tree.EMPTY_ARRAY)
.setType(definitions.UNIT_TYPE);
} else {
- Tree thenp1 = transform(thenp, EXPRmode, pt);
- Tree elsep1 = transform(elsep, EXPRmode, pt);
- return copy.If(tree, cond1, thenp1, elsep1)
- .setType(Type.lub(new Type[]{thenp1.type, elsep1.type}));
+ thenp1 = transform(thenp, EXPRmode, pt);
+ elsep1 = transform(elsep, EXPRmode, pt);
}
+ return copy.If(tree, cond1, thenp1, elsep1)
+ .setType(Type.lub(new Type[]{thenp1.type, elsep1.type}));
case New(Tree.Template templ):
switch (templ) {
case Template(Tree[] parents, Tree[] body):
if (parents.length == 1 && body.length == 0) {
Tree parent1 = transform(parents[0], CONSTRmode, pt);
+ Type owntype = parent1.type;
Tree.Template templ1 = (Tree.Template)
copy.Template(templ, Symbol.NONE, new Tree[]{parent1}, body)
- .setType(parent1.type);
- Type owntype = parent1.type;
+ .setType(owntype);
checkInstantiatable(tree.pos, owntype);
return copy.New(tree, templ1)
.setType(owntype.instanceType());
@@ -1963,7 +1817,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
Type[] parentTypes = clazz.info().parents();
Scope refinement = new Scope();
Type base = Type.compoundType(parentTypes, Scope.EMPTY);
- Type tp = Type.compoundType(
+ Type owntype = Type.compoundType(
parentTypes, refinement, clazz);
Scope.SymbolIterator it = clazz.members().iterator();
while (it.hasNext()) {
@@ -1976,21 +1830,19 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
}
if (refinement.elems == Scope.Entry.NONE &&
parentTypes.length == 1)
- tp = parentTypes[0];
+ owntype = parentTypes[0];
else
- tp = checkNoEscape(tree.pos, tp);
-
- Tree alloc =
- gen.Typed(
- gen.New(
- gen.Apply(
- gen.mkRef(tree.pos,
- Type.localThisType, clazz.constructor()),
- Tree.EMPTY_ARRAY)),
- tp);
+ owntype = checkNoEscape(tree.pos, owntype);
+
+ Tree alloc = gen.New(
+ gen.Apply(
+ gen.mkRef(tree.pos,
+ Type.localThisType, clazz.constructor()),
+ Tree.EMPTY_ARRAY))
+ .setType(owntype);
popContext();
return make.Block(tree.pos, new Tree[]{cd, alloc})
- .setType(tp);
+ .setType(owntype);
}
default:
throw new ApplicationError();
@@ -1999,18 +1851,18 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
case Typed(Tree expr, Tree tpe):
Tree tpe1 = transform(tpe, TYPEmode);
Tree expr1 = transform(expr, mode & baseModes, tpe1.type);
- return copy.Typed(tree, expr1, tpe1)
- .setType(tpe1.type);
+ return copy.Typed(tree, expr1, tpe1).setType(tpe1.type);
case Function(Tree.ValDef[] vparams, Tree body):
pushContext(tree, context.owner, new Scope(context.scope));
Type restype = desugarize.preFunction(vparams, pt);
enterParams(vparams);
+ Tree.ValDef[] vparams1 = transform(vparams);
Tree body1 = transform(body, EXPRmode, restype);
if (!infer.isFullyDefined(restype)) restype = body1.type;
popContext();
- Tree tree1 = copy.Function(tree, vparams, body1);
- return transform(desugarize.Function(tree1, restype));
+ return gen.mkFunction(
+ tree.pos, vparams1, body1, restype, context.owner);
case TypeApply(Tree fn, Tree[] args):
Tree fn1 = transform(fn, EXPRmode | FUNmode, Type.AnyType);
@@ -2030,20 +1882,9 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
// match against arguments
switch (fn1.type) {
case PolyType(Symbol[] tparams, Type restp):
- if (tparams.length == argtypes.length) {
- int i = 0;
- while (i < tparams.length &&
- (context.delayArgs ||
- (argtypes[i].isSubType(
- tparams[i].info().subst(tparams, argtypes)) &&
- tparams[i].loBound().subst(tparams, argtypes)
- .isSubType(argtypes[i]))))
- i++;
- if (i == tparams.length) {
- return copy.TypeApply(tree, fn1, args1)
- .setType(restp.subst(tparams, argtypes));
- }
- }
+ if (tparams.length == argtypes.length)
+ return copy.TypeApply(tree, fn1, args1)
+ .setType(restp.subst(tparams, argtypes));
break;
case ErrorType:
return tree.setType(Type.ErrorType);
@@ -2110,14 +1951,10 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
}
}
- // return prematurely if delayArgs is true and no type arguments
- // need to be inferred.
- if (context.delayArgs) {
- switch (fn1.type) {
- case MethodType(_, Type restp):
- return copy.Apply(tree, fn1, args).setType(restp);
- }
- }
+ // return prematurely if function is a superclass constructor
+ // and no type arguments need to be inferred.
+ if ((mode & SUPERmode) != 0 && fn1.type instanceof Type.MethodType)
+ return copy.Apply(tree, fn1, args).setType(fn1.type.resultType());
// type arguments with formals as prototypes if they exist.
fn1.type = infer.freshInstance(fn1.type);
@@ -2150,6 +1987,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
// infer instance, and adapt arguments to instantiated formals
try {
fn1 = infer.methodInstance(fn1, tparams, restp, argtypes, pt);
+ //System.out.println(fn1 + ":" + fn1.type);//DEBUG
} catch (Type.Error ex) {
error(tree.pos, ex.msg);
}
@@ -2258,7 +2096,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
case SingletonType(Tree ref):
Tree ref1 = transform(ref, EXPRmode | QUALmode, Type.AnyType);
- return make.TypeTerm(tree.pos)
+ return copy.SingletonType(tree, ref1)
.setType(checkObjectType(tree.pos, ref1.type.resultType()));
case SelectFromType(Tree qual, Name name):
@@ -2277,9 +2115,8 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
enterSym(refinements[i]).flags |= OVERRIDE;
}
Tree[] refinements1 = transformStatSeq(refinements, Symbol.NONE);
- checkAllOverrides(clazz);
popContext();
- return make.TypeTerm(tree.pos)
+ return copy.CompoundType(tree, parents1, refinements1)
.setType(self);
case AppliedType(Tree tpe, Tree[] args):
@@ -2293,25 +2130,14 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
: Symbol.EMPTY_ARRAY;
Type owntype = Type.ErrorType;
if (tpe1.type != Type.ErrorType) {
- if (tparams.length == args.length) {
- try {
- if (!context.delayArgs)
- infer.checkBounds(tparams, argtypes, "");
- owntype = Type.appliedType(tpe1.type, argtypes);
- } catch (Type.Error ex) {
- error(tree.pos, ex.msg);
- }
- } else {
- if (tparams.length == 0)
- error(tree.pos, tpe1.type +
- " does not take type parameters");
- else
- error(tree.pos,
- "wrong number of type arguments for " +
- tpe1.type);
- }
+ if (tparams.length == args.length)
+ owntype = Type.appliedType(tpe1.type, argtypes);
+ else if (tparams.length == 0)
+ error(tree.pos, tpe1.type + " does not take type parameters");
+ else error(tree.pos, "wrong number of type arguments for " +
+ tpe1.type);
}
- return make.TypeTerm(tree.pos).setType(owntype);
+ return copy.AppliedType(tree, tpe1, args1).setType(owntype);
case FunType(_, _):
return transform(desugarize.FunType(tree));
@@ -2326,83 +2152,5 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
return tree;
}
}
-
-// Contexts -------------------------------------------------------------------
-
- /** Push new context associated with given tree, owner, and scope on stack.
- * Fields `imports' and, possibly, `enclClass' are inherited from parent.
- */
- void pushContext(Tree tree, Symbol owner, Scope scope) {
- context = new Context(tree, owner, scope, context);
- }
-
- /** Pop context from stack.
- */
- void popContext() {
- context = context.outer;
- }
-
-// Lazy Types ------------------------------------------------------------------
-
- /** A lazy type which, when forced returns the type of a symbol defined
- * in `tree'.
- */
- class LazyTreeType extends Type.LazyType {
- Tree tree;
- Unit u;
- Context c;
-
- LazyTreeType(Tree tree) {
- this.tree = tree;
- this.u = unit;
- this.c = context;
- }
- public void complete(Symbol sym) {
- //System.out.println("completing " + sym);//DEBUG
- //if (sym.isConstructor()) sym.constructorClass().initialize();
- //else if (sym.isModule()) sym.moduleClass().initialize();
- 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 extends LazyTreeType {
- LazyConstrMethodType(Tree tree) {
- super(tree);
- }
- public void complete(Symbol sym) {
- Type constrtype = tree.symbol().constructor().type().instanceType();
- switch (tree) {
- case ClassDef(_, _, _, ValDef[][] vparams, _, _):
- if (vparams.length == 0) {
- constrtype = removeMethod(constrtype);
- }
- }
- sym.setInfo(constrtype);
- }
- private Type removeMethod(Type tp) {
- switch (tp) {
- case MethodType(_, Type restp):
- return restp;
- case PolyType(Symbol[] tparams, Type restp):
- return Type.PolyType(tparams, removeMethod(restp));
- default:
- return tp;
- }
- }
- }
-
- /** A lazy type for self types
- */
- class LazySelfType extends LazyTreeType {
- LazySelfType(Tree tree) {
- super(tree);
- }
- public void complete(Symbol sym) {
- defineSelfType(sym, tree, u, c);
- }
- }
}
diff --git a/sources/scalac/typechecker/Context.java b/sources/scalac/typechecker/Context.java
index 5c01e9d73e..090f0e58fb 100644
--- a/sources/scalac/typechecker/Context.java
+++ b/sources/scalac/typechecker/Context.java
@@ -20,7 +20,6 @@ public class Context {
Context enclClass = this; // The next outer context whose tree
// is a class template
int variance; // Variance relative to eclosing class.
- boolean delayArgs = false; // delay checking of type arguments
public Context() {}
@@ -37,7 +36,6 @@ public class Context {
tree instanceof Tree.CompoundType) this.enclClass = this;
else this.enclClass = outer.enclClass;
this.variance = outer.variance;
- this.delayArgs = outer.delayArgs;
this.outer = outer;
}
diff --git a/sources/scalac/typechecker/DeSugarize.java b/sources/scalac/typechecker/DeSugarize.java
index e5f2b2095d..89f82cec0d 100644
--- a/sources/scalac/typechecker/DeSugarize.java
+++ b/sources/scalac/typechecker/DeSugarize.java
@@ -163,7 +163,7 @@ public class DeSugarize implements Kinds, Modifiers {
}
/** (x_1: T_1, ..., x_n: T_N) => e ==>
- * new new scala.Object() with scala.Function[T_1, ..., T_N, T]() {
+ * new scala.Object() with scala.Function[T_1, ..., T_N, T]() {
* def apply(x_1: T_1, ..., x_N: T_N): T = e
* def toString(): java.lang.String = "<function>"
* }
@@ -232,7 +232,6 @@ public class DeSugarize implements Kinds, Modifiers {
* Cases' = case P1 if G1 => True, ..., Pn if Gn => True, _ => False
* Argtpe = targs[0]
* Restpe = targs[1]
- */
public Tree partialFunction(Tree tree, Type pattpe, Type restpe) {
Tree constr =
make.Apply(
@@ -271,8 +270,9 @@ public class DeSugarize implements Kinds, Modifiers {
print(tree, "partialfun", result);
return result;
}
+ */
- private Tree isDefinedAtVisitor(Tree tree) {
+ Tree isDefinedAtVisitor(Tree tree) {
switch (tree) {
case Visitor(CaseDef[] cases):
CaseDef lastCase = cases[cases.length - 1];
@@ -310,7 +310,7 @@ public class DeSugarize implements Kinds, Modifiers {
/** match => this.match
* match[targs] => this.match[targs]
- * tree is already attributed and attributes need to be preserved.
+ * IMPORTANT: tree is already attributed and attributes need to be preserved.
*/
Tree postMatch(Tree tree, Symbol currentclazz) {
switch (tree) {
@@ -507,7 +507,7 @@ public class DeSugarize implements Kinds, Modifiers {
Name valname = Name.fromString(name + "$");
Tree valdef1 = copy.ValDef(
tree, (mods & (DEFERRED | MUTABLE | CASEACCESSOR | MODUL)) | PRIVATE,
- valname, tpe, rhs);
+ valname, tpe, rhs).setType(null);
int mods1 = mods | ACCESSOR;
if ((mods1 & MUTABLE) == 0) mods1 |= STABLE;
Tree getter = make.DefDef(
@@ -540,33 +540,6 @@ public class DeSugarize implements Kinds, Modifiers {
}
}
- /** Tree represents an application of a constructor method of a case class
- * (whose name is a term name). Convert this tree to application of
- * the case classe's primary constructor `constr'.
- */
- public Tree toConstructor(Tree tree, Symbol constr) {
- switch (tree) {
- case Apply(Tree fn, Tree[] args):
- return toConstructor1(tree, constr);
- default:
- return make.Apply(tree.pos, toConstructor1(tree, constr), Tree.EMPTY_ARRAY);
- }
- }
- private Tree toConstructor1(Tree tree, Symbol constr) {
- switch (tree) {
- case Apply(Tree fn, Tree[] args):
- return copy.Apply(tree, toConstructor1(fn, constr), args);
- case TypeApply(Tree fn, Tree[] args):
- return copy.TypeApply(tree, toConstructor1(fn, constr), args);
- case Ident(Name name):
- return copy.Ident(tree, constr.name).setSymbol(constr);
- case Select(Tree qual, Name name):
- return copy.Select(tree, qual, constr.name).setSymbol(constr);
- default:
- throw new ApplicationError();
- }
- }
-
/** Expand partial function applications of type `type'.
*
* p.f(es_1)...(es_n)
@@ -601,13 +574,14 @@ public class DeSugarize implements Kinds, Modifiers {
return tree;
case Select(Tree qual, _):
- return copy.Select(tree, liftout(qual, defs));
+ return copy.Select(tree, liftout(qual, defs)).setType(null);
case TypeApply(Tree fn, Tree[] args):
- return copy.TypeApply(tree, liftoutPrefix(fn, defs), args);
+ return copy.TypeApply(tree, liftoutPrefix(fn, defs), args).setType(null);
case Apply(Tree fn, Tree[] args):
- return copy.Apply(tree, liftoutPrefix(fn, defs), liftout(args, defs));
+ return copy.Apply(tree, liftoutPrefix(fn, defs), liftout(args, defs))
+ .setType(null);
default:
throw new ApplicationError();
diff --git a/sources/scalac/typechecker/Infer.java b/sources/scalac/typechecker/Infer.java
index a212e26e77..9852e2d1f1 100644
--- a/sources/scalac/typechecker/Infer.java
+++ b/sources/scalac/typechecker/Infer.java
@@ -241,9 +241,32 @@ public class Infer implements Modifiers, Kinds {
*/
private boolean isWithinBounds(Symbol[] tparams, Type[] targs) {
for (int i = 0; i < targs.length; i++) {
- if (!targs[i].isSubType(tparams[i].info().subst(tparams, targs)) ||
- !tparams[i].loBound().subst(tparams, targs).isSubType(targs[i]))
+ Type hibound = tparams[i].info().subst(tparams, targs);
+ if (!targs[i].isSubType(hibound)) {
+ for (int j = 0; j < tparams.length; j++) {
+ if (hibound.symbol() == tparams[j])
+ return isWithinBounds(
+ tparams,
+ Type.subst(
+ targs,
+ new Symbol[]{tparams[j]},
+ new Type[]{targs[i]}));
+ }
return false;
+ }
+ Type lobound = tparams[i].loBound().subst(tparams, targs);
+ if (!lobound.isSubType(targs[i])) {
+ for (int j = 0; j < tparams.length; j++) {
+ if (lobound.symbol() == tparams[j])
+ return isWithinBounds(
+ tparams,
+ Type.subst(
+ targs,
+ new Symbol[]{tparams[j]},
+ new Type[]{targs[i]}));
+ }
+ return false;
+ }
}
return true;
}
@@ -444,7 +467,7 @@ public class Infer implements Modifiers, Kinds {
private Symbol[] normalizeArgs(Type[] targs, Symbol[] tparams) {
Type.List uninstantiated = Type.List.EMPTY;
for (int i = 0; i < targs.length; i++) {
- if (targs[i] == Global.instance.definitions.ALL_TYPE) {
+ if (targs[i].symbol() == Global.instance.definitions.ALL_CLASS) {
targs[i] = tparams[i].type();
uninstantiated = Type.List.append(uninstantiated, targs[i]);
}
diff --git a/sources/scalac/typechecker/RefCheck.java b/sources/scalac/typechecker/RefCheck.java
index c40341c1d0..3719fe0664 100644
--- a/sources/scalac/typechecker/RefCheck.java
+++ b/sources/scalac/typechecker/RefCheck.java
@@ -16,7 +16,22 @@ import scalac.ast.printer.*;
import scalac.symtab.*;
import Tree.*;
-/** Check that no forward reference to a term symbol extends beyond a value definition.
+/** Post-attribution checking and transformation.
+ *
+ * This phase performs the following checks.
+ *
+ * - All overrides conform to rules.
+ * - All type arguments conform to bounds.
+ * - All type variable uses conform to variance annotations.
+ * - No forward reference to a term symbol extends beyond a value definition.
+ *
+ * It preforms the following transformations.
+ *
+ * - Local modules are replaces by variables and classes
+ * - toString, equals, and hashCode methods are added to case classes, unless
+ * they are defined in the class or a baseclass different from java.lang.Object
+ * - Calls to case factory methods are replaced by new's.
+ * - Type nodes are replaced by TypeTerm nodes.
*/
public class RefCheck extends Transformer implements Modifiers, Kinds {
@@ -25,15 +40,238 @@ public class RefCheck extends Transformer implements Modifiers, Kinds {
}
private Unit unit;
+ private Definitions defs = global.definitions;
+ private Infer infer = new Infer(this);
+
+ public void apply(Unit unit) {
+ this.unit = unit;
+ level = 0;
+ scopes[0] = new Scope();
+ maxindex[0] = Integer.MIN_VALUE;
+ unit.body = transformStats(unit.body);
+ scopes[0] = null;
+ symIndex.clear();
+ }
+
+// Override checking ------------------------------------------------------------
+
+ /** Check all members of class `clazz' for overriding conditions.
+ */
+ void checkAllOverrides(int pos, Symbol clazz) {
+ Type[] closure = clazz.closure();
+ for (int i = 0; i < closure.length; i++) {
+ for (Scope.SymbolIterator it = closure[i].members().iterator();
+ it.hasNext();) {
+ Symbol other = it.next();
+ Symbol member = clazz.info().lookup(other.name);
+ if (other != member && (other.flags & PRIVATE) == 0 &&
+ member.kind != NONE)
+ checkOverride(pos, clazz, member, other);
+ if ((member.flags & DEFERRED) != 0 &&
+ clazz.kind == CLASS &&
+ (clazz.flags & ABSTRACTCLASS) == 0) {
+ if (clazz.isAnonymousClass())
+ unit.error(
+ clazz.pos, "object creation impossible, since " +
+ member + member.locationString() + " is not defined" +
+ (((member.flags & MUTABLE) == 0) ? ""
+ : "\n(Note that variables need to be initialized to be defined)"));
+ else
+ unit.error(clazz.pos,
+ clazz + " needs to be abstract; it does not define " +
+ member + member.locationString() +
+ (((member.flags & MUTABLE) == 0) ? ""
+ : "\n(Note that variables need to be initialized to be defined)"));
+ clazz.flags |= ABSTRACTCLASS;
+ }
+ }
+ }
+ }
+
+ /** Check that all conditions for overriding `other' by `member' are met.
+ */
+ void checkOverride(int pos, Symbol clazz, Symbol member, Symbol other) {
+ if (member.owner() == clazz) pos = member.pos;
+ else if (member.owner().isSubClass(other.owner()))
+ return; // everything was already checked elsewhere
+
+ if ((member.flags & PRIVATE) != 0) {
+ overrideError(pos, member, other, "has weaker access privileges; it should not be private");
+ } else if ((member.flags & PROTECTED) != 0 && (other.flags & PROTECTED) == 0) {
+ overrideError(pos, member, other, "has weaker access privileges; it should not be protected");
+ } else if ((other.flags & FINAL) != 0) {
+ overrideError(pos, member, other, "cannot override final member");
+ } else if ((other.flags & DEFERRED) == 0 && ((member.flags & OVERRIDE) == 0)) {
+ overrideError(pos, member, other, "needs `override' modifier");
+ } else if (other.isStable() && !member.isStable()) {
+ overrideError(pos, member, other, "needs to be an immutable value");
+ } else {
+ Type self = clazz.thisType();
+ switch (other.kind) {
+ case CLASS:
+ overrideError(pos, member, other, "cannot override a class");
+ break;
+ case ALIAS:
+ if (!self.memberType(member).isSameAs(self.memberType(other)))
+ overrideTypeError(pos, member, other, self, false);
+ break;
+ default:
+ if (other.isConstructor())
+ overrideError(pos, member, other,
+ "cannot override a class constructor");
+ Type selftype = normalizedInfo(self, member);
+ Type othertype = normalizedInfo(self, other);
+ if (!selftype.isSubType(othertype))
+ overrideTypeError(pos, member, other, self, false);
+ if (member.kind == TYPE &&
+ !self.memberLoBound(other).isSubType(
+ self.memberLoBound(member)))
+ overrideTypeError(pos, member, other, self, true);
+
+ }
+ }
+ }
+
+ void overrideError(int pos, Symbol member, Symbol other, String msg) {
+ if (other.type() != Type.ErrorType && member.type() != Type.ErrorType)
+ unit.error(pos,
+ "error overriding " + other + other.locationString() +
+ ";\n " + member + member.locationString() + " " + msg);
+ }
+
+ void overrideTypeError(int pos, Symbol member, Symbol other, Type site,
+ boolean lobound) {
+ if (other.type() != Type.ErrorType && member.type() != Type.ErrorType) {
+ Type memberInfo = lobound ? site.memberLoBound(member)
+ : normalizedInfo(site, member);
+ Type otherInfo = lobound ? site.memberLoBound(other)
+ : normalizedInfo(site, other);
+ unit.error(pos,
+ member + member.locationString() +
+ infoString(member, memberInfo, lobound) +
+ "\n cannot override " + other + other.locationString() +
+ infoString(other, otherInfo, lobound));
+ Type.explainTypes(memberInfo, otherInfo);
+ }
+ }
+
+ Type normalizedInfo(Type site, Symbol sym) {
+ Type tp = site.memberInfo(sym);
+ if (sym.kind == VAL && (sym.flags & STABLE) != 0) tp = tp.resultType();
+ return tp;
+ }
+
+ String infoString(Symbol sym, Type symtype, boolean lobound) {
+ switch (sym.kind) {
+ case ALIAS: return ", which equals " + symtype;
+ case TYPE: return " bounded" + (lobound ? " from below" : "") + " by " + symtype;
+ case VAL: return " of type " + symtype;
+ default: return "";
+ }
+ }
+
+ /** compensate for renaming during addition of access functions
+ */
+ Name normalize(Name name) {
+ return (name.endsWith(Name.fromString("$")))
+ ? name.subName(0, name.length() - 1)
+ : name;
+ }
+
+// Variance Checking --------------------------------------------------------
+
+ private final int
+ ContraVariance = -1,
+ NoVariance = 0,
+ CoVariance = 1,
+ AnyVariance = 2;
+
+ private String varianceString(int variance) {
+ if (variance == 1) return "covariant";
+ else if (variance == -1) return "contravariant";
+ else return "invariant";
+ }
+
+ /** The variance of symbol `base' relative to the class which defines `tvar'.
+ */
+ int flip(Symbol base, Symbol tvar) {
+ Symbol clazz = tvar.owner().primaryConstructorClass();
+ Symbol sym = base;
+ int flip = CoVariance;
+ while (sym != clazz && flip != AnyVariance) {
+ //System.out.println("flip: " + sym + " " + sym.isParameter());//DEBUG
+ if (sym.isParameter()) flip = -flip;
+ else if (sym.owner().kind != CLASS) flip = AnyVariance;
+ else if (sym.kind == ALIAS) flip = NoVariance;
+ sym = sym.owner();
+ }
+ return flip;
+ }
+
+ /** Check variance of type variables in this type
+ */
+ void validateVariance(Symbol base, Type tp, int variance) {
+ validateVariance(base, tp, tp, variance);
+ }
+
+ void validateVariance(Symbol base, Type all, Type tp, int variance) {
+ switch (tp) {
+ case ErrorType:
+ case AnyType:
+ case NoType:
+ case ThisType(Symbol sym):
+ break;
+ case SingleType(Type pre, Symbol sym):
+ validateVariance(base, all, pre, variance);
+ break;
+ case TypeRef(Type pre, Symbol sym, Type[] args):
+ if (sym.variance() != 0) {
+ int f = flip(base, sym);
+ if (f != AnyVariance && sym.variance() != f * variance) {
+ //System.out.println("flip(" + base + "," + sym + ") = " + f);//DEBUG
+ unit.error(base.pos,
+ varianceString(sym.variance()) + " " + sym +
+ " occurs in " + varianceString(f * variance) +
+ " position in type " + all + " of " + base);
+ }
+ }
+ validateVariance(base, all, pre, variance);
+ validateVariance(base, all, args, variance, sym.typeParams());
+ break;
+ case CompoundType(Type[] parts, Scope members):
+ validateVariance(base, all, parts, variance);
+ break;
+ case MethodType(Symbol[] vparams, Type result):
+ validateVariance(base, all, result, variance);
+ break;
+ case PolyType(Symbol[] tparams, Type result):
+ validateVariance(base, all, result, variance);
+ break;
+ case OverloadedType(Symbol[] alts, Type[] alttypes):
+ validateVariance(base, all, alttypes, variance);
+ }
+ }
+
+ void validateVariance(Symbol base, Type all, Type[] tps, int variance) {
+ for (int i = 0; i < tps.length; i++)
+ validateVariance(base, all, tps[i], variance);
+ }
+
+ void validateVariance(Symbol base, Type all, Type[] tps, int variance, Symbol[] tparams) {
+ for (int i = 0; i < tps.length; i++)
+ validateVariance(base, all, tps[i], variance * tparams[i].variance());
+ }
+
+// Forward reference checking ---------------------------------------------------
+
private Scope[] scopes = new Scope[4];
private int[] maxindex = new int[4];
private int[] refpos = new int[4];
private Symbol[] refsym = new Symbol[4];
private int level;
private HashMap symIndex = new HashMap();
- private Definitions defs = global.definitions;
- void pushLevel() {
+ private void pushLevel() {
level++;
if (level == scopes.length) {
Scope[] scopes1 = new Scope[scopes.length * 2];
@@ -53,36 +291,18 @@ public class RefCheck extends Transformer implements Modifiers, Kinds {
maxindex[level] = Integer.MIN_VALUE;
}
- void popLevel() {
+ private void popLevel() {
scopes[level] = null;
level --;
}
- public void apply(Unit unit) {
- this.unit = unit;
- level = 0;
- scopes[0] = new Scope();
- maxindex[0] = Integer.MIN_VALUE;
- unit.body = transformStats(unit.body);
- scopes[0] = null;
- symIndex.clear();
- }
-
- /** compensate for renaming during addition of access functions
- */
- Name normalize(Name name) {
- return (name.endsWith(Name.fromString("$")))
- ? name.subName(0, name.length() - 1)
- : name;
- }
-
- void enterSyms(Tree[] stats) {
+ private void enterSyms(Tree[] stats) {
for (int i = 0; i < stats.length; i++) {
enterSym(stats[i], i);
}
}
- void enterSym(Tree stat, int index) {
+ private void enterSym(Tree stat, int index) {
Symbol sym = null;
switch (stat) {
case ClassDef(_, _, _, _, _, _):
@@ -99,27 +319,7 @@ public class RefCheck extends Transformer implements Modifiers, Kinds {
}
}
- public Tree[] transformStats(Tree[] stats) {
- pushLevel();
- enterSyms(stats);
- int i = 0;
- while (i < stats.length) {
- Tree[] newstat = transformStat(stats[i], i);
- if (newstat != null) {
- Tree[] newstats = new Tree[stats.length + newstat.length - 1];
- System.arraycopy(stats, 0, newstats, 0, i);
- System.arraycopy(newstat, 0, newstats, i, newstat.length);
- System.arraycopy(stats, i + 1, newstats, i + newstat.length,
- stats.length - i - 1);
- i = i + newstat.length;
- stats = newstats;
- } else {
- i = i + 1;
- }
- }
- popLevel();
- return stats;
- }
+// Module eliminiation -----------------------------------------------------------
private Tree[] transformModule(Tree tree, int mods, Name name, Tree tpe, Tree.Template templ) {
Symbol sym = tree.symbol();
@@ -181,6 +381,8 @@ public class RefCheck extends Transformer implements Modifiers, Kinds {
}
}
+// Adding case methods --------------------------------------------------------------
+
private boolean hasImplementation(Symbol clazz, Name name) {
Symbol sym = clazz.info().lookupNonPrivate(name);
return sym.kind == VAL &&
@@ -275,68 +477,67 @@ public class RefCheck extends Transformer implements Modifiers, Kinds {
Type.MethodType(new Symbol[]{equalsParam}, defs.BOOLEAN_TYPE));
clazz.info().members().enter(equalsSym);
Tree[] fields = caseFields(clazz);
- Type constrtype = clazz.constructor().type();
- switch (constrtype) {
- case PolyType(Symbol[] tparams, Type restp):
- Type[] targs = new Type[tparams.length];
- for (int i = 0; i < targs.length; i++)
- targs[i] = defs.ANY_TYPE;
- constrtype = restp.subst(tparams, targs);
+ Type testtp = clazz.type();
+ {
+ Symbol[] tparams = clazz.typeParams();
+ if (tparams.length != 0) {
+ Type[] targs = new Type[tparams.length];
+ for (int i = 0; i < targs.length; i++)
+ targs[i] = defs.ANY_TYPE;
+ testtp = testtp.subst(tparams, targs);
+ }
}
- Tree[] patargs = patternVars(clazz.pos, constrtype, equalsSym);
- Tree pattern = make.Apply(
- clazz.pos, gen.mkType(clazz.pos, constrtype), patargs)
- .setType(clazz.type());
- Tree rhs;
+
+ // if (that is C) {...
+ Tree cond = gen.TypeApply(
+ gen.Select(
+ gen.mkRef(clazz.pos, Type.localThisType, equalsParam),
+ defs.IS),
+ new Tree[]{gen.mkType(clazz.pos, testtp)});
+
+ Tree thenpart;
if (fields.length == 0) {
- rhs = gen.mkBooleanLit(clazz.pos, true);
+ thenpart = gen.mkBooleanLit(clazz.pos, true);
} else {
- rhs = eqOp(fields[0], patargs[0]);
+ // val that1 = that as C;
+ Tree cast = gen.TypeApply(
+ gen.Select(
+ gen.mkRef(clazz.pos, Type.localThisType, equalsParam),
+ defs.AS),
+ new Tree[]{gen.mkType(clazz.pos, testtp)});
+ Symbol that1sym = new TermSymbol(clazz.pos, Names.that1, equalsSym, 0)
+ .setType(testtp);
+ Tree that1def = gen.ValDef(that1sym, cast);
+
+ // this.elem_1 == that1.elem_1 && ... && this.elem_n == that1.elem_n
+ Tree cmp = eqOp(
+ fields[0],
+ qualCaseField(clazz,
+ gen.mkRef(clazz.pos, Type.localThisType, that1sym), 0));
for (int i = 1; i < fields.length; i++) {
- rhs = gen.Apply(
- gen.Select(rhs, defs.AMPAMP()),
- new Tree[]{eqOp(fields[i], patargs[i])});
+ cmp = gen.Apply(
+ gen.Select(cmp, defs.AMPAMP()),
+ new Tree[]{
+ eqOp(
+ fields[i],
+ qualCaseField(clazz,
+ gen.mkRef(clazz.pos, Type.localThisType, that1sym), i))});
}
+ thenpart = gen.Block(new Tree[]{that1def, cmp});
}
- CaseDef case1 = (Tree.CaseDef) make.CaseDef(
- clazz.pos, pattern, Tree.Empty, rhs)
- .setType(defs.BOOLEAN_TYPE);
- CaseDef case2 = (Tree.CaseDef) make.CaseDef(clazz.pos,
- patternVar(clazz.pos, Names.WILDCARD, defs.ANY_TYPE, equalsSym),
- Tree.Empty,
- gen.mkBooleanLit(clazz.pos, false))
- .setType(defs.BOOLEAN_TYPE);
- Tree body = make.Apply(clazz.pos,
- gen.Select(
- gen.mkRef(clazz.pos, Type.localThisType, equalsParam),
- defs.MATCH),
- new Tree[]{make.Visitor(clazz.pos, new CaseDef[]{case1, case2})
- .setType(defs.BOOLEAN_TYPE)})
- .setType(defs.BOOLEAN_TYPE);
- return gen.DefDef(clazz.pos, equalsSym, body);
+ Tree body = gen.If(cond, thenpart, gen.mkBooleanLit(clazz.pos, false));
+ return gen.DefDef(equalsSym, body);
}
//where
- private Tree patternVar(int pos, Name name, Type tp, Symbol owner) {
- return make.Ident(pos, name)
- .setSymbol(new TermSymbol(pos, name, owner, 0).setType(tp))
- .setType(tp);
- }
-
- private Tree[] patternVars(int pos, Type constrtype, Symbol owner) {
- Symbol[] vparams = constrtype.firstParams();
- Tree[] pats = new Tree[vparams.length];
- for (int i = 0; i < pats.length; i++) {
- pats[i] = patternVar(
- pos, vparams[i].name, vparams[i].type(), owner);
- }
- return pats;
- }
-
private Tree eqOp(Tree l, Tree r) {
Symbol eqMethod = getUnaryMemberMethod(l.type, Names.EQEQ, r.type);
return gen.Apply(gen.Select(l, eqMethod), new Tree[]{r});
}
+ private Tree qualCaseField(ClassSymbol clazz, Tree qual, int i) {
+ return gen.Select(qual, clazz.caseFieldAccessor(i));
+ }
+
private Tree hashCodeMethod(ClassSymbol clazz) {
Symbol hashCodeSym = new TermSymbol(
clazz.pos, Names.hashCode, clazz, OVERRIDE)
@@ -401,33 +602,22 @@ public class RefCheck extends Transformer implements Modifiers, Kinds {
}
}
- public Tree convertCaseFactoryCall(Tree tree) {
- Symbol fsym = TreeInfo.methSymbol(tree);
- if (fsym != null && fsym.isMethod() && !fsym.isConstructor() &&
- (fsym.flags & CASE) != 0) {
- // convert case methods to new's
- Symbol constr = fsym.owner().info()
- .lookup(fsym.name.toTypeName()).constructor();
- return gen.New(toConstructor(tree, constr));
- } else {
- return tree;
+// Convert case factory calls to constructor calls ---------------------------
+
+ /** Tree represents an application of a constructor method of a case class
+ * (whose name is a term name). Convert this tree to application of
+ * the case classe's primary constructor `constr'.
+ */
+ private Tree toConstructor(Tree tree, Symbol constr) {
+ switch (tree) {
+ case Apply(Tree fn, Tree[] args):
+ return copy.Apply(tree, toConstructor1(fn, constr), args);
+ default:
+ return gen.Apply(
+ tree.pos, toConstructor1(tree, constr), Tree.EMPTY_ARRAY);
}
}
//where
- /** Tree represents an application of a constructor method of a case class
- * (whose name is a term name). Convert this tree to application of
- * the case classe's primary constructor `constr'.
- */
- private Tree toConstructor(Tree tree, Symbol constr) {
- switch (tree) {
- case Apply(Tree fn, Tree[] args):
- return copy.Apply(tree, toConstructor1(fn, constr), args);
- default:
- return gen.Apply(
- tree.pos, toConstructor1(tree, constr), Tree.EMPTY_ARRAY);
- }
- }
-
private Tree toConstructor1(Tree tree, Symbol constr) {
switch (tree) {
case TypeApply(Tree fn, Tree[] args):
@@ -463,17 +653,64 @@ public class RefCheck extends Transformer implements Modifiers, Kinds {
}
}
- /** The main checking functions
- */
- public Tree[] transformStat(Tree tree, int index) {
- Tree resultTree;
+// Bounds checking -----------------------------------------------------------
+
+ private void checkBounds(int pos, Symbol[] tparams, Type[] argtypes) {
+ if (tparams.length == argtypes.length) {
+ try {
+ infer.checkBounds(tparams, argtypes, "");
+ } catch (Type.Error ex) {
+ unit.error(pos, ex.msg);
+ }
+ }
+ }
+
+// Type node eliminiation ------------------------------------------------------
+
+ private Tree elimTypeNode(Tree tree) {
+ if (tree.isType() && !tree.isMissing())
+ return make.TypeTerm(tree.pos).setType(tree.type);
+ else
+ return tree;
+ }
+
+// Transformation ---------------------------------------------------------------
+
+ public Tree[] transformStats(Tree[] stats) {
+ pushLevel();
+ enterSyms(stats);
+ int i = 0;
+ while (i < stats.length) {
+ Object stat1 = transformStat(stats[i], i);
+ if (stat1 instanceof Tree) {
+ stats[i] = (Tree) stat1;
+ i = i + 1;
+ } else {
+ Tree[] newstats = (Tree[]) stat1;
+ Tree[] stats1 = new Tree[stats.length - 1 + newstats.length];
+ System.arraycopy(stats, 0, stats1, 0, i);
+ System.arraycopy(newstats, 0, stats1, i, newstats.length);
+ System.arraycopy(stats, i + 1, stats1, i + newstats.length,
+ stats.length - i - 1);
+ stats = stats1;
+ i = i + newstats.length;
+ }
+ }
+ popLevel();
+ return stats;
+ }
+
+ public Object transformStat(Tree tree, int index) {
switch (tree) {
case ModuleDef(int mods, Name name, Tree tpe, Tree.Template templ):
return transform(transformModule(tree, mods, name, tpe, templ));
case ValDef(int mods, Name name, Tree tpe, Tree rhs):
Symbol sym = tree.symbol();
- resultTree = transform(tree);
+ validateVariance(
+ sym, sym.type(),
+ ((sym.flags & MUTABLE) != 0) ? NoVariance : CoVariance);
+ Tree tree1 = transform(tree);
//todo: handle variables
if (sym.isLocal() && !sym.isModule() && index <= maxindex[level]) {
if (Global.instance.debug)
@@ -483,36 +720,86 @@ public class RefCheck extends Transformer implements Modifiers, Kinds {
"forward reference extends over definition of value " +
normalize(name));
}
- break;
+ return tree1;
default:
- resultTree = transform(tree);
+ return transform(tree);
}
- return (resultTree == tree) ? null : new Tree[]{resultTree};
}
public Tree transform(Tree tree) {
- Tree tree1;
+ Symbol sym = tree.symbol();
switch (tree) {
case ClassDef(_, _, Tree.TypeDef[] tparams, Tree.ValDef[][] vparams, Tree tpe, Tree.Template templ):
+ validateVariance(sym, sym.info(), CoVariance);
+ validateVariance(sym, sym.typeOfThis(), CoVariance);
return super.transform(
copy.ClassDef(tree, tree.symbol(), tparams, vparams, tpe, addCaseMethods(templ, tree.symbol())));
+ case DefDef(_, _, _, _, _, _):
+ validateVariance(sym, sym.type(), CoVariance);
+ return super.transform(tree);
+
+ case TypeDef(_, _, _, _):
+ if (sym.kind == ALIAS) {
+ validateVariance(sym, sym.info(), NoVariance);
+ } else {
+ validateVariance(sym, sym.info(), CoVariance);
+ validateVariance(sym, sym.loBound(), ContraVariance);
+ }
+ return super.transform(tree);
+
case Template(Tree[] bases, Tree[] body):
Tree[] bases1 = transform(bases);
Tree[] body1 = transformStats(body);
+ if (sym.kind == VAL) {
+ checkAllOverrides(tree.pos, tree.symbol().owner());
+ }
return copy.Template(tree, bases1, body1);
+
case Block(Tree[] stats):
Tree[] stats1 = transformStats(stats);
return copy.Block(tree, stats1);
+
case This(_):
return tree;
+
case PackageDef(Tree pkg, Template packaged):
return copy.PackageDef(tree, pkg, super.transform(packaged));
+
+ case TypeApply(Tree fn, Tree[] args):
+ switch (fn.type) {
+ case PolyType(Symbol[] tparams, Type restp):
+ checkBounds(tree.pos, tparams, Tree.typeOf(args));
+ }
+ return super.transform(tree);
+
+ case Apply(Tree fn, Tree[] args):
+ Symbol fsym = TreeInfo.methSymbol(fn);
+ if (fsym != null && fsym.isMethod() && !fsym.isConstructor() &&
+ (fsym.flags & CASE) != 0) {
+ // convert case methods to new's
+ Symbol constr = fsym.owner().info()
+ .lookup(fsym.name.toTypeName()).constructor();
+ tree = gen.New(toConstructor(tree, constr));
+ }
+ return super.transform(tree);
+
+ case AppliedType(Tree tpe, Tree[] args):
+ //todo: this needs to be refined.
+ Symbol[] tparams =
+ (Type.isSameAs(
+ tpe.type.typeArgs(), Symbol.type(tpe.type.typeParams())))
+ ? tpe.type.typeParams() : Symbol.EMPTY_ARRAY;
+ checkBounds(tree.pos, tparams, Tree.typeOf(args));
+ return elimTypeNode(super.transform(tree));
+
+ case CompoundType(_, _):
+ checkAllOverrides(tree.pos, tree.type.symbol());
+ return elimTypeNode(super.transform(tree));
+
case Ident(Name name):
Scope.Entry e = scopes[level].lookupEntry(name);
- Symbol sym = tree.symbol();
- assert sym != null : name;
if (sym.isLocal() && sym == e.sym) {
int i = level;
while (scopes[i] != e.owner) i--;
@@ -523,14 +810,12 @@ public class RefCheck extends Transformer implements Modifiers, Kinds {
maxindex[i] = symindex;
}
}
- tree1 = convertCaseFactoryCall(tree);
- break;
+ return elimTypeNode(tree);
+
default:
- tree1 = super.transform(convertCaseFactoryCall(tree));
+ return elimTypeNode(super.transform(tree));
}
- if (tree1.isType() && !tree1.isMissing())
- tree1 = gen.mkType(tree1.pos, tree1.type);
- return tree1;
- }
+
+ }
}
diff --git a/sources/scalac/util/Names.java b/sources/scalac/util/Names.java
index b7e2b0e0c2..f2cfab763d 100644
--- a/sources/scalac/util/Names.java
+++ b/sources/scalac/util/Names.java
@@ -82,7 +82,6 @@ public class Names {
public static final Name runtime = Name.fromString("runtime");
public static final Name scala = Name.fromString("scala");
public static final Name scala_COLONCOLON = Name.fromString("scala." + COLONCOLON);
- public static final Name scala_Algebraic = Name.fromString("scala.Algebraic");
public static final Name scala_All = Name.fromString("scala.All");
public static final Name scala_AllRef = Name.fromString("scala.AllRef");
public static final Name scala_Any = Name.fromString("scala.Any");
@@ -113,6 +112,7 @@ public class Names {
public static final Name equals = Name.fromString("equals");
public static final Name toString = Name.fromString("toString");
public static final Name that = Name.fromString("that");
+ public static final Name that1 = Name.fromString("that1");
public static final Name this_ = Name.fromString("this");
public static final Name throw_ = Name.fromString("throw");
public static final Name true_ = Name.fromString("true");