summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/reference/ReferencePart.tex23
-rw-r--r--sources/scala/tools/scalac/typechecker/Analyzer.scala112
-rw-r--r--sources/scala/tools/scalac/typechecker/Infer.scala2
-rw-r--r--sources/scalac/ast/TreeInfo.java5
-rw-r--r--test/files/neg/Y.check4
-rw-r--r--test/files/neg/Y.scala (renamed from test/files/pos/Y.scala)0
-rw-r--r--test/files/pos/bug295.scala2
7 files changed, 107 insertions, 41 deletions
diff --git a/doc/reference/ReferencePart.tex b/doc/reference/ReferencePart.tex
index eb665d0167..d628a57c2d 100644
--- a/doc/reference/ReferencePart.tex
+++ b/doc/reference/ReferencePart.tex
@@ -2207,21 +2207,26 @@ which appear in the same statement sequence as the definition of
A class definition which starts with the reserved word \code{trait}
instead of \code{class} defines a trait. A trait is a specific
instance of an abstract class, so the \code{abstract} modifier is
-redundant for it. The template of a trait must satisfy the following
+redundant for it. The trait definition must satisfy the following
four restrictions.
\begin{enumerate}
-\item All base classes of the trait are traits.
-\item All parent class constructors of a template
- must be primary constructors with empty value
+\item There are no value parameters in the trait's primary constructor, nor
+ are there secondary constructors.
+\item All mixin base classes of the trait are traits.
+\item All parent class constructors of the trait
+ are primary constructors with empty value
parameter lists.
-\item All non-empty statements in the template are either imports or pure definitions.
-\item A trait may not have secondary constructors.
+\item All non-empty statements in the trait's template are either
+ imports or pure definitions.
\end{enumerate}
A {\em pure} definition can be evaluated without any side effect.
Function, type, class, or object definitions are always pure. A value
-definition is pure if its right-hand side expression is pure. Pure
-expressions are paths, literals, and typed expressions
-$e: T$ where $e$ is pure.
+definition is pure if its right-hand side expression is pure. A
+secondary constructor definition is pure if its right-hand side
+consists only
+Pure
+expressions are paths, literals, and typed expressions $e: T$ where
+$e$ is pure.
These restrictions ensure that the evaluation of the mixin constructor
of a trait has no effect. Therefore, traits may appear several times
diff --git a/sources/scala/tools/scalac/typechecker/Analyzer.scala b/sources/scala/tools/scalac/typechecker/Analyzer.scala
index da4695c6f5..9550011d61 100644
--- a/sources/scala/tools/scalac/typechecker/Analyzer.scala
+++ b/sources/scala/tools/scalac/typechecker/Analyzer.scala
@@ -481,25 +481,52 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
}
}
- /** Check that tree represents a pure definition.
+ /** Check that tree represents a legal trait definition.
*/
- def checkPureDef(tree: Tree, clazz: Symbol): unit = {
- if (!TreeInfo.isPureDef(tree) && !tree.getType().isError())
- error(tree.pos, "" + clazz + " may contain only pure definitions");
- }
+ def checkTraitDef(pos: int, clazz: Symbol, templ: Tree$Template) = {
- /** Check that tree represents a pure constructor.
- */
- def checkPureConstr(tree: Tree, clazz: Symbol): unit = {
- if (!TreeInfo.isPureConstr(tree) && !tree.getType().isError())
- error(tree.pos, "" + clazz + " may invoke only pure superclass constructors");
- }
+ /** Check that type does not have value parameters
+ */
+ def checkNoParams(tpe: Type): unit = tpe match {
+ case Type$MethodType(vparams, _) =>
+ if (vparams.length > 0)
+ error(pos, "trait may not have value parameters")
+ case Type$PolyType(tparams, restpe) =>
+ checkNoParams(infer.skipViewParams(tparams, restpe))
+ case _ =>
+ }
- /** Check that tree represents a trait constructor.
- */
- def checkTrait(tree: Tree, clazz: Symbol): unit = {
- if (!tree.getType().symbol().isTrait() && !tree.getType().isError())
- error(tree.pos, " " + clazz + " may inherit only traits as mixins");
+ /** Check that tree represents a pure constructor.
+ */
+ def checkPureConstr(tree: Tree): unit = {
+ if (!TreeInfo.isPureConstr(tree) && !tree.getType().isError())
+ error(tree.pos, "" + clazz + " may invoke only pure superclass constructors");
+ }
+
+ /** Check that tree refers to a trait
+ */
+ def checkTraitRef(tree: Tree): unit = {
+ if (!tree.getType().symbol().isTrait() && !tree.getType().isError())
+ error(tree.pos, " " + clazz + " may inherit only traits as mixins");
+ }
+
+ /** Check that tree represents a pure definition.
+ */
+ def checkPureDef(tree: Tree): unit = {
+ if (!TreeInfo.isPureDef(tree) && !tree.getType().isError())
+ error(tree.pos, "" + clazz + " may contain only pure definitions");
+ }
+
+ checkNoParams(clazz.primaryConstructor().getType());
+ var i = 0; while (i < templ.parents.length) {
+ checkPureConstr(templ.parents(i));
+ if (i >= 1) checkTraitRef(templ.parents(i));
+ i = i + 1
+ }
+ var j = 0; while (j < templ.body.length) {
+ checkPureDef(templ.body(j));
+ j = j + 1
+ }
}
/** Check that tree is a stable expression .p
@@ -1082,7 +1109,10 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
case Tree$ModuleDef(mods, name, _tpe, templ) =>
var tpe = _tpe;
val clazz: Symbol = sym.moduleClass();
+ pushContext(
+ tree, clazz.primaryConstructor(), context.scope);
defineTemplate(templ, clazz, new Scope());
+ popContext();
clazz.setInfo(templ.getType());
tpe = transform(tpe, TYPEmode);
(tree.asInstanceOf[Tree$ModuleDef]).tpe = tpe;
@@ -1390,7 +1420,12 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
(infer.isCompatible(tree.getType(), pt) ||
pt.symbol() == definitions.UNIT_CLASS)) {
checkEtaExpandable(tree.pos, tree.getType());
- return transform(desugarize.etaExpand(tree, tree.getType()), mode, pt);
+ if (TreeInfo.methPart(tree).symbol() == definitions.ANY_MATCH) {
+ error(tree.pos, "`match' needs to be applied fully");
+ return errorTree(tree)
+ } else {
+ return transform(desugarize.etaExpand(tree, tree.getType()), mode, pt);
+ }
} else if ((mode & (CONSTRmode | FUNmode)) == CONSTRmode) {
error(tree.pos, "missing arguments for class constructor");
return errorTermTree(tree);
@@ -1584,7 +1619,28 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
while (nextimports != null && nextimports.tree.pos >= tree.pos) {
nextimports = nextimports.prev;
}
- while (sym1.kind == NONE && nextimports != null && nextimports.tree.pos > stopPos) {
+
+ if (stopPos > tree.pos) {
+ // set stopPos to beginning of block enclosed in the scope which defines the
+ // referenced symbol.
+ var lastc = Context.NONE;
+ var c = nextcontext;
+ while (c.outer.scope != null && c.outer.scope.lookup(name) == sym) {
+ c.tree match {
+ case Tree$Block(_, _) | Tree$CaseDef(_, _, _) | Tree$ClassDef(_, _, _, _, _, _) | Tree$ModuleDef(_, _, _, _) =>
+ lastc = c;
+ case _ =>
+ }
+ c = c.outer
+ }
+ if (lastc != Context.NONE) {
+ //System.out.println("revising stop to [" + lastc.tree + "]; symbol = " + sym + ", context = " + nextcontext);//debug
+ stopPos = lastc.tree.pos;
+ }
+ }
+
+ while (sym1.kind == NONE &&
+ nextimports != null && nextimports.tree.pos > stopPos) {
sym1 = nextimports.importedSymbol(name);
lastimports = nextimports;
nextimports = nextimports.prev;
@@ -1842,17 +1898,6 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
popContext();
*/
popContext();
- if (owner.isTrait()) {
- var i = 0; while (i < parents.length) {
- checkPureConstr(parents(i), owner);
- if (i >= 1) checkTrait(parents(i), owner);
- i = i + 1
- }
- var j = 0; while (j < templ.body.length) {
- checkPureDef(body1(j), owner);
- j = j + 1
- }
- }
val templ1: Tree$Template = copy.Template(templ, parents, body1);
templ1.setType(owner.getType());
templ1
@@ -2098,14 +2143,19 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
templ.body, vparams(vparams.length - 1));
val templ1: Tree$Template = transformTemplate(templ, sym);
+ if (sym.isTrait()) checkTraitDef(tree.pos, sym, templ1);
checkNoEscape(tree.pos, sym.info());
popContext();
copy.ClassDef(tree, sym, tparams1, vparams1, tpe1, templ1)
.setType(Type.NoType);
case Tree$ModuleDef(_, _, tpe, templ) =>
- sym.moduleClass().initialize();
+ val clazz = sym.moduleClass();
+ clazz.initialize();
+ pushContext(
+ tree, clazz.primaryConstructor(), context.scope);
val tpe1: Tree = transform(tpe, TYPEmode);
+ popContext();
val templ1: Tree$Template = transformTemplate(templ, sym.moduleClass());
if (tpe1 != Tree.Empty && !templ1.getType().isSubType(tpe1.getType()))
error(tree.pos, "" + sym + " does not implement " + tpe1.getType());
@@ -2417,6 +2467,7 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
val body1: Tree = transform(body, EXPRmode, restype);
if (!infer.isFullyDefined(restype))
restype = body1.getType().deconst();
+ restype = checkNoEscape(tree.pos, restype);
popContext();
gen.mkFunction(tree.pos, vparams1, body1, restype, context.owner);
@@ -2506,6 +2557,7 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
var c = context;
while (c != Context.NONE &&
!c.tree.isInstanceOf[Tree$ClassDef] &&
+ !c.tree.isInstanceOf[Tree$ModuleDef] &&
!c.tree.isInstanceOf[Tree$Template])
c = c.outer;
enclClassOrConstructorContext = c
diff --git a/sources/scala/tools/scalac/typechecker/Infer.scala b/sources/scala/tools/scalac/typechecker/Infer.scala
index 2b7b8812ed..438a28afd5 100644
--- a/sources/scala/tools/scalac/typechecker/Infer.scala
+++ b/sources/scala/tools/scalac/typechecker/Infer.scala
@@ -249,7 +249,7 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal
(sym.flags & (PRIVATE | PROTECTED)) == 0
||
{val owner = if (sym.isConstructor()) sym.constructorClass()
- else sym.owner();
+ else sym.owner();
accessWithin(owner)
||
((sym.flags & PRIVATE) == 0) &&
diff --git a/sources/scalac/ast/TreeInfo.java b/sources/scalac/ast/TreeInfo.java
index b66b7d2357..6321fc280b 100644
--- a/sources/scalac/ast/TreeInfo.java
+++ b/sources/scalac/ast/TreeInfo.java
@@ -77,13 +77,16 @@ public class TreeInfo {
case Tree.Empty:
case ClassDef(_, _, _, _, _, _):
case ModuleDef(_, _, _, _):
- case DefDef(_, _, _, _, _, _):
case AbsTypeDef(_, _, _, _):
case AliasTypeDef(_, _, _, _):
case Import(_, _):
return true;
+ case DefDef(_, Name name, _, _, _, _):
+ return name != Names.CONSTRUCTOR;
case ValDef(int mods, _, _, Tree rhs):
return (mods & Modifiers.MUTABLE) == 0 && isPureExpr(rhs);
+ case DocDef(_, Tree definition):
+ return isPureDef(definition);
default:
return false;
}
diff --git a/test/files/neg/Y.check b/test/files/neg/Y.check
new file mode 100644
index 0000000000..fca14d1c0b
--- /dev/null
+++ b/test/files/neg/Y.check
@@ -0,0 +1,4 @@
+/home/odersky/scala/test/files/neg/Y.scala:3: `match' needs to be applied fully
+ def f(x: Object): java.lang.Object /* !!! Object */ = x.match;
+ ^
+one error found
diff --git a/test/files/pos/Y.scala b/test/files/neg/Y.scala
index fd235e735d..fd235e735d 100644
--- a/test/files/pos/Y.scala
+++ b/test/files/neg/Y.scala
diff --git a/test/files/pos/bug295.scala b/test/files/pos/bug295.scala
new file mode 100644
index 0000000000..22c7beff4d
--- /dev/null
+++ b/test/files/pos/bug295.scala
@@ -0,0 +1,2 @@
+object Test extends java.rmi.server.UnicastRemoteObject {
+}