Skip to content

Commit 6fde36a

Browse files
committed
Type Type
1 parent 9e6af83 commit 6fde36a

File tree

1 file changed

+128
-83
lines changed

1 file changed

+128
-83
lines changed

specification/dartLangSpec.tex

Lines changed: 128 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -859,10 +859,13 @@ \section{Overview}
859859
Type annotations declare the types of
860860
variables and functions (including methods and constructors).
861861
\item
862-
%% TODO(eernst): Change when integrating instantiate-to-bounds.md.
863862
Type annotations may be omitted, in which case they are generally
864-
filled in with the type \DYNAMIC{}
863+
filled in using type inference, or using the type \DYNAMIC{}
865864
(\ref{typeDynamic}).
865+
\commentary{%
866+
Type inference will be specified in a future version of this document
867+
(\ref{overview}).%
868+
}
866869
\end{enumerate}%
867870
}
868871

@@ -7701,12 +7704,7 @@ \subsection{Instantiation to Bound}
77017704
For instance, with the declaration \code{Type listType() => List;},
77027705
evaluation of the raw type expression \code{List} in the body yields
77037706
an instance of class \code{Type} reifying \code{List<dynamic>},
7704-
because \code{List} is subject to instantiation to bound.
7705-
Note that \code{List<dynamic>} is not syntactically an expression,
7706-
but it is still possible to get access to
7707-
a \code{Type} instance reifying \code{List<dynamic>}
7708-
without instantiation to bound,
7709-
because it can be the value of a type variable.%
7707+
because \code{List} is subject to instantiation to bound.%
77107708
}
77117709

77127710
\rationale{%
@@ -8421,7 +8419,9 @@ \subsection{Constants}
84218419
a mixin or a type alias that is not qualified by a deferred prefix,
84228420
is a potentially constant and constant expression.
84238421
\commentary{%
8424-
The constant expression always evaluates to a \code{Type} object.
8422+
The constant expression always evaluates to a \code{Type} object
8423+
which is a reified type
8424+
(\ref{typeType}).
84258425
For example, if $C$ is the name of a class or type alias,
84268426
the expression \code{$C$} is a constant,
84278427
and if $C$ is imported with a prefix $p$, \code{$p$.$C$} is
@@ -17557,7 +17557,8 @@ \subsection{Identifier Reference}
1755717557
\item
1755817558
If $D$ is a class, mixin, or type alias,
1755917559
the value of $e$ is an object implementing the class \code{Type}
17560-
which reifies the corresponding type.
17560+
which reifies the corresponding type
17561+
(\ref{typeType}).
1756117562
\item
1756217563
If $D$ is a type parameter $X$ then the value of $e$ is
1756317564
the value of the actual type argument corresponding to $X$
@@ -21183,41 +21184,6 @@ \subsection{Dynamic Type System}
2118321184
(\ref{actualTypes}).%
2118421185
}
2118521186

21186-
\LMHash{}%
21187-
When types are reified as instances of the built-in class \code{Type},
21188-
those objects override the \lit{==} operator
21189-
inherited from the \code{Object} class, so that
21190-
two \code{Type} objects are equal according to operator \lit{==}
21191-
if{}f the corresponding types are subtypes of each other.
21192-
21193-
\commentary{%
21194-
For example, the \code{Type} objects for the types
21195-
\DYNAMIC{} and \code{Object} are equal to each other
21196-
and hence \code{dynamic\,==\,Object} must evaluate to \TRUE.
21197-
No constraints are imposed on the built-in function \code{identical},
21198-
so \code{identical(dynamic, Object)} may be \TRUE{} or \FALSE.
21199-
21200-
Similarly, \code{Type} instances for distinct type alias declarations
21201-
declaring a name for the same function type are equal:%
21202-
}
21203-
21204-
\begin{dartCode}
21205-
\TYPEDEF{} F = \VOID{} \FUNCTION{}<X>(X);
21206-
\TYPEDEF{} G = \VOID{} \FUNCTION{}<Y>(Y);
21207-
\\
21208-
\VOID{} main() \{
21209-
assert(F == G);
21210-
\}
21211-
\end{dartCode}
21212-
21213-
\LMHash{}%
21214-
\commentary{%
21215-
Instances of \code{Type} can be obtained in various ways,
21216-
for example by using reflection,
21217-
by reading the \code{runtimeType} of an object,
21218-
or by evaluating a \emph{type literal} expression.%
21219-
}
21220-
2122121187
\LMHash{}%
2122221188
An expression is a \emph{type literal} if it is an identifier,
2122321189
or a qualified identifier,
@@ -23102,7 +23068,7 @@ \subsection{Type Never}
2310223068
}
2310323069

