summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/reference/reference.verb.tex289
-rw-r--r--sources/scalac/ast/TreeInfo.java4
-rw-r--r--sources/scalac/ast/parser/Parser.java119
-rw-r--r--sources/scalac/ast/parser/Scanner.java3
-rw-r--r--sources/scalac/symtab/SourceCompleter.java2
-rw-r--r--sources/scalac/symtab/Symbol.java17
-rw-r--r--sources/scalac/typechecker/Analyzer.java42
-rw-r--r--sources/scalac/typechecker/DeSugarize.java16
-rw-r--r--sources/scalac/typechecker/RefCheck.java7
-rw-r--r--test/files/neg/S4.check4
-rw-r--r--test/files/neg/bug38.check7
-rw-r--r--test/files/neg/constrparams.check11
-rw-r--r--test/files/neg/vincent1.check4
-rw-r--r--test/neg/S4.check4
-rw-r--r--test/neg/bug38.check7
-rw-r--r--test/neg/constrparams.check11
-rw-r--r--test/neg/vincent1.check4
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 } =
^