From 0a01a0ce97c65b3b6dba1498ba5ebf544a3f8bb9 Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Tue, 7 Jun 2022 15:45:08 +0200 Subject: [PATCH 1/8] Resolve conflict in initial comment --- specification/dartLangSpec.tex | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index 8685378a7d..86960daed4 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -42,6 +42,8 @@ % - Clarify the conflicts between extension members and `Object` instance % members. % - Correct to include metadata. +% - Clarify errors involving overrides of private members in a library where +% they are not accessible. % % 2.14 % - Add constraint on type of parameter which is covariant-by-declaration in @@ -4906,16 +4908,12 @@ \section{Interfaces} An interface has method, getter and setter signatures, and a set of superinterfaces, which are again interfaces. -Each interface is the implicit interface of a class, -in which case we call it a -\IndexCustom{class interface}{interface!class}, -or a combination of several other interfaces, -in which case we call it a -\IndexCustom{combined interface}{interface!combined}. \LMHash{}% Let $C$ be a class. -The \Index{class interface} $I$ of $C$ is the interface that declares +The +\IndexCustom{class interface}{interface!class} +$I$ of $C$ is the interface that declares a member signature derived from each instance member declared by $C$. The \Index{direct superinterfaces} of $I$ are the direct superinterfaces of $C$ From ab9b76f8bcd9a1344cc84cb8bb5b20f91e03b090 Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Tue, 7 Jun 2022 16:04:22 +0200 Subject: [PATCH 2/8] WIP --- specification/dartLangSpec.tex | 70 +--------------------------------- 1 file changed, 1 insertion(+), 69 deletions(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index 86960daed4..5d1b9c942f 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -4947,74 +4947,6 @@ \section{Interfaces} $T$ is considered to have a method named \CALL{} with signature $m$, such that the function type of $m$ is $T_0$. -\LMHash{}% -\BlindDefineSymbol{I, \List{I}{1}{k}}% -The \Index{combined interface} $I$ of a list of interfaces \List{I}{1}{k} -is the interface that declares the set of member signatures $M$, -where $M$ is determined as specified below. -The \Index{direct superinterfaces} of $I$ is the set \List{I}{1}{k}. - -\LMHash{}% -Let $M_0$ be the set of all member signatures declared by \List{I}{1}{k}. -\DefineSymbol{M} is then the smallest set satisfying the following: - -\begin{itemize} -\item For each name \id{} and library $L$ such that $M_0$ contains - a member signature named \id{} which is accessible to $L$, - let $m$ be the combined member signature named \id{} - from \List{I}{1}{k} with respect to $L$. - It is a compile-time error - if the computation of this combined member signature failed. - Otherwise, $M$ contains $m$. -\end{itemize} - -\rationale{% -Interfaces must be able to contain inaccessible member signatures, -because they may be accessible from the interfaces associated with -declarations of subtypes.% -} - -\commentary{% -For instance, class $C$ in library $L$ may declare a private member named -\code{\_foo}, -a class $D$ in a different library $L_2$ may extend $C$, -and a class $E$ in library $L$ may extend $D$; -$E$ may then declare a member that overrides \code{\_foo} from $C$, -and that override relation must be checked based on the interface of $D$. -So we cannot allow the interface of $D$ -to ``forget'' inaccessible members like \code{\_foo}. - -For conflicts the situation is even more demanding: -Classes $C_1$ and $C_2$ in library $L$ may declare private members -\code{String \_foo(int i)} and \code{int get \_foo}, -and a subtype $D_{12}$ in a different library $L_2$ may have -an \IMPLEMENTS{} clause listing both $C_1$ and $C_2$. -In that case we must report a conflict even though the conflicting -declarations are not accessible to $L_2$, -because those member signatures are then noSuchMethod forwarded -(\ref{theMethodNoSuchMethod}), -and an invocation of \code{\_foo} on an instance of $D$ in $L$ -must return an `int` according to the first member signature, -and it must return a function object according to the second one, -and an invocation of \code{\_foo(42)} -must return a \code{String} with the first member signature, and it must fail -(at compile time or, for a dynamic invocation, run time) with the second.% -} - -\rationale{% -It may not be possible to satisfy such constraints simultaneously, -and it will inevitably be a complex semantics, -so we have chosen to make it an error. -It is unfortunate that the addition of a private declaration -in one library may break existing code in a different library. -But it should be noted that the conflicts can be detected locally -in the library where the private declarations exist, -because they only arise for private members with -the same name and incompatible signatures. -Renaming that private member to anything not used in that library -will eliminate the conflict and will not break any clients.% -} - \subsection{Combined Member Signatures} \LMLabel{combinedMemberSignatures} @@ -5060,7 +4992,7 @@ \subsection{Combined Member Signatures} \FunctionTypeSimple{\DYNAMIC}{} and \FunctionTypeSimple{\code{Object}}{} are not equal, even though they are subtypes of each other. We need this distinction because management of top type discrepancies is -one of the purposes of computing a combined interface.% +one of the purposes of computing combined member signatures.% } \LMHash{}% From 18156f147b460b70cf25d90f5081e6c8bb7dd5e3 Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Tue, 7 Jun 2022 17:05:19 +0200 Subject: [PATCH 3/8] Moved the "correct override" rule from "Instance Methods" to "Classes" --- specification/dartLangSpec.tex | 120 ++++++++++++++++----------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index 5d1b9c942f..f2a47336aa 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -2573,6 +2573,66 @@ \section{Classes} \} \end{dartCode} +\LMHash{}% +\BlindDefineSymbol{C, D, m}% +Consider a class $C$ +and an instance member declaration $D$ in $C$, with member signature $m$ +(\ref{interfaces}). +It is a compile-time error if $D$ overrides a declaration +% Note that $m'$ is accessible, due to the definition of `overrides'. +with member signature $m'$ +from a direct superinterface of $C$ +(\ref{interfaceInheritanceAndOverriding}), +unless $m$ is a correct member override of $m'$ +(\ref{correctMemberOverrides}). + +\commentary{% +This is not the only kind of conflict that may exist: +An instance member declaration $D$ may conflict with another declaration $D'$, +even in the case where they do not have the same name +or they are not the same kind of declaration. +E.g., $D$ could be an instance getter and $D'$ a static setter +(\ref{classMemberConflicts}).% +} + +\LMHash{}% +For each parameter $p$ of $m$ where \COVARIANT{} is present, +it is a compile-time error if there exists +a direct or indirect superinterface of $C$ which has +an accessible method signature $m''$ with the same name as $m$, +such that $m''$ has a parameter $p''$ that corresponds to $p$ +(\ref{covariantParameters}), +unless the type of $p$ is a subtype or a supertype of the type of $p''$. + +\commentary{% +This means that +a parameter which is covariant-by-declaration can have a type +which is a supertype or a subtype of the type of +a corresponding parameter in a superinterface, +but the two types cannot be unrelated. +Note that this requirement must be satisfied +for each direct or indirect superinterface separately, +because that relationship is not transitive.% +} + +\rationale{% +The superinterface may be the statically known type of the receiver, +so this means that we relax the potential typing relationship +between the statically known type of a parameter and the +type which is actually required at run time +to the subtype-or-supertype relationship, +rather than the strict supertype relationship +which applies to a parameter which is not covariant. +It should be noted that it is not statically known +at the call site whether any given parameter is covariant, +because the covariance could be introduced in +a proper subtype of the statically known type of the receiver. +We chose to give priority to flexibility rather than safety here, +because the whole point of covariant parameters is that developers +can make the choice to increase the flexibility +in a trade-off where some static type safety is lost.% +} + \subsection{Fully Implementing an Interface} \LMLabel{fullyImplementingAnInterface} @@ -2716,66 +2776,6 @@ \subsection{Instance Methods} and the instance methods inherited by $C$ from its superclass (\ref{inheritanceAndOverriding}). -\LMHash{}% -\BlindDefineSymbol{C, D, m}% -Consider a class $C$ -and an instance member declaration $D$ in $C$, with member signature $m$ -(\ref{interfaces}). -It is a compile-time error if $D$ overrides a declaration -% Note that $m'$ is accessible, due to the definition of `overrides'. -with member signature $m'$ -from a direct superinterface of $C$ -(\ref{interfaceInheritanceAndOverriding}), -unless $m$ is a correct member override of $m'$ -(\ref{correctMemberOverrides}). - -\commentary{% -This is not the only kind of conflict that may exist: -An instance member declaration $D$ may conflict with another declaration $D'$, -even in the case where they do not have the same name -or they are not the same kind of declaration. -E.g., $D$ could be an instance getter and $D'$ a static setter -(\ref{classMemberConflicts}).% -} - -\LMHash{}% -For each parameter $p$ of $m$ where \COVARIANT{} is present, -it is a compile-time error if there exists -a direct or indirect superinterface of $C$ which has -an accessible method signature $m''$ with the same name as $m$, -such that $m''$ has a parameter $p''$ that corresponds to $p$ -(\ref{covariantParameters}), -unless the type of $p$ is a subtype or a supertype of the type of $p''$. - -\commentary{% -This means that -a parameter which is covariant-by-declaration can have a type -which is a supertype or a subtype of the type of -a corresponding parameter in a superinterface, -but the two types cannot be unrelated. -Note that this requirement must be satisfied -for each direct or indirect superinterface separately, -because that relationship is not transitive.% -} - -\rationale{% -The superinterface may be the statically known type of the receiver, -so this means that we relax the potential typing relationship -between the statically known type of a parameter and the -type which is actually required at run time -to the subtype-or-supertype relationship, -rather than the strict supertype relationship -which applies to a parameter which is not covariant. -It should be noted that it is not statically known -at the call site whether any given parameter is covariant, -because the covariance could be introduced in -a proper subtype of the statically known type of the receiver. -We chose to give priority to flexibility rather than safety here, -because the whole point of covariant parameters is that developers -can make the choice to increase the flexibility -in a trade-off where some static type safety is lost.% -} - \subsubsection{Operators} \LMLabel{operators} From 7124b8a55aab6ff408bdd8697ff7fede5f50e2f3 Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Tue, 7 Jun 2022 19:14:50 +0200 Subject: [PATCH 4/8] Finished the checklist --- specification/dartLangSpec.tex | 77 +++++++++++++++++++++++----------- 1 file changed, 52 insertions(+), 25 deletions(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index f2a47336aa..59976d88bd 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -2518,11 +2518,13 @@ \section{Classes} \rationale{% We want different behavior for concrete classes and abstract classes. If $A$ is intended to be abstract, -we want the static checker to warn about any attempt to instantiate $A$, +the static checker should report an error +if an attempt is made to instantiate $A$, and we do not want the checker to complain about unimplemented methods in $A$. In contrast, if $A$ is intended to be concrete, -the checker should warn about all unimplemented methods, -but allow clients to instantiate it freely.% +the checker should raise an error for all unimplemented methods, +but clients should be allowed to instantiate it. +This motivates the use of an explicit modifier to identify abstract classes.% } \commentary{% @@ -2534,6 +2536,12 @@ \section{Classes} (\ref{interfaces}, \ref{superinterfaces}).% } +\LMHash{}% +It is a compile-time error if a class $C$ has the interface $I$, +and $I$ has a member signature conflict +with respect to any name and library +(\ref{interfaceInheritanceAndOverriding}). + \LMHash{}% When a class name appears as a type, that name denotes the interface of the class. @@ -2637,10 +2645,10 @@ \section{Classes} \subsection{Fully Implementing an Interface} \LMLabel{fullyImplementingAnInterface} -% Note that rules here and in \ref{instanceMethods} overlap, but they are +% Note that rules here and in \ref{classes} overlap, but they are % both needed: This section is concerned with concrete methods, including -% inherited ones, and \ref{instanceMethods} is concerned with instance -% members declared in $C$, including both concrete and abstract ones. +% inherited ones, and \ref{classes} is concerned with instance members +% declared in $C$, including both concrete and abstract ones. \LMHash{}% % The use of `concrete member' below may seem redundant, because a class @@ -2759,7 +2767,7 @@ \subsection{Fully Implementing an Interface} This ensures that an inherited method satisfies the same constraint for each formal parameter which is covariant-by-declaration as the constraint which is specified for a declaration in $C$ -(\ref{instanceMethods}).% +(\ref{classes}).% } @@ -4566,7 +4574,7 @@ \subsubsection{Inheritance and Overriding} Whether an override is legal or not is specified relative to all direct superinterfaces, not just the interface of the superclass, and that is described elsewhere -(\ref{instanceMethods}). +(\ref{classes}). Static members never override anything, but they may participate in some conflicts involving declarations in superinterfaces @@ -4910,6 +4918,7 @@ \section{Interfaces} which are again interfaces. \LMHash{}% +\BlindDefineSymbol{C, I}% Let $C$ be a class. The \IndexCustom{class interface}{interface!class} @@ -5212,26 +5221,44 @@ \subsubsection{Inheritance and Overriding} \end{itemize} \LMHash{}% -Let $I$ be the interface of a class $C$ declared in library $L$. -$I$ \Index{inherits} all members of $\inherited{I, L}$ -and $I$ \Index{overrides} $m'$ if $m' \in \overrides{I, L}$. +Let $I$ be the interface of a class $C$ declared in a library $L$, +and let $K$ be a library. +We say that the set of members that $I$ +\IndexCustom{inherits with respect to $K$}{interface!inherits} +is $\inherited{I, K}$, +and the set of members that $I$ +\IndexCustom{overrides}{interface!overrides} +is $\overrides{I, L}$. + +\commentary{% +Note that an interface can inherit members that are inaccessible +(because they are private to a different library), +but it can only override members that are accessible.% +} \LMHash{}% -All the compile-time errors pertaining to the overriding of instance members -given in section~\ref{classes} hold for overriding between interfaces as well. +We say that $I$ +\IndexCustom{has a member}{interface!has a member} +$m$ if $I$ inherits $m$ with respect to any library, +or $I$ overrides $m$. \LMHash{}% -If the above rule would cause multiple member signatures -with the same name \id{} to be inherited then -exactly one member is inherited, namely -the combined member signature named \id, -from the direct superinterfaces -% This is well-defined because $I$ is a class interface. -in the textual order that they are declared, -with respect to $L$ -(\ref{combinedMemberSignatures}). -It is a compile-time error -if the computation of said combined member signature fails. +\BlindDefineSymbol{I, K, n, m}% +Let $I$ be an interface, $K$ a library, and +$n$ a name such that a member $m$ with the name $n$ +is inherited by $I$ with respect to $K$. +\commentary{% +Note that there may be more than one such member.% +} +The +\IndexCustom{member signature}{interface!member signature} +of $I$ for $n$ with respect to $K$ is +the combined member signature for $n$ +of the direct superinterfaces of $I$ with respect to $K$. +In the case where the computation of the combined member signature fails, +we say that $I$ has a +\IndexCustom{member signature conflict}{interface!member signature conflict} +with respect to $n$ and $K$. \subsubsection{Correct Member Overrides} @@ -5281,7 +5308,7 @@ \subsubsection{Correct Member Overrides} must have a type which satisfies one more requirement, relative to the corresponding parameters in all superinterfaces, both direct and indirect -(\ref{instanceMethods}). +(\ref{classes}). We cannot make that requirement a part of the notion of correct overrides, because correct overrides are only concerned with the relation to a single superinterface.% From 7885aabc743c166d69969713057fa8a97378b6fe Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Tue, 7 Jun 2022 19:17:43 +0200 Subject: [PATCH 5/8] Correct initial comment --- specification/dartLangSpec.tex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index 59976d88bd..c969105557 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -42,8 +42,8 @@ % - Clarify the conflicts between extension members and `Object` instance % members. % - Correct to include metadata. -% - Clarify errors involving overrides of private members in a library where -% they are not accessible. +% - Clarify errors involving private members that are brought together in a +% library where they are not accessible. % % 2.14 % - Add constraint on type of parameter which is covariant-by-declaration in From 7c0a05d241bfb082aa4eb5066096f19bd372136d Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Wed, 8 Jun 2022 16:03:11 +0200 Subject: [PATCH 6/8] Review response --- specification/dartLangSpec.tex | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index c969105557..722d4e3cb1 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -2519,11 +2519,11 @@ \section{Classes} We want different behavior for concrete classes and abstract classes. If $A$ is intended to be abstract, the static checker should report an error -if an attempt is made to instantiate $A$, +if an attempt is made to instantiate $A$ (such as \code{new A(42)}), and we do not want the checker to complain about unimplemented methods in $A$. In contrast, if $A$ is intended to be concrete, -the checker should raise an error for all unimplemented methods, -but clients should be allowed to instantiate it. +the checker should raise an error for each member which is unimplemented, +but clients should be allowed to create instances. This motivates the use of an explicit modifier to identify abstract classes.% } @@ -2591,11 +2591,11 @@ \section{Classes} with member signature $m'$ from a direct superinterface of $C$ (\ref{interfaceInheritanceAndOverriding}), -unless $m$ is a correct member override of $m'$ +and $m$ is not a correct member override of $m'$ (\ref{correctMemberOverrides}). \commentary{% -This is not the only kind of conflict that may exist: +Other kinds of compile-time errors may exist as well: An instance member declaration $D$ may conflict with another declaration $D'$, even in the case where they do not have the same name or they are not the same kind of declaration. @@ -2607,10 +2607,11 @@ \section{Classes} For each parameter $p$ of $m$ where \COVARIANT{} is present, it is a compile-time error if there exists a direct or indirect superinterface of $C$ which has -an accessible method signature $m''$ with the same name as $m$, +an accessible member signature $m''$ with the same name as $m$, such that $m''$ has a parameter $p''$ that corresponds to $p$ (\ref{covariantParameters}), -unless the type of $p$ is a subtype or a supertype of the type of $p''$. +and the type of $p$ is not a subtype and not a supertype +of the type of $p''$. \commentary{% This means that From ffed8777c87af4ece673876c05d8cc1e905eccfe Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Thu, 16 Jun 2022 14:33:31 +0200 Subject: [PATCH 7/8] Review response --- specification/dartLangSpec.tex | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index 722d4e3cb1..270d1920da 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -2595,11 +2595,7 @@ \section{Classes} (\ref{correctMemberOverrides}). \commentary{% -Other kinds of compile-time errors may exist as well: -An instance member declaration $D$ may conflict with another declaration $D'$, -even in the case where they do not have the same name -or they are not the same kind of declaration. -E.g., $D$ could be an instance getter and $D'$ a static setter +Note that other, somewhat similar kinds of compile-time errors may exist as well (\ref{classMemberConflicts}).% } @@ -3314,7 +3310,7 @@ \subsection{Getters} those static getters declared by $C$. \commentary{% -A getter declaration may conflict with other declarations +A getter declaration may conflict with other declarations as well (\ref{classMemberConflicts}). In particular, a getter can never override a method, and a method can never override a getter or an instance variable. @@ -3548,7 +3544,7 @@ \subsection{Constructors} } \commentary{% -A constructor declaration may conflict with static member declarations +A constructor declaration may conflict with static member declarations as well (\ref{classMemberConflicts}).% } @@ -4428,7 +4424,7 @@ \subsection{Static Methods} } \commentary{% -Static method declarations may conflict with other declarations +Static method declarations may conflict with other declarations as well (\ref{classMemberConflicts}).% } From 2d1bbeb078a25f81f0ec7f69e595b5bc5daf9221 Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Mon, 11 Jul 2022 19:56:05 +0200 Subject: [PATCH 8/8] Added some extra commentary text at locations where the main text seemed to need it --- specification/dartLangSpec.tex | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index 270d1920da..df6f48748b 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -5230,7 +5230,11 @@ \subsubsection{Inheritance and Overriding} \commentary{% Note that an interface can inherit members that are inaccessible (because they are private to a different library), -but it can only override members that are accessible.% +but it can only override members that are accessible. +This is the reason why it is called ``with respect to $K$'' +when the topic is inheritance, +but no library is mentioned when the topic is overriding: +only one library is relevant, namely the one that declares $C$.% } \LMHash{}% @@ -5240,12 +5244,15 @@ \subsubsection{Inheritance and Overriding} or $I$ overrides $m$. \LMHash{}% -\BlindDefineSymbol{I, K, n, m}% -Let $I$ be an interface, $K$ a library, and -$n$ a name such that a member $m$ with the name $n$ +\BlindDefineSymbol{I, C, K, n, m}% +Let $I$ be the interface of the class $C$ declared by the library $L$, +$K$ a library +(\commentary{which may or may not be the same as $L$}), +and $n$ a name such that a member $m$ with the name $n$ is inherited by $I$ with respect to $K$. \commentary{% -Note that there may be more than one such member.% +Note that there may be more than one such member, +and also that $C$ does not override $m$.% } The \IndexCustom{member signature}{interface!member signature} @@ -5257,6 +5264,21 @@ \subsubsection{Inheritance and Overriding} \IndexCustom{member signature conflict}{interface!member signature conflict} with respect to $n$ and $K$. +\commentary{% +When $n$ is a public name, $K$ can be $L$ +or any other library where $C$ is in scope. +In other words, $K$ does not matter. +But when $n$ is a private name then +$K$ must be the library that declares $m$, +such that $m$ is accessible to $K$. +This covers the case where the interface $I$ +(as well as the underlying class $C$) has +a member signature conflict on +a member which is private to another library. +This can be a compile-time error +(\ref{classes}).% +} + \subsubsection{Correct Member Overrides} \LMLabel{correctMemberOverrides}