*** 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} A class definition which starts with the reserved word \code{trait}
instead of \code{class} defines a trait. A trait is a specific instead of \code{class} defines a trait. A trait is a specific
instance of an abstract class, so the \code{abstract} modifier is 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. four restrictions.
\begin{enumerate} \begin{enumerate}
\item All base classes of the trait are traits. \item There are no value parameters in the trait's primary constructor, nor
\item All parent class constructors of a template are there secondary constructors.
must be primary constructors with empty value \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. parameter lists.
\item All non-empty statements in the template are either imports or pure definitions. \item All non-empty statements in the trait's template are either
\item A trait may not have secondary constructors. imports or pure definitions.
\end{enumerate} \end{enumerate}
A {\em pure} definition can be evaluated without any side effect. A {\em pure} definition can be evaluated without any side effect.
Function, type, class, or object definitions are always pure. A value Function, type, class, or object definitions are always pure. A value
definition is pure if its right-hand side expression is pure. Pure definition is pure if its right-hand side expression is pure. A
expressions are paths, literals, and typed expressions secondary constructor definition is pure if its right-hand side
$e: T$ where $e$ is pure. 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 These restrictions ensure that the evaluation of the mixin constructor
of a trait has no effect. Therefore, traits may appear several times 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 = { def checkTraitDef(pos: int, clazz: Symbol, templ: Tree$Template) = {
if (!TreeInfo.isPureDef(tree) && !tree.getType().isError())
error(tree.pos, "" + clazz + " may contain only pure definitions"); /** 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. /** 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()) if (!TreeInfo.isPureConstr(tree) && !tree.getType().isError())
error(tree.pos, "" + clazz + " may invoke only pure superclass constructors"); 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()) if (!tree.getType().symbol().isTrait() && !tree.getType().isError())
error(tree.pos, " " + clazz + " may inherit only traits as mixins"); 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 /** Check that tree is a stable expression .p
*/ */
def checkStable(tree: Tree): Tree = 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) => case Tree$ModuleDef(mods, name, _tpe, templ) =>
var tpe = _tpe; var tpe = _tpe;
val clazz: Symbol = sym.moduleClass(); val clazz: Symbol = sym.moduleClass();
pushContext(
tree, clazz.primaryConstructor(), context.scope);
defineTemplate(templ, clazz, new Scope()); defineTemplate(templ, clazz, new Scope());
popContext();
clazz.setInfo(templ.getType()); clazz.setInfo(templ.getType());
tpe = transform(tpe, TYPEmode); tpe = transform(tpe, TYPEmode);
(tree.asInstanceOf[Tree$ModuleDef]).tpe = tpe; (tree.asInstanceOf[Tree$ModuleDef]).tpe = tpe;
@ -1390,7 +1420,12 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
(infer.isCompatible(tree.getType(), pt) || (infer.isCompatible(tree.getType(), pt) ||
pt.symbol() == definitions.UNIT_CLASS)) { pt.symbol() == definitions.UNIT_CLASS)) {
checkEtaExpandable(tree.pos, tree.getType()); 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); return transform(desugarize.etaExpand(tree, tree.getType()), mode, pt);
}
} else if ((mode & (CONSTRmode | FUNmode)) == CONSTRmode) { } else if ((mode & (CONSTRmode | FUNmode)) == CONSTRmode) {
error(tree.pos, "missing arguments for class constructor"); error(tree.pos, "missing arguments for class constructor");
return errorTermTree(tree); return errorTermTree(tree);
@ -1584,7 +1619,28 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
while (nextimports != null && nextimports.tree.pos >= tree.pos) { while (nextimports != null && nextimports.tree.pos >= tree.pos) {
nextimports = nextimports.prev; 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); sym1 = nextimports.importedSymbol(name);
lastimports = nextimports; lastimports = nextimports;
nextimports = nextimports.prev; nextimports = nextimports.prev;
@ -1842,17 +1898,6 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
popContext(); popContext();
*/ */
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); val templ1: Tree$Template = copy.Template(templ, parents, body1);
templ1.setType(owner.getType()); templ1.setType(owner.getType());
templ1 templ1
@ -2098,14 +2143,19 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
templ.body, vparams(vparams.length - 1)); templ.body, vparams(vparams.length - 1));
val templ1: Tree$Template = transformTemplate(templ, sym); val templ1: Tree$Template = transformTemplate(templ, sym);
if (sym.isTrait()) checkTraitDef(tree.pos, sym, templ1);
checkNoEscape(tree.pos, sym.info()); checkNoEscape(tree.pos, sym.info());
popContext(); popContext();
copy.ClassDef(tree, sym, tparams1, vparams1, tpe1, templ1) copy.ClassDef(tree, sym, tparams1, vparams1, tpe1, templ1)
.setType(Type.NoType); .setType(Type.NoType);
case Tree$ModuleDef(_, _, tpe, templ) => 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); val tpe1: Tree = transform(tpe, TYPEmode);
popContext();
val templ1: Tree$Template = transformTemplate(templ, sym.moduleClass()); val templ1: Tree$Template = transformTemplate(templ, sym.moduleClass());
if (tpe1 != Tree.Empty && !templ1.getType().isSubType(tpe1.getType())) if (tpe1 != Tree.Empty && !templ1.getType().isSubType(tpe1.getType()))
error(tree.pos, "" + sym + " does not implement " + 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); val body1: Tree = transform(body, EXPRmode, restype);
if (!infer.isFullyDefined(restype)) if (!infer.isFullyDefined(restype))
restype = body1.getType().deconst(); restype = body1.getType().deconst();
restype = checkNoEscape(tree.pos, restype);
popContext(); popContext();
gen.mkFunction(tree.pos, vparams1, body1, restype, context.owner); 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; var c = context;
while (c != Context.NONE && while (c != Context.NONE &&
!c.tree.isInstanceOf[Tree$ClassDef] && !c.tree.isInstanceOf[Tree$ClassDef] &&
!c.tree.isInstanceOf[Tree$ModuleDef] &&
!c.tree.isInstanceOf[Tree$Template]) !c.tree.isInstanceOf[Tree$Template])
c = c.outer; c = c.outer;
enclClassOrConstructorContext = c enclClassOrConstructorContext = c

View File

@ -77,13 +77,16 @@ public class TreeInfo {
case Tree.Empty: case Tree.Empty:
case ClassDef(_, _, _, _, _, _): case ClassDef(_, _, _, _, _, _):
case ModuleDef(_, _, _, _): case ModuleDef(_, _, _, _):
case DefDef(_, _, _, _, _, _):
case AbsTypeDef(_, _, _, _): case AbsTypeDef(_, _, _, _):
case AliasTypeDef(_, _, _, _): case AliasTypeDef(_, _, _, _):
case Import(_, _): case Import(_, _):
return true; return true;
case DefDef(_, Name name, _, _, _, _):
return name != Names.CONSTRUCTOR;
case ValDef(int mods, _, _, Tree rhs): case ValDef(int mods, _, _, Tree rhs):
return (mods & Modifiers.MUTABLE) == 0 && isPureExpr(rhs); return (mods & Modifiers.MUTABLE) == 0 && isPureExpr(rhs);
case DocDef(_, Tree definition):
return isPureDef(definition);
default: default:
return false; 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 {
}