diff options
author | Martin Odersky <odersky@gmail.com> | 2003-07-16 10:49:15 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2003-07-16 10:49:15 +0000 |
commit | 0a0595a1c73b956f8582879d518c75970b910c23 (patch) | |
tree | 5bffa1f28df8a5cb2b7451c18fc3a9acf85c3722 | |
parent | 9aaa79cdba130a6e22e9b761d5a1f78720a2a180 (diff) | |
download | scala-0a0595a1c73b956f8582879d518c75970b910c23.tar.gz scala-0a0595a1c73b956f8582879d518c75970b910c23.tar.bz2 scala-0a0595a1c73b956f8582879d518c75970b910c23.zip |
*** empty log message ***
-rw-r--r-- | doc/reference/reference.verb.tex | 289 | ||||
-rw-r--r-- | sources/scalac/ast/TreeInfo.java | 4 | ||||
-rw-r--r-- | sources/scalac/ast/parser/Parser.java | 119 | ||||
-rw-r--r-- | sources/scalac/ast/parser/Scanner.java | 3 | ||||
-rw-r--r-- | sources/scalac/symtab/SourceCompleter.java | 2 | ||||
-rw-r--r-- | sources/scalac/symtab/Symbol.java | 17 | ||||
-rw-r--r-- | sources/scalac/typechecker/Analyzer.java | 42 | ||||
-rw-r--r-- | sources/scalac/typechecker/DeSugarize.java | 16 | ||||
-rw-r--r-- | sources/scalac/typechecker/RefCheck.java | 7 | ||||
-rw-r--r-- | test/files/neg/S4.check | 4 | ||||
-rw-r--r-- | test/files/neg/bug38.check | 7 | ||||
-rw-r--r-- | test/files/neg/constrparams.check | 11 | ||||
-rw-r--r-- | test/files/neg/vincent1.check | 4 | ||||
-rw-r--r-- | test/neg/S4.check | 4 | ||||
-rw-r--r-- | test/neg/bug38.check | 7 | ||||
-rw-r--r-- | test/neg/constrparams.check | 11 | ||||
-rw-r--r-- | test/neg/vincent1.check | 4 |
17 files changed, 329 insertions, 222 deletions
diff --git a/doc/reference/reference.verb.tex b/doc/reference/reference.verb.tex index 571c0acbd9..7d76ab2f23 100644 --- a/doc/reference/reference.verb.tex +++ b/doc/reference/reference.verb.tex @@ -996,12 +996,10 @@ value of type \verb@p.type@ if the context requires it. Dcl \=::=\= val ValDcl {`,' ValDcl} \> |\> var VarDcl {`,' VarDcl} \> |\> def FunDcl {`,' FunDcl} - \> |\> constr ConstrDcl {`,' ConstrDcl} \> |\> type TypeDcl {`,' TypeDcl} Def \>::=\> val PatDef {`,' PatDef} \> |\> var VarDef {`,' VarDef} \> |\> def FunDef {`,' FunDef} - \> |\> constr ConstrDef {`,' ConstrDef} \> |\> type TypeDef {`,' TypeDef} \> |\> ClsDef \end{verbatim} @@ -1462,16 +1460,15 @@ constructor invocation \verb@sc@ which defines the template's {\em superclass}, constructor invocations \verb@mc$_1$ \commadots mc$_n$@ $(n \geq 0)$, which define the template's {\em mixin classes}, and a statement sequence \verb@stats@ which contains additional member -definitions for the template. The superclass of a template must be a -subtype of the superclass of each mixin class. The {\em least proper -supertype} of a template is the class type or compound type -(\sref{sec:compound-types}) consisting of its superclass and mixin -classes. +definitions for the template. Superclass and mixin classes together +are called the {\em parent classes} of a template. The superclass of +a template must be a subtype of the superclass of each mixin class. +The {\em least proper supertype} of a template is the class type or +compound type (\sref{sec:compound-types}) consisting of the its parent classes. Member definitions define new members or overwrite members in the -superclass and the mixin classes. If the template forms part of a -class definition, \verb@stats@ may also contain declarations of abstract -members. +parent classes. If the template forms part of a class definition, +\verb@stats@ may also contain declarations of abstract members. %The type of each non-private definition or declaration of a %template must be equivalent to a type which does not refer to any %private members of that template. @@ -1737,7 +1734,7 @@ that defines them. %packagings (\sref{sec:topdefs}) other than the one containing the %definition. Private members are not inherited by subclasses and they -may not override definitions in superclasses. +may not override definitions in parent classes. \verb@private@ may not be applied to abstract members, and it may not be combined in one modifier list with \verb@protected@, \verb@final@ or \verb@override@. @@ -1765,7 +1762,7 @@ overriding member is abstract. The \verb@abstract@ modifier is used in class definitions. It is mandatory if the class has abstract members, or if the class has members labelled \verb@override@ which override only abstract members -in a superclass or mixin class. Classes with \verb@abstract@ members +in a parent class. Classes with \verb@abstract@ members cannot be instantiated (\sref{sec:inst-creation}) with a constructor invocation unless followed by mixin constructors or statements which override all abstract members of the class. @@ -1819,7 +1816,8 @@ object; it is not possible for clients to create objects of class \syntax\begin{verbatim} ClsDef \=::=\= class ClassDef {`,' ClassDef} - ClassDef \=::=\= Id [TypeParamClause] [ParamClause] [`:' SimpleType] ClassTemplate + ClassDef \>::=\> Id [TypeParamClause] [ParamClause] [`:' SimpleType] + \> \> ClassTemplate {[`;'] ConstrDef} ClassTemplate \>::=\> extends Template \> |\> TemplateBody \> |\> @@ -1841,9 +1839,11 @@ called {\em polymorphic}, otherwise it is called {\em monomorphic}. \item[] \verb@ps@ is a formal parameter clause for the {\em primary constructor} of the class. The scope of a formal parameter includes -the template \verb@t@. It is illegal to define two formal parameters -with the same name. The formal parameter section \verb@(ps)@ may be omitted -in which case an empty parameter section \verb@()@ is assumed. +the template \verb@t@. However, the formal parameter may not form +part of the types of any of the parent classes or members of \verb@t@. +It is illegal to define two formal parameters with the same name. +The formal parameter section \verb@(ps)@ may be omitted in which case +an empty parameter section \verb@()@ is assumed. \item[] \verb@s@ is the {\em self type} of the class. Inside the class, the type of \verb@this@ is assumed to be \verb@s@. The self @@ -1863,41 +1863,81 @@ can be omitted, in which case \verb@{}@ is assumed. \end{itemize} This class definition defines both a type \verb@c[tps]@ and a constructor -with signature \verb@constr c[tps](ps)@ -which when applied -initializes instances of \verb@c[tps]@ type by evaluating the template \verb@t@. +which when applied to parameters conforming to typles \verb@ps@ +initializes instances of type \verb@c[tps]@ by evaluating the template \verb@t@. + +\subsection{Constructor Definitions} + +\syntax\begin{verbatim} + ConstrDef \=::=\= constr [ParamClause] `=' ConstrExpr + ConstrExpr \>::=\> this ArgumentExpr + \> |\> `{' { BlockStat `;' } ConstrExpr `}' +\end{verbatim} + +A class definition may be followed by additional constructor +definitions. Each of these takes the form \verb@constr (ps) = e@. +This defines an additional constructor for the preceding class, with +parameters as given in the formal parameter list \verb@ps@, and whose +evaluation is defined by the constructor expression \verb@e@. The +formal parameter list \verb@(ps)@ may be omitted, in which case +\verb@()@ is assumed. The scope of each formal parameter is the +constructor expression \verb@e@. A constructor expression is either a +self constructor invocation \verb@this(args)@ or a block which ends in +a constructor expression. + +If there are auxilary constructors of a class \verb@C@, they define +together with \verb@C@'s primary constructor an overloaded constructor +value. The usual rules for overloading resolution +\sref{sec:overloading} apply for constructor invocations of \verb@C@, +including the self constructor invocations in the constructor +expressions themselves. To prevent infinite cycles of constructor +invocations there is the restriction that every self constructor +invocation must refer to a constructor definition which precedes it +(i.e. it must refer to either a preceding auxiliary constructor or the +primary constructor of the class). The type of a constructor +expression must be always so that a generic instance of the class is +constructed. I.e. if the class in question has name \verb@C@ and type +parameters \verb@[tps]@, then each constructor must construct an +instance of \verb@C[tps]@; it is not permitted to instantiate formal +type parameters. \subsection{Case Classes} \label{sec:case-classes} -\syntax\begin{verbatim} - ClsDef \=::=\= case class ClassDef {`,' ClassDef} +\syntax\begin{verbatim} ClsDef \=::=\= case class ClassDef {`,' + ClassDef} \end{verbatim} If a class definition is prefixed with \verb@case@, the class is said to be a {\em case class}. The primary constructor of a case class may -be used in a constructor pattern (\sref{sec:patterns}). None of the -base classes of a case class may be a case class. Furthermore, no type -may have two different case classes among its basetypes. +be used in a constructor pattern (\sref{sec:patterns}). That +constructor make not have any value parameters which are prefixed by +\verb@def@. None of the base classes of a case class may be a case +class. Furthermore, no type may have two different case classes among +its basetypes. A case class definition of \verb@c[tps](ps)@ with type parameters \verb@tps@ and value parameters \verb@ps@ implicitly -generates the function definition +generates the a function definition of a {\em case class factory} \begin{verbatim} def c[tps](ps): c[tps] = new c[tps](ps) \end{verbatim} -together with the class definition itself. Also implicity defined are -accessor member definitions in the class that return its value -parameters. Every binding \verb@x: T@ in the parameter section leads -to a value definition of \verb@x@ that defines \verb@x@ -to be an alias of the parameter. Every parameterless function binding -\verb@def x: T@ leads to a parameterless function definition of -\verb@x@ which returns the result of invoking the parameter function. -The case class may not contain a directly bound member with the same -simple name as one of its value parameters. +together with the class definition itself (if a type parameter section +is missing in the class, it is also missing in the factory +definition). Also implicity defined are accessor member definitions +in the class that return its value parameters. Every binding +\verb@x: T@ in the parameter section leads to a value definition of +\verb@x@ that defines \verb@x@ to be an alias of the parameter. +%Every +%parameterless function binding \verb@def x: T@ leads to a +%parameterless function definition of \verb@x@ which returns the result +%of invoking the parameter function. +%The case class may not contain a +%directly bound member with the same simple name as one of its value +%parameters. Every case class implicitly overrides some method definitions of class -\verb@Object@ (\sref{sec:cls-object}) unless a definition of the same +\verb@scala.Object@ (\sref{sec:cls-object}) unless a definition of the same method is already given in the case class itself or a non-abstract definition of the same method is given in some base class of the case class different from \verb@Object@. In particular: @@ -1918,9 +1958,9 @@ calculus: \begin{verbatim} class Expr; case class - Var (x: String) extends Expr, - Apply (f: Expr, e: Expr) extends Expr, - Lambda (x: String, e: Expr) extends Expr; + Var \=(x: String) \=extends Expr, + Apply \>(f: Expr, e: Expr) \>extends Expr, + Lambda \>(x: String, e: Expr) \>extends Expr; \end{verbatim} This defines a class \verb@Expr@ with case classes \verb@Var@, \verb@Apply@ and \verb@Lambda@. A call-by-value evaluator for lambda @@ -1948,119 +1988,132 @@ It is possible to define further case classes that extend type case class Number(x: Int) extends Expr; \end{verbatim} -This form of extensibility can be excluded by declaring the case class \verb@sealed@; in this case, only +This form of extensibility can be excluded by declaring the base class +\verb@Expr@ \verb@sealed@; in this case, the only classes permitted to +extend \verb@Expr@ are those which are nested inside \verb@Expr@, or +which appear in the same statement sequence as the definition of +\verb@Expr@. -\section{Interface Classes} +\section{Traits} -\label{sec:interfaces} +\label{sec:traits} \syntax\begin{verbatim} - ClassDef \=::= \= Id [TypeParamClause] ClassTemplate + ClsDef \=::=\= trait ClassDef {`,' ClassDef} \end{verbatim} -A class definition whose constructor does not have value parameters -defines an {\em interface class}. The template of an interface classes -must satisfy the following two restrictions. +A class definition which starts with the reserved word \verb@trait@ +instead of \verb@class@ defines a trait. A trait is a specific +instance of an abstract class, so the \verb@abstract@ modifier is +redundant for it. The template of a trait must satisfy the following +four restrictions. \begin{enumerate} -\item All base classes of the template are interface classes. -\item All non-empty statements are either declarations or method definitions. +\item All base classes of the trait are traits. +\item All parent class constructors of a template + must be primary constructors with empty value + parameter lists. +\item None of the statements in the template may be a variable definition. +\item For every value definition \verb@val x: T = e@ among the statements + of the template, the defining expression \verb@e@ must {\em pure}. \end{enumerate} +A pure expression is a literal, or an occurrence of \verb@this@, +or a stable identifier, or a typed expression \verb@e: T@ where +\verb@e@ is a pure expression. + These restrictions ensure that the evaluation of the mixin constructor -of an interface type has no effect. Therefore, interface classes can be -used in two constellations where other classes cannot. Namely: -\begin{itemize} -\item The same interface class may appear several times in the base class -sequence of a template. -\item Packagings may add interface classes as new base classes to an -existing class or modulee. -\end{itemize} +of a trait has no effect. Therefore, traits may appear several times +in the base class sequence of a template, whereas other classes cannot. +%\item Packagings may add interface classes as new base classes to an +%existing class or modulee. \example\label{ex:comparable} -The following interface class defines the property of being -comparable to objects of some type. It contains an abstract method +The following trait class defines the property of being +ordered, i.e. comparable to objects of some type. It contains an abstract method \verb@<@ and default implementations of the other comparison operators \verb@<=@, \verb@>@, and \verb@>=@. \begin{verbatim} -abstract class Comparable[a] with { - def <(that: a) - def <= (that: a) = this < that || this == that - def > (that: a) = that < this - def >= (that: a) = that <= this +trait Ord[t <: Ord[t]]: t { + def < (that: t): Boolean; + def <=(that: t): Boolean = this < that || this == that; + def > (that: t): Boolean = that < this; + def >=(that: t): Boolean = that <= this; } \end{verbatim} -\section{Modules} +\section{Object Definitions} \label{sec:modules} +\label{sec:object-defs} \syntax\begin{verbatim} - ModuleDef \=::= \= Id [`:' Type] ClassTemplate + ObjectDef \=::=\= Id [`:' SimpleType] ClassTemplate \end{verbatim} -A module definition is of the form \verb@\MODULE;m;\EXTENDS;t@ where \verb@t@ is -a template (\sref{sec:templates}) -\verb@sc;\WITH;mc_1;\WITH;\ldots;\WITH;mc_n;\WITH;(stats)@. The extends -clause \verb@\EXTENDS;sc@ can be omitted, in which case -\verb@extends scala.Object@ is assumed. -The module body \verb@\WITH;(stats)@ may also be omitted, in which case the -empty body \verb@\WITH;\{\}@ is assumed. - -The module definition defines a single object conforming to the -template \verb@t@. It is almost equivalent to a triple of a class -definition, -a type definition and a value definition that creates an object of the class: +An object definition defines a single object of a new class. Its +most general is +\verb@object m: s extends t@. Here, +\begin{itemize} +\item[] +\verb@m@ is the name of the object to be defined. +\item[] \verb@s@ is the {\em self type} of the object. References to +\verb@m@ are assumed to have type \verb@s@. Furthermore, inside the +template \verb@t@, the type of \verb@this@ is also assumed to be \verb@s@. +The self type must conform to the self types of all classes which are +inherited by the template \verb@t@. The self type declaration +\verb@:s@ may be omitted, in which case the self type of the class is +assumed to be equal to the anonymous class defined by \verb@t@. +\item[] +\verb@t@ is a +template (\sref{sec:templates}) of the form +\verb@sc with mc$_1$ with ... with mc$_n$ { stats }@ +which defines the base classes, behavior and initial state of \verb@m@. +The extends clause \verb@extends sc with ... with mc$_n$@ +can be omitted, in which case +\verb@extends scala.Object@ is assumed. The class body +\verb@{stats}@ may also be omitted, in which case the empty body +\verb@{}@ is assumed. +\end{itemize} +The object definition defines a single object (or: {\em module} +conforming to the template \verb@t@. It is almost equivalent to a class +definition and a value definition that creates an object of the class: \begin{verbatim} -final class m$\Dollar$class extends t; -final type m = m$\Dollar$class; -final val m = new m$\Dollar$class; +final class m$\Dollar$class: s extends t; +final val m: s = new m$\Dollar$class; \end{verbatim} (The \verb@final@ modifiers are omitted if the definition occurs as -part of a block). The class name \verb@m$\Dollar$class@ is not +part of a block). The class name \verb@m$\Dollar$class@ is not accessible for user programs. -However, unlike value definitions, modules are instantiated lazily. +Unlike value definitions, object definitions may appear +as top-level definitions in a compilation unit. +Also, unlike for value definitions, modules are instantiated lazily. The \verb@new m$\Dollar$class@ constructor is evaluated not at the -point of the let definition, but is instead evaluated the first time +point of the value definition, but is instead evaluated the first time $m$ is dereferenced during execution of the program (which might be never at all). An attempt to dereference $m$ again in the course of -evaluation of the constructor leads to a run-time error. Other +evaluation of the constructor leads to a infinite loop or run-time error. +Other threads trying to dereference $m$ while the constructor is being evaluated block until evaluation is complete. -A module definition may also mention a type $T$ which represents the -externally visible interface of a module. The definition $\MODULE;m: -T;\EXTENDS;t$ then corresponds to: -\begin{verbatim} -final class m$\Dollar$class extends t; -final type m = m$\Dollar$class; -final val m: T = new m$\Dollar$class; -\end{verbatim} - \example Classes in Scala do not have static members; however, an equivalent -effect can be achieved by defining a module: +effect can be achieved by an accompanying object definition E.g. \begin{verbatim} -module Points with { - abstract class Point() with { - val x: Double; - val y: Double; - def isOrigin = x == 0,0 && y == 0.0; - } +abstract class Point { + val x: Double; + val y: Double; + def isOrigin = (x == 0.0 && y == 0.0); +} +object Point { val origin = new Point() with { val x = 0.0, y = 0.0 } } -type Point = Points.Point -def Point(): class Point = Points.Point() -val Point = Points -\end{verbatim} -This defines a type \verb@Point@, a constructor \verb@Point@, and a -value \verb@Point@ which contains \verb@origin@ as a member. Hence, -Note that the double definition of \verb@Point@ in the term namespace -is a legal overloaded definition (\sref{sec:overloaded-defs}), since -\verb@Point@ exists both as a unary constructor function and as a -value. Therefore the name \verb@Point@ used in isolation identifies -the \verb@Point@ module, the expression \verb@Point.origin@ selects -its \verb@origin@ field, but \verb@new Point()@ is an invocation of -the \verb@Point@ constructor. +\end{verbatim} +This defines a type \verb@Point@, a constructor \verb@Point()@, and an +object \verb@Point@ which contains \verb@origin@ as a member. +Note that the double use of the name \verb@Point@ is lgel, since the class +definition defines the name \verb@Point@ in the type and constructor name spaces, +whereas the object definition defines a name only in the term namespace. \comment{ \example Here's an outline of a module definition for a file system. @@ -4195,8 +4248,6 @@ grammar. CaseClause \>::=\> case Pattern [`if' PostfixExpr] `=>' Block Constr \>::=\> StableId [TypeArgs] [`(' [Exprs] `)'] - ConstrExpr \>::=\> this [ArgumentExpr] - \> |\> `{' {BlockStat `;'} this [ArgumentExpr] `}' Pattern \>::=\> varid `:' Type1 \> |\> `_' `:' Type1 @@ -4244,33 +4295,33 @@ grammar. Dcl \>::=\> val ValDcl {`,' ValDcl} \> |\> var VarDcl {`,' VarDcl} \> |\> def FunDcl {`,' FunDcl} - \> |\> constr ConstrDcl {`,' ConstrDcl} \> |\> type TypeDcl {`,' TypeDcl} ValDcl \>::=\> Id `:' Type VarDcl \>::=\> Id `:' Type FunDcl \>::=\> Id [FunTypeParamClause] {ParamClause} `:' Type - ConstrDcl \>::=\> Id [FunTypeParamClause] [ParamClause] `:' Type TypeDcl \>::=\> Id [`>:' Type] [`<:' Type] Def \>::=\> val PatDef {`,' PatDef} \> |\> var VarDef {`,' VarDef} \> |\> def FunDef {`,' FunDef} - \> |\> constr ConstrDef {`,' ConstrDef} \> |\> type TypeDef {`,' TypeDef} \> |\> ClsDef PatDef \>::=\> Pattern `=' Expr VarDef \>::=\> Id [`:' Type] `=' Expr \> |\> Id `:' Type `=' `_' FunDef \>::=\> Id [FunTypeParamClause] {ParamClause} [`:' Type] `=' Expr - ConstrDef \>::=\> this [ParamClause] `=' ConstrExpr TypeDef \>::=\> Id `=' Type ClsDef \>::=\> ([case] class | trait) ClassDef {`,' ClassDef} \> |\> [case] object ObjectDef {`,' ObjectDef} - ClassDef \>::=\> Id [TypeParamClause] [ParamClause] [`:' SimpleType] ClassTemplate + ClassDef \>::=\> Id [TypeParamClause] [ParamClause] [`:' SimpleType] + \> \> ClassTemplate {[`;'] ConstrDef} ObjectDef \>::=\> Id [`:' SimpleType] ClassTemplate ClassTemplate \>::=\> extends Template \> |\> TemplateBody \> |\> + ConstrDef \>::=\> constr [ParamClause] `=' ConstrExpr + ConstrExpr \>::=\> this ArgumentExpr + \> |\> `{' { BlockStat `;' } ConstrExpr `}' CompilationUnit \>::=\> [package QualId `;'] [{TopStat `;'} TopStat] TopStat \>::=\> {Modifier} ClsDef diff --git a/sources/scalac/ast/TreeInfo.java b/sources/scalac/ast/TreeInfo.java index f79a5765a5..9721afb447 100644 --- a/sources/scalac/ast/TreeInfo.java +++ b/sources/scalac/ast/TreeInfo.java @@ -112,10 +112,8 @@ public class TreeInfo { public static boolean isPureConstr(Tree tree) { switch (tree) { case Ident(_): + case Select(_, _): return tree.symbol() != null && tree.symbol().isPrimaryConstructor(); - case Select(Tree qual, _): - return isPureExpr(qual) && - tree.symbol() != null && tree.symbol().isPrimaryConstructor(); case TypeApply(Tree constr, _): return isPureConstr(constr); case Apply(Tree fn, Tree[] args): diff --git a/sources/scalac/ast/parser/Parser.java b/sources/scalac/ast/parser/Parser.java index 6c5356ebbb..b5aa598f23 100644 --- a/sources/scalac/ast/parser/Parser.java +++ b/sources/scalac/ast/parser/Parser.java @@ -369,10 +369,6 @@ public class Parser implements Tokens { */ Tree convertToConstr(Tree t) { switch (t) { - case Apply(Tree fn, Tree[] args): - return make.Apply(t.pos, convertToConstr(fn), args); - case TypeApply(Tree fn, Tree[] args): - return make.TypeApply(t.pos, convertToConstr(fn), args); case Ident(Name name): return make.Ident(t.pos, name.toConstrName()); case Select(Tree qual, Name name): @@ -382,6 +378,27 @@ public class Parser implements Tokens { } } + /** Convert this(...) application to constructor invocation + */ + Tree convertToSelfConstr(Tree t, Name constrname) { + switch (t) { + case Block(Tree[] stats): + if (stats.length > 0) { + stats[stats.length - 1] = convertToSelfConstr( + stats[stats.length - 1], constrname); + return t; + } + break; + case Apply(Tree fn, Tree[] args): + switch (fn) { + case This(Tree.Empty): + return make.Apply( + t.pos, make.Ident(t.pos, constrname), args); + } + } + return syntaxError(t.pos, "class constructor expected", false); + } + /** Complete unapplied constructor with `()' arguments */ Tree applyConstr(Tree t) { @@ -994,31 +1011,6 @@ public class Parser implements Tokens { return res; } - /** ConstrExpr ::= Constr - * | `{' {BlockStat `;'} Constr `}' - */ - Tree constrExpr() { - if (s.token == LBRACE) { - int pos = s.skipToken(); - Tree res = block(pos); - switch (res) { - case Block(Tree[] stats): - if (stats.length > 0) - stats[stats.length - 1] = applyConstr( - convertToConstr(stats[stats.length - 1])); - else - syntaxError(res.pos, "class constructor expected", false); - break; - default: - res = applyConstr(convertToConstr(res)); - } - accept(RBRACE); - return res; - } else { - return constr(); - } - } - /** Block ::= BlockStatSeq */ Tree block(int pos) { @@ -1177,7 +1169,7 @@ public class Parser implements Tokens { make.Sequence(s.pos, Tree.EMPTY_ARRAY)})); } } - while ((s.token == IDENTIFIER)&&( s.name != BAR )) { + while ((s.token == IDENTIFIER) && (s.name != BAR)) { top = reduceStack( false, base, top, s.name.precedence(), s.name.isLeftAssoc()); push(top, s.pos, s.name); @@ -1341,6 +1333,13 @@ public class Parser implements Tokens { return (ValDef[][])ts.toArray(new ValDef[ts.size()][]); } + /** ParamClauseOpt ::= [ParamClause] + */ + ValDef[][] paramClauseOpt() { + return (s.token == LPAREN) ? new ValDef[][]{paramClause()} + : Tree.ValDef_EMPTY_ARRAY_ARRAY; + } + /** ParamClause ::= `(' [Param {`,' Param}] `)' */ ValDef[] paramClause() { @@ -1535,7 +1534,6 @@ public class Parser implements Tokens { /** Def ::= val PatDef {`,' PatDef} * | var VarDef {`,' VarDef} * | def FunDef {`,' FunDef} - * | constr ConstrDef {`,' ConstrDef} * | type TypeDef {`,' TypeDef} * | ClsDef * Dcl ::= val ValDcl {`,' ValDcl} @@ -1565,12 +1563,6 @@ public class Parser implements Tokens { ts.append(funDefOrDcl(mods)); } while (s.token == COMMA); return ts.toArray(); - case CONSTR: - do { - s.nextToken(); - ts.append(constrDefOrDcl(mods)); - } while (s.token == COMMA); - return ts.toArray(); case TYPE: do { s.nextToken(); @@ -1678,23 +1670,25 @@ public class Parser implements Tokens { tparams, vparams, restype, Tree.Empty); } - /* ConstrDef ::= Id [FunTypeParamClause] [ParamClause] [`:' Type] `=' ConstrExpr + /* ConstrDef ::= [ParamClause] `=' ConstrExpr + * ConstrExpr ::= this `(' [Exprs] `)' + * | `{' { BlockStat `;' } ConstrExpr `}' */ - Tree constrDefOrDcl(int mods) { + Tree constrDef(int mods, Name clazzname, TypeDef[] tparams) { + Name constrname = clazzname.toConstrName(); int pos = s.pos; - Name name = ident().toConstrName(); - TypeDef[] tparams = typeParamClauseOpt(false); - ValDef[][] vparams = new ValDef[][]{paramClause()}; - Tree restype = typedOpt(); - if (s.token == EQUALS || restype == Tree.Empty) { - accept(EQUALS); - return make.DefDef( - pos, mods | Modifiers.FINAL, name, - tparams, vparams, restype, constrExpr()); - } else - return make.DefDef( - pos, mods | Modifiers.FINAL | Modifiers.DEFERRED, name, - tparams, vparams, restype, Tree.Empty); + ValDef[][] vparams = paramClauseOpt(); + accept(EQUALS); + Tree restype = make.Ident(pos, clazzname.toTypeName()); + if (tparams.length != 0) { + Tree[] targs = new Tree[tparams.length]; + for (int i = 0; i < tparams.length; i++) + targs[i] = make.Ident(pos, ((TypeDef) tparams[i]).name); + restype = make.AppliedType(pos, restype, targs); + } + return make.DefDef( + pos, mods | Modifiers.FINAL, constrname, + tparams, vparams, restype, convertToSelfConstr(expr(), constrname)); } /** TypeDef ::= Id `=' Type @@ -1718,16 +1712,23 @@ public class Parser implements Tokens { } } - /** ClassDef ::= Id [TypeParamClause] [ParamClause] [`:' SimpleType] ClassTemplate + /** ClassDef ::= Id [TypeParamClause] [ParamClause] [`:' SimpleType] + * ClassTemplate { [`;'] constr ConstrDef } */ - Tree classDef(int mods) { + Tree[] classDef(int mods) { int pos = s.pos; - Name name = ident(); + Name clazzname = ident().toTypeName(); TypeDef[] tparams = typeParamClauseOpt(true); - ValDef[][] params = (s.token == LPAREN) ? new ValDef[][]{paramClause()} - : Tree.ValDef_EMPTY_ARRAY_ARRAY; - return make.ClassDef(pos, mods, name.toTypeName(), tparams, params, - simpleTypedOpt(), classTemplate()); + ValDef[][] params = paramClauseOpt(); + TreeList result = new TreeList(); + result.append( + make.ClassDef(pos, mods, clazzname, tparams, params, + simpleTypedOpt(), classTemplate())); + while (s.token == CONSTR) { + s.nextToken(); + result.append(constrDef(mods, clazzname, tparams)); + } + return result.toArray(); } /** ObjectDef ::= Id [`:' SimpleType] ClassTemplate diff --git a/sources/scalac/ast/parser/Scanner.java b/sources/scalac/ast/parser/Scanner.java index da022bd953..bc153c869f 100644 --- a/sources/scalac/ast/parser/Scanner.java +++ b/sources/scalac/ast/parser/Scanner.java @@ -114,6 +114,7 @@ public class Scanner extends TokenData { int prevpos = pos; fetchToken(); switch (token) { + case CONSTR: case ELSE: case EXTENDS: case WITH: case YIELD: case CATCH: case FINALLY: case COMMA: case SEMI: case DOT: @@ -152,7 +153,7 @@ public class Scanner extends TokenData { } else if (token == SEMI) { prev.copyFrom(this); fetchToken(); - if (token != ELSE) { + if (token != ELSE || token == CONSTR) { next.copyFrom(this); this.copyFrom(prev); } diff --git a/sources/scalac/symtab/SourceCompleter.java b/sources/scalac/symtab/SourceCompleter.java index 9475e79ffe..1fe722abac 100644 --- a/sources/scalac/symtab/SourceCompleter.java +++ b/sources/scalac/symtab/SourceCompleter.java @@ -33,7 +33,7 @@ public class SourceCompleter extends Type.LazyType { */ public void complete(Symbol c) { if (completed) { - c.setInfo(Type.ErrorType); + c.setInfo(Type.NoType); } else if (filename != null) { try { String fname = filename; diff --git a/sources/scalac/symtab/Symbol.java b/sources/scalac/symtab/Symbol.java index a67669075a..f6466931d7 100644 --- a/sources/scalac/symtab/Symbol.java +++ b/sources/scalac/symtab/Symbol.java @@ -187,8 +187,7 @@ public abstract class Symbol implements Modifiers, Kinds { public final boolean isStable() { return kind == VAL && ((flags & STABLE) != 0 || - (flags & MUTABLE) == 0 && type().isObjectType()) && - !owner.isPrimaryConstructor(); + (flags & MUTABLE) == 0 && type().isObjectType()); } /** Does this symbol denote a variable? */ @@ -560,13 +559,13 @@ public abstract class Symbol implements Modifiers, Kinds { info.complete(this); flags = flags & ~LOCKED; if (info instanceof SourceCompleter && (flags & SNDTIME) == 0) { - flags |= SNDTIME; - Type tp = info(); - flags &= ~SNDTIME; - } else { - assert !(rawInfoAt(id) instanceof Type.LazyType) : this; - flags |= INITIALIZED; - } + flags |= SNDTIME; + Type tp = info(); + flags &= ~SNDTIME; + } else { + assert !(rawInfoAt(id) instanceof Type.LazyType) : this; + flags |= INITIALIZED; + } //System.out.println("done: " + this.name);//DEBUG } return rawInfoAt(id); diff --git a/sources/scalac/typechecker/Analyzer.java b/sources/scalac/typechecker/Analyzer.java index fb903640aa..5ddd9b9d5a 100644 --- a/sources/scalac/typechecker/Analyzer.java +++ b/sources/scalac/typechecker/Analyzer.java @@ -11,9 +11,7 @@ // todo: use SELECTOR flag to avoid access methods for privates // todo: use mangled name or drop. // todo: emit warnings for unchecked. -// todo: qualified super. -// todo: pattern definitions with 0 or 1 bound variable. -// todo: phase sync +// todo: synchronize on module instantiation. package scalac.typechecker; @@ -417,6 +415,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { error(pos, "cyclic aliasing or subtyping involving " + sym); } else if (sym.kind == ALIAS || sym.kind == TYPE) { sym.flags |= LOCKED; + //System.out.println("checking " + sym);//DEBUG checkNonCyclic( pos, pre.memberInfo(sym).subst(sym.typeParams(), args)); if (sym.kind == TYPE) @@ -444,7 +443,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { try { return checkNoEscapeMap.apply(tp); } catch (Type.Error ex) { - if (infer.isFullyDefined(pt)) return pt; + if ((mode & EXPRmode) != 0 && infer.isFullyDefined(pt)) return pt; error(pos, ex.msg + " as part of " + tp.unalias()); return Type.ErrorType; } @@ -612,14 +611,17 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { Symbol constr = tree.symbol().constructor(); Type constrtype = constr.type().instanceType(); constrtype = constrtype.cloneType(constr, sym); + /* todo: remove switch (tree) { case ClassDef(_, _, _, ValDef[][] vparams, _, _): if (vparams.length == 0) { constrtype = removeMethod(constrtype); } } + */ sym.setInfo(constrtype); } + /* todo: remove private Type removeMethod(Type tp) { switch (tp) { case MethodType(_, Type restp): @@ -630,6 +632,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { return tp; } } + */ } /** A lazy type for self types @@ -707,9 +710,12 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { enterSym(tree, clazz.constructor()); if ((mods & CASE) != 0) { + /* todo: remove if (vparams.length == 0) { error(tree.pos, "case class needs () parameter section"); - } else if ((mods & ABSTRACTCLASS) == 0) { + } + else */ + if ((mods & ABSTRACTCLASS) == 0) { // enter case constructor method. enterInScope( new TermSymbol( @@ -964,8 +970,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { 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); + ((DefDef) tree).rhs = rhs = transform(rhs, EXPRmode); ((DefDef) tree).tpe = tpe = gen.mkType(tree.pos, rhs.type); } Type restype = checkNoEscape(tpe.pos, tpe.type); @@ -1002,7 +1007,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { tp.lookup(selectors[i]) == Symbol.NONE && tp.lookup(selectors[i].toTypeName()) == Symbol.NONE && tp.lookup(selectors[i].toConstrName()) == Symbol.NONE) - error(tree.pos, selectors[i] + " is not a member of " + expr); + error(tree.pos, NameTransformer.decode(selectors[i]) + " is not a member of " + expr); } break; @@ -1317,6 +1322,8 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { checkAccessible(tree.pos, sym, qual); } symtype = pre.memberType(sym); + if (symtype == Type.NoType) + return error(tree.pos, "not found: " + decode(name)); if ((pt != null && pt.isStable() || (mode & QUALmode) != 0) && sym.isStable()) { //System.out.println("making single " + sym + ":" + symtype);//DEBUG symtype = Type.singleType(pre, sym); @@ -1346,6 +1353,8 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { if (!TreeInfo.isSelf(qual, context.enclClass.owner)) sym.flags |= SELECTOR; Type symtype = qual.type.memberType(sym); + if (symtype == Type.NoType) + return error(tree.pos, "not found: " + decode(name)); //System.out.println(sym.name + ":" + symtype);//DEBUG if (uninst.length != 0) { switch (symtype) { @@ -1370,7 +1379,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { * results. */ Tree transformVisitor(Tree tree, Type pattpe, Type pt) { - //System.out.println("trans visitor with " + pt);//DEBUG + //System.out.println("trans visitor with " + pattpe + "," + pt);//DEBUG switch (tree) { case Visitor(Tree.CaseDef[] cases): Tree.CaseDef[] cases1 = cases; @@ -1569,6 +1578,13 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { } return transformArgs(pos, meth, tparams2, restp, argMode, args, pt); + case Type.ErrorType: + for (int i = 0; i < args.length; i++) { + args[i] = transform(args[i], argMode, Type.ErrorType); + argtypes[i] = args[i].type; + } + return argtypes; + default: for (int i = 0; i < args.length; i++) { args[i] = transform(args[i], argMode, Type.AnyType); @@ -1590,6 +1606,8 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { this.pt = pt; Tree tree1 = adapt(transform(tree), mode, pt); + assert tree.type != Type.AnyType : tree;//debug + //new TextTreePrinter().print(tree1).print(": " + tree1.type).println().end();//DEBUG this.mode = savedMode; @@ -1670,6 +1688,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { Tree.ValDef[][] vparams1 = transform(vparams); Tree tpe1 = transform(tpe); Tree.Template templ1 = transformTemplate(templ, sym); + checkNoEscape(tree.pos, sym.info()); popContext(); return copy.ClassDef(tree, sym, tparams1, vparams1, tpe1, templ1) .setType(definitions.UNIT_TYPE); @@ -1683,7 +1702,10 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { Tree rhs1 = rhs; if (rhs != Tree.Empty) { pushContext(tree, sym, context.scope); - rhs1 = transform(rhs, EXPRmode, tpe.type); + if ((sym.flags & CASEACCESSOR) != 0) + rhs1.type = rhs1.symbol().type(); + else + rhs1 = transform(rhs, EXPRmode, tpe.type); popContext(); } sym.flags |= LOCKED; diff --git a/sources/scalac/typechecker/DeSugarize.java b/sources/scalac/typechecker/DeSugarize.java index 58b40ec390..defc49f470 100644 --- a/sources/scalac/typechecker/DeSugarize.java +++ b/sources/scalac/typechecker/DeSugarize.java @@ -96,6 +96,10 @@ public class DeSugarize implements Kinds, Modifiers { for (int i = 0; i < args.length; i++) getVariables(args[i], vars); break; + case Sequence(Tree[] elems): + for (int i = 0; i < elems.length; i++) + getVariables(elems[i], vars); + break; default: throw new ApplicationError ("illegal pattern", tree); } @@ -474,11 +478,13 @@ public class DeSugarize implements Kinds, Modifiers { if (vars.length == 0) { // e.match (case p => ()) + print(pat, "patdef", match); return new Tree[]{match}; } else if (vars.length == 1) { // val x_1 = e.match (case p => x_1) - return new Tree[]{ - make.ValDef(pos, mods, vars[0], Tree.Empty, match)}; + Tree valdef = make.ValDef(pos, mods, vars[0], Tree.Empty, match); + print(pat, "patdef", valdef); + return new Tree[]{valdef}; } else { // t$ Name var = getvar(); @@ -493,7 +499,7 @@ public class DeSugarize implements Kinds, Modifiers { pos, mods, vars[i], Tree.Empty, make.Select(pos, make.Ident(pos, var), tupleSelectorName(i + 1))); } - print(pat, " -> ", new Block(res));//debug + print(pat, "patdef", new Block(res));//debug return res; } default: @@ -684,12 +690,12 @@ public class DeSugarize implements Kinds, Modifiers { /** Build value element definition name for case parameter. */ void addCaseElement(TreeList ts, ValDef vparam) { - vparam.symbol().initialize(); + //vparam.symbol().initialize(); ts.append( make.ValDef( vparam.pos, CASEACCESSOR, vparam.name, vparam.tpe, make.Ident(vparam.pos, vparam.name) - .setSymbol(vparam.symbol()).setType(vparam.symbol().type()))); + .setSymbol(vparam.symbol()))); } /** add case constructor, value defintiions and access functions. diff --git a/sources/scalac/typechecker/RefCheck.java b/sources/scalac/typechecker/RefCheck.java index 79a3e1a015..8c8f899abd 100644 --- a/sources/scalac/typechecker/RefCheck.java +++ b/sources/scalac/typechecker/RefCheck.java @@ -27,7 +27,7 @@ import Tree.*; * * It preforms the following transformations. * - * - Local modules are replaces by variables and classes + * - Local modules are replaced 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. @@ -903,7 +903,12 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { //System.out.println("name: "+name); Scope.Entry e = scopes[level].lookupEntry(name); +<<<<<<< RefCheck.java + //System.out.println("sym: "+sym); + if (sym == null) unit.error(tree.pos, "sym is null"); +======= //System.out.println("sym: "+sym); +>>>>>>> 1.27 if (sym.isLocal() && sym == e.sym) { int i = level; while (scopes[i] != e.owner) i--; diff --git a/test/files/neg/S4.check b/test/files/neg/S4.check index 49f79ba97a..1297b6d18c 100644 --- a/test/files/neg/S4.check +++ b/test/files/neg/S4.check @@ -1,4 +1,4 @@ -S4.scala:4: stable identifier required, but a found. +S4.scala:4: type a.type escapes its defining scope as part of a.Inner { def foo(a.Inner): a.Inner, val b$: Other, def b: Other } class S4(a: Other) extends a.Inner() { - ^ + ^ one error found diff --git a/test/files/neg/bug38.check b/test/files/neg/bug38.check new file mode 100644 index 0000000000..0f0bea262b --- /dev/null +++ b/test/files/neg/bug38.check @@ -0,0 +1,7 @@ +bug38.scala:3: * is not a member of scala.xml + import scala.xml.* ; // does not work + ^ +bug38.scala:7: not found: constructor Element + val foo = new Element { def getName = "hallo"; def getChildren = Nil; def getAttribs = new HashMap[String,String] }; + ^ +two errors found diff --git a/test/files/neg/constrparams.check b/test/files/neg/constrparams.check index 19eb56bf7f..a9b7c39573 100644 --- a/test/files/neg/constrparams.check +++ b/test/files/neg/constrparams.check @@ -1,4 +1,9 @@ -constrparams.scala:4: stable identifier required, but x found. +constrparams.scala:4: type mismatch; + found : scala.AllRef + required: x.t private val z: x.t = null; //error - ^ -one error found + ^ +constrparams.scala:1: type x.type escapes its defining scope as part of scala.Object { type t, val y$: x.type, def y: x.type, val z$: x.t, def z: x.t } +abstract class C(x: C) { + ^ +two errors found diff --git a/test/files/neg/vincent1.check b/test/files/neg/vincent1.check index 32dffd2884..a9f60e9ad2 100644 --- a/test/files/neg/vincent1.check +++ b/test/files/neg/vincent1.check @@ -1,6 +1,6 @@ -vincent1.scala:7: stable identifier required, but x found. +vincent1.scala:7: type x.type escapes its defining scope as part of scala.Object { type T = x.T } class Functor(x: A) { type T = x.T } - ^ + ^ vincent1.scala:9: type x.type escapes its defining scope as part of test.B { type T = x.T } def functor(x: A): B { type T = x.T } = ^ diff --git a/test/neg/S4.check b/test/neg/S4.check index 49f79ba97a..1297b6d18c 100644 --- a/test/neg/S4.check +++ b/test/neg/S4.check @@ -1,4 +1,4 @@ -S4.scala:4: stable identifier required, but a found. +S4.scala:4: type a.type escapes its defining scope as part of a.Inner { def foo(a.Inner): a.Inner, val b$: Other, def b: Other } class S4(a: Other) extends a.Inner() { - ^ + ^ one error found diff --git a/test/neg/bug38.check b/test/neg/bug38.check new file mode 100644 index 0000000000..0f0bea262b --- /dev/null +++ b/test/neg/bug38.check @@ -0,0 +1,7 @@ +bug38.scala:3: * is not a member of scala.xml + import scala.xml.* ; // does not work + ^ +bug38.scala:7: not found: constructor Element + val foo = new Element { def getName = "hallo"; def getChildren = Nil; def getAttribs = new HashMap[String,String] }; + ^ +two errors found diff --git a/test/neg/constrparams.check b/test/neg/constrparams.check index 19eb56bf7f..a9b7c39573 100644 --- a/test/neg/constrparams.check +++ b/test/neg/constrparams.check @@ -1,4 +1,9 @@ -constrparams.scala:4: stable identifier required, but x found. +constrparams.scala:4: type mismatch; + found : scala.AllRef + required: x.t private val z: x.t = null; //error - ^ -one error found + ^ +constrparams.scala:1: type x.type escapes its defining scope as part of scala.Object { type t, val y$: x.type, def y: x.type, val z$: x.t, def z: x.t } +abstract class C(x: C) { + ^ +two errors found diff --git a/test/neg/vincent1.check b/test/neg/vincent1.check index 32dffd2884..a9f60e9ad2 100644 --- a/test/neg/vincent1.check +++ b/test/neg/vincent1.check @@ -1,6 +1,6 @@ -vincent1.scala:7: stable identifier required, but x found. +vincent1.scala:7: type x.type escapes its defining scope as part of scala.Object { type T = x.T } class Functor(x: A) { type T = x.T } - ^ + ^ vincent1.scala:9: type x.type escapes its defining scope as part of test.B { type T = x.T } def functor(x: A): B { type T = x.T } = ^ |