diff options
author | Martin Odersky <odersky@gmail.com> | 2004-04-19 17:02:30 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2004-04-19 17:02:30 +0000 |
commit | 77f339b1011924a21e463739f9132bde850c17c6 (patch) | |
tree | 8d121abc7c7ec98ccd7ef971444e4bb641091b06 | |
parent | 8ff3a9738146851ae41568c2df359c8f8fa83942 (diff) | |
download | scala-77f339b1011924a21e463739f9132bde850c17c6.tar.gz scala-77f339b1011924a21e463739f9132bde850c17c6.tar.bz2 scala-77f339b1011924a21e463739f9132bde850c17c6.zip |
*** empty log message ***
-rw-r--r-- | doc/reference/ReferencePart.tex | 23 | ||||
-rw-r--r-- | sources/scala/tools/scalac/typechecker/Analyzer.scala | 112 | ||||
-rw-r--r-- | sources/scala/tools/scalac/typechecker/Infer.scala | 2 | ||||
-rw-r--r-- | sources/scalac/ast/TreeInfo.java | 5 | ||||
-rw-r--r-- | test/files/neg/Y.check | 4 | ||||
-rw-r--r-- | test/files/neg/Y.scala (renamed from test/files/pos/Y.scala) | 0 | ||||
-rw-r--r-- | test/files/pos/bug295.scala | 2 |
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 { +} |