2310423070

23105-
\subsection{Type \code{Null}}
23071+
\subsection{Type Null}
2310623072
\LMLabel{typeNull}
2310723073

2310823074
\LMHash{}%
@@ -23148,6 +23114,109 @@ \subsection{Type \code{Null}}
2314823114
}
2314923115

2315023116

23117+
\subsection{Type Type}
23118+
\LMLabel{typeType}
23119+
23120+
\LMHash{}%
23121+
The Dart runtime supports a very limited kind of introspective reflection
23122+
for all programs
23123+
(\commentary{%
23124+
that is, without including any reflection support mechanisms,
23125+
e.g., importing \code{dart:mirrors},
23126+
or using reflection related code generation%
23127+
}).
23128+
In particular, evaluation of a type literal as an expression yields
23129+
an object whose run-time type is a subtype of the built-in type \code{Type}.
23130+
System libraries may deliver such objects as well
23131+
(\commentary{e.g., the method \code{runtimeType} on \code{Object}}).
23132+
If an object $o$ is obtained in this manner
23133+
as a reification of the Dart type $T$,
23134+
we say that $o$ is a \Index{reified type},
23135+
and we say that $o$ \IndexCustom{reifies}{type!reifies} $T$.
23136+
23137+
%% TODO(eernst): Define "same type" in one location in this spec, use it here.
23138+
\LMHash{}%
23139+
A reified type identifies the underlying Dart type in the sense that
23140+
it supports equality tests with other reified types as follows.
23141+
Let $o_1$ and $o_2$ be reified types that reify $S_1$ respectively $S_2$,
23142+
and let $o_3$ be an object which is not a reified type.
23143+
Let $U_j$ be the transitive alias expansion of $S_j$, for $j \in 1 .. 3$,
23144+
and let $v_j$ be a fresh variable whose value is $o_j$, for $j \in 1 .. 3$.
23145+
It is then guaranteed that \code{$v_1$ == $v_2$} if{}f
23146+
\NormalizedTypeOf{$U_1$} and \NormalizedTypeOf{$U_2$}
23147+
are syntactically equal,
23148+
up to equivalence of bound variables
23149+
and up to designations of the same type using different syntax
23150+
(\commentary{e.g., \code{C} and \code{prefix.C} may denote the same type}).
23151+
Conversely, \code{$v_1$ == $v_3$} will yield false.
23152+
23153+
\commentary{%
23154+
Note that we do not equate primitive top types.
23155+
For example,
23156+
reified types reifying \code{List<\VOID>} and \code{List<\DYNAMIC>}
23157+
are not equal.
23158+
However, a type variable which is declared by a function type
23159+
is treated as if it were consistently renamed to a fresh name,
23160+
thus making types identical if possible
23161+
(also known as alpha equivalence).
23162+
For example:%
23163+
}
23164+
23165+
\begin{dartCode}
23166+
\TYPEDEF{} F = \VOID{} \FUNCTION{}<X>(X);
23167+
\TYPEDEF{} G = \VOID{} \FUNCTION{}<Y>(Y);
23168+
\\
23169+
\VOID{} main() \{
23170+
print(F == G); // \comment{Prints 'true'.}
23171+
\}
23172+
\end{dartCode}
23173+
23174+
\commentary{%
23175+
Note that reified types have a primitive operator \lit{==}
23176+
(\ref{theOperatorEqualsEquals}).
23177+
This property cannot be assumed for arbitrary expressions of type \code{Type}.
23178+
For instance, we can declare
23179+
\code{\CLASS\,\,MyType\,\,\EXTENDS\,\,Type \{\ldots\}}
23180+
and override operator \lit{==}.%
23181+
}
23182+
23183+
\LMHash{}%
23184+
Let $e_1$ and $e_2$ be constant expressions
23185+
(\ref{constants})
23186+
evaluating to $o_1$ respectively $o_2$,
23187+
which are reified types reifying the Dart types $S_1$ respecively $S_2$.
23188+
Let $v_1$ and $v_2$ be fresh variables bound to $o_1$ respectively $o_2$
23189+
We then have \code{identical($v_1$, $v_2$)} if{}f
23190+
\code{$S_1$\,\,==\,\,$S_2$}.
23191+
23192+
\commentary{%
23193+
In other words, constant reified types are canonicalized.
23194+
For runtime implementations which implement identity by choosing a
23195+
canonical representative for the equivalence class of equal instances,
23196+
the choice of what type object to canonicalize to is not
23197+
observable in the language.
23198+
}
23199+
23200+
\rationale{%
23201+
As mentioned at the beginning of this section,
23202+
reified types support a very limited kind of introspective reflection.
23203+
In particular, we can compare reified types for equality,
23204+
and in the case where two reified types are equal
23205+
it is known that they reify types which are subtypes of each other
23206+
(that is, they are ``the same type'' with respect to subtyping).
23207+
But we cannot compare reified types for any inequality, that is,
23208+
we cannot determine whether one is a subtype of the other.
23209+
It is also impossible to deconstruct a reified type.
23210+
E.g., we cannot obtain the reified type for \code{$T$}
23211+
by performing operations on a given reified type for \code{List<$T$>}.
23212+
This design was chosen in order to ensure that Dart programs
23213+
do not incur the substantial implications in terms of
23214+
program size and run-time performance
23215+
that are very difficult to avoid
23216+
when a more powerful form of reflection is supported.%
23217+
}
23218+
23219+
2315123220
\subsection{Function Types}
2315223221
\LMLabel{functionTypes}
2315323222

@@ -23200,7 +23269,7 @@ \subsection{Function Types}
2320023269
}
2320123270

2320223271

23203-
\subsection{Type \FUNCTION}
23272+
\subsection{Type Function}
2320423273
\LMLabel{functionType}
2320523274

2320623275
\LMHash{}%
@@ -23241,7 +23310,7 @@ \subsection{Type \FUNCTION}
2324123310
}
2324223311

2324323312

23244-
\subsection{Type \DYNAMIC}
23313+
\subsection{Type dynamic}
2324523314
\LMLabel{typeDynamic}
2324623315

2324723316
\LMHash{}%
@@ -24372,44 +24441,20 @@ \subsubsection{Null promotion}
2437224441
These are extended as per
2437324442
[separate proposal](https://github.com/dart-lang/language/blob/master/resources/type-system/flow-analysis.md).
2437424443

24375-
\subsubsection{Runtime type equality operator}
24376-
24377-
!!!TODO!!!
24378-
24379-
Two objects $T_1$ and $T_2$ which are instances of \code{Type} (that
24380-
is, runtime type objects) are considered equal if and only if the
24381-
runtime type objects $T_1$ and $T_2$ corresponds to the types $S_1$
24382-
and $S_2$ respectively, and the normal forms \NormalizedTypeOf{$S_1$}
24383-
and \NormalizedTypeOf{$S_2$} are syntactically equal up to equivalence
24384-
of bound variables. Note that we do not equate primitive top types.
24385-
\code{List<\VOID>} and \code{List<\DYNAMIC>} are still considered
24386-
distinct runtime type objects. Note that we also do not equate
24387-
function types which differ in the placement of \REQUIRED{} on
24388-
parameter types.
24389-
24390-
\subsubsection{Constant evaluation and canonicalization}
24391-
24392-
\paragraph{Type literals}
24393-
24394-
Two constant type literals $T_1$ and $T_2$ compare as identical if they
24395-
are equal using the definition of runtime type equality specified above.
24396-
24397-
For runtime implementations which implement identity by choosing a
24398-
canonical representative for the equivalence class of equal instances,
24399-
the choice of what type object to canonicalize to is not
24400-
observable in the language.
2440124444

2440224445
\paragraph{Constant instances}
2440324446

24404-
Any two
24405-
instances which are otherwise identical except for their generic type arguments
24406-
shall be considered identical if those generic type arguments compare equal
24407-
using the definition of runtime type object equality defined above. That is,
24408-
comparison (or canonicalization) of constant instances of generic classes is
24409-
performed relative to the normal forms of their generic type arguments.
24410-
Hence, an instance of
24411-
\code{$C$<$T_0$>} compares identical to \code{C<$T_1$>} if $T_0$ and $T_1$ have the same normal form
24412-
(up to the identity of bound variables), and the objects are otherwise
24447+
!!!TODO!!!
24448+
24449+
Any two instances which are otherwise identical except for their
24450+
generic type arguments shall be considered identical if those generic
24451+
type arguments compare equal using the definition of runtime type
24452+
object equality defined above. That is, comparison (or
24453+
canonicalization) of constant instances of generic classes is
24454+
performed relative to the normal forms of their generic type
24455+
arguments. Hence, an instance of \code{$C$<$T_0$>} compares identical
24456+
to \code{C<$T_1$>} if $T_0$ and $T_1$ have the same normal form (up to
24457+
the identity of bound variables), and the objects are otherwise
2441324458
identical.
2441424459

2441524460
Implementations of the Dart runtime semantics rely on canonicalization of

0 commit comments

Comments
 (0)