*** empty log message ***

git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@3053 5e8d7ff9-d8ef-0310-90f0-a4852d11357a
This commit is contained in:
odersky 2004-04-19 17:02:30 +00:00
parent 3fb3ee4ff2
commit 0e50f11a89
7 changed files with 107 additions and 41 deletions

View File

@ -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

View File

@ -481,27 +481,54 @@ 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 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 pure constructor.
*/
def checkPureConstr(tree: Tree, clazz: Symbol): unit = {
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 represents a trait constructor.
/** Check that tree refers to a trait
*/
def checkTrait(tree: Tree, clazz: Symbol): unit = {
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
*/
def checkStable(tree: Tree): Tree =
@ -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());
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

View File

@ -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;
}

4
test/files/neg/Y.check Normal file
View File

@ -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

View File

@ -0,0 +1,2 @@
object Test extends java.rmi.server.UnicastRemoteObject {
}