Skip to content

Commit 895184d

Browse files
committed
Type Type
1 parent 55fdf3f commit 895184d

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
@@ -881,10 +881,13 @@ \section{Overview}
881881
Type annotations declare the types of
882882
variables and functions (including methods and constructors).
883883
\item
884-
%% TODO(eernst): Change when integrating instantiate-to-bounds.md.
885884
Type annotations may be omitted, in which case they are generally
886-
filled in with the type \DYNAMIC{}
885+
filled in using type inference, or using the type \DYNAMIC{}
887886
(\ref{typeDynamic}).
887+
\commentary{%
888+
Type inference will be specified in a future version of this document
889+
(\ref{overview}).%
890+
}
888891
\end{enumerate}%
889892
}
890893

@@ -7879,12 +7882,7 @@ \subsection{Instantiation to Bound}
78797882
For instance, with the declaration \code{Type listType() => List;},
78807883
evaluation of the raw type expression \code{List} in the body yields
78817884
an instance of class \code{Type} reifying \code{List<dynamic>},
7882-
because \code{List} is subject to instantiation to bound.
7883-
Note that \code{List<dynamic>} is not syntactically an expression,
7884-
but it is still possible to get access to
7885-
a \code{Type} instance reifying \code{List<dynamic>}
7886-
without instantiation to bound,
7887-
because it can be the value of a type variable.%
7885+
because \code{List} is subject to instantiation to bound.%
78887886
}
78897887

78907888
\rationale{%
@@ -8599,7 +8597,9 @@ \subsection{Constants}
85998597
a mixin or a type alias that is not qualified by a deferred prefix,
86008598
is a potentially constant and constant expression.
86018599
\commentary{%
8602-
The constant expression always evaluates to a \code{Type} object.
8600+
The constant expression always evaluates to a \code{Type} object
8601+
which is a reified type
8602+
(\ref{typeType}).
86038603
For example, if $C$ is the name of a class or type alias,
86048604
the expression \code{$C$} is a constant,
86058605
and if $C$ is imported with a prefix $p$, \code{$p$.$C$} is
@@ -17742,7 +17742,8 @@ \subsection{Identifier Reference}
1774217742
\item
1774317743
If $D$ is a class, mixin, enum, or type alias,
1774417744
the value of $e$ is an object implementing the class \code{Type}
17745-
which reifies the corresponding type.
17745+
which reifies the corresponding type
17746+
(\ref{typeType}).
1774617747
\item
1774717748
If $D$ is a type parameter $X$ then the value of $e$ is
1774817749
the value of the actual type argument corresponding to $X$
@@ -21419,41 +21420,6 @@ \subsection{Dynamic Type System}
2141921420
(\ref{actualTypes}).%
2142021421
}
2142121422

21422-
\LMHash{}%
21423-
When types are reified as instances of the built-in class \code{Type},
21424-
those objects override the \lit{==} operator
21425-
inherited from the \code{Object} class, so that
21426-
two \code{Type} objects are equal according to operator \lit{==}
21427-
if{}f the corresponding types are subtypes of each other.
21428-
21429-
\commentary{%
21430-
For example, the \code{Type} objects for the types
21431-
\DYNAMIC{} and \code{Object} are equal to each other
21432-
and hence \code{dynamic\,==\,Object} must evaluate to \TRUE.
21433-
No constraints are imposed on the built-in function \code{identical},
21434-
so \code{identical(dynamic, Object)} may be \TRUE{} or \FALSE.
21435-
21436-
Similarly, \code{Type} instances for distinct type alias declarations
21437-
declaring a name for the same function type are equal:%
21438-
}
21439-
21440-
\begin{dartCode}
21441-
\TYPEDEF{} F = \VOID{} \FUNCTION{}<X>(X);
21442-
\TYPEDEF{} G = \VOID{} \FUNCTION{}<Y>(Y);
21443-
\\
21444-
\VOID{} main() \{
21445-
assert(F == G);
21446-
\}
21447-
\end{dartCode}
21448-
21449-
\LMHash{}%
21450-
\commentary{%
21451-
Instances of \code{Type} can be obtained in various ways,
21452-
for example by using reflection,
21453-
by reading the \code{runtimeType} of an object,
21454-
or by evaluating a \emph{type literal} expression.%
21455-
}
21456-
2145721423
\LMHash{}%
2145821424
An expression is a \emph{type literal} if it is an identifier,
2145921425
or a qualified identifier,
@@ -23340,7 +23306,7 @@ \subsection{Type Never}
2334023306
}
2334123307

2334223308

23343-
\subsection{Type \code{Null}}
23309+
\subsection{Type Null}
2334423310
\LMLabel{typeNull}
2334523311

2334623312
\LMHash{}%
@@ -23386,6 +23352,109 @@ \subsection{Type \code{Null}}
2338623352
}
2338723353

2338823354

23355+
\subsection{Type Type}
23356+
\LMLabel{typeType}
23357+
23358+
\LMHash{}%
23359+
The Dart runtime supports a very limited kind of introspective reflection
23360+
for all programs
23361+
(\commentary{%
23362+
that is, without including any reflection support mechanisms,
23363+
e.g., importing \code{dart:mirrors},
23364+
or using reflection related code generation%
23365+
}).
23366+
In particular, evaluation of a type literal as an expression yields
23367+
an object whose run-time type is a subtype of the built-in type \code{Type}.
23368+
System libraries may deliver such objects as well
23369+
(\commentary{e.g., the method \code{runtimeType} on \code{Object}}).
23370+
If an object $o$ is obtained in this manner
23371+
as a reification of the Dart type $T$,
23372+
we say that $o$ is a \Index{reified type},
23373+
and we say that $o$ \IndexCustom{reifies}{type!reifies} $T$.
23374+
23375+
%% TODO(eernst): Define "same type" in one location in this spec, use it here.
23376+
\LMHash{}%
23377+
A reified type identifies the underlying Dart type in the sense that
23378+
it supports equality tests with other reified types as follows.
23379+
Let $o_1$ and $o_2$ be reified types that reify $S_1$ respectively $S_2$,
23380+
and let $o_3$ be an object which is not a reified type.
23381+
Let $U_j$ be the transitive alias expansion of $S_j$, for $j \in 1 .. 3$,
23382+
and let $v_j$ be a fresh variable whose value is $o_j$, for $j \in 1 .. 3$.
23383+
It is then guaranteed that \code{$v_1$ == $v_2$} if{}f
23384+
\NormalizedTypeOf{$U_1$} and \NormalizedTypeOf{$U_2$}
23385+
are syntactically equal,
23386+
up to equivalence of bound variables
23387+
and up to designations of the same type using different syntax
23388+
(\commentary{e.g., \code{C} and \code{prefix.C} may denote the same type}).
23389+
Conversely, \code{$v_1$ == $v_3$} will yield false.
23390+
23391+
\commentary{%
23392+
Note that we do not equate primitive top types.
23393+
For example,
23394+
reified types reifying \code{List<\VOID>} and \code{List<\DYNAMIC>}
23395+
are not equal.
23396+
However, a type variable which is declared by a function type
23397+
is treated as if it were consistently renamed to a fresh name,
23398+
thus making types identical if possible
23399+
(also known as alpha equivalence).
23400+
For example:%
23401+
}
23402+
23403+
\begin{dartCode}
23404+
\TYPEDEF{} F = \VOID{} \FUNCTION{}<X>(X);
23405+
\TYPEDEF{} G = \VOID{} \FUNCTION{}<Y>(Y);
23406+
\\
23407+
\VOID{} main() \{
23408+
print(F == G); // \comment{Prints 'true'.}
23409+
\}
23410+
\end{dartCode}
23411+
23412+
\commentary{%
23413+
Note that reified types have a primitive operator \lit{==}
23414+
(\ref{theOperatorEqualsEquals}).
23415+
This property cannot be assumed for arbitrary expressions of type \code{Type}.
23416+
For instance, we can declare
23417+
\code{\CLASS\,\,MyType\,\,\EXTENDS\,\,Type \{\ldots\}}
23418+
and override operator \lit{==}.%
23419+
}
23420+
23421+
\LMHash{}%
23422+
Let $e_1$ and $e_2$ be constant expressions
23423+
(\ref{constants})
23424+
evaluating to $o_1$ respectively $o_2$,
23425+
which are reified types reifying the Dart types $S_1$ respecively $S_2$.
23426+
Let $v_1$ and $v_2$ be fresh variables bound to $o_1$ respectively $o_2$
23427+
We then have \code{identical($v_1$, $v_2$)} if{}f
23428+
\code{$S_1$\,\,==\,\,$S_2$}.
23429+
23430+
\commentary{%
23431+
In other words, constant reified types are canonicalized.
23432+
For runtime implementations which implement identity by choosing a
23433+
canonical representative for the equivalence class of equal instances,
23434+
the choice of what type object to canonicalize to is not
23435+
observable in the language.
23436+
}
23437+
23438+
\rationale{%
23439+
As mentioned at the beginning of this section,
23440+
reified types support a very limited kind of introspective reflection.
23441+
In particular, we can compare reified types for equality,
23442+
and in the case where two reified types are equal
23443+
it is known that they reify types which are subtypes of each other
23444+
(that is, they are ``the same type'' with respect to subtyping).
23445+
But we cannot compare reified types for any inequality, that is,
23446+
we cannot determine whether one is a subtype of the other.
23447+
It is also impossible to deconstruct a reified type.
23448+
E.g., we cannot obtain the reified type for \code{$T$}
23449+
by performing operations on a given reified type for \code{List<$T$>}.
23450+
This design was chosen in order to ensure that Dart programs
23451+
do not incur the substantial implications in terms of
23452+
program size and run-time performance
23453+
that are very difficult to avoid
23454+
when a more powerful form of reflection is supported.%
23455+
}
23456+
23457+
2338923458
\subsection{Function Types}
2339023459
\LMLabel{functionTypes}
2339123460

@@ -23438,7 +23507,7 @@ \subsection{Function Types}
2343823507
}
2343923508

2344023509

23441-
\subsection{Type \FUNCTION}
23510+
\subsection{Type Function}
2344223511
\LMLabel{functionType}
2344323512

2344423513
\LMHash{}%
@@ -23479,7 +23548,7 @@ \subsection{Type \FUNCTION}
2347923548
}
2348023549

2348123550

23482-
\subsection{Type \DYNAMIC}
23551+
\subsection{Type dynamic}
2348323552
\LMLabel{typeDynamic}
2348423553

2348523554
\LMHash{}%
@@ -24610,44 +24679,20 @@ \subsubsection{Null promotion}
2461024679
These are extended as per
2461124680
[separate proposal](https://github.com/dart-lang/language/blob/master/resources/type-system/flow-analysis.md).
2461224681

24613-
\subsubsection{Runtime type equality operator}
24614-
24615-
!!!TODO!!!
24616-
24617-
Two objects $T_1$ and $T_2$ which are instances of \code{Type} (that
24618-
is, runtime type objects) are considered equal if and only if the
24619-
runtime type objects $T_1$ and $T_2$ corresponds to the types $S_1$
24620-
and $S_2$ respectively, and the normal forms \NormalizedTypeOf{$S_1$}
24621-
and \NormalizedTypeOf{$S_2$} are syntactically equal up to equivalence
24622-
of bound variables. Note that we do not equate primitive top types.
24623-
\code{List<\VOID>} and \code{List<\DYNAMIC>} are still considered
24624-
distinct runtime type objects. Note that we also do not equate
24625-
function types which differ in the placement of \REQUIRED{} on
24626-
parameter types.
24627-
24628-
\subsubsection{Constant evaluation and canonicalization}
24629-
24630-
\paragraph{Type literals}
24631-
24632-
Two constant type literals $T_1$ and $T_2$ compare as identical if they
24633-
are equal using the definition of runtime type equality specified above.
24634-
24635-
For runtime implementations which implement identity by choosing a
24636-
canonical representative for the equivalence class of equal instances,
24637-
the choice of what type object to canonicalize to is not
24638-
observable in the language.
2463924682

2464024683
\paragraph{Constant instances}
2464124684

24642-
Any two
24643-
instances which are otherwise identical except for their generic type arguments
24644-
shall be considered identical if those generic type arguments compare equal
24645-
using the definition of runtime type object equality defined above. That is,
24646-
comparison (or canonicalization) of constant instances of generic classes is
24647-
performed relative to the normal forms of their generic type arguments.
24648-
Hence, an instance of
24649-
\code{$C$<$T_0$>} compares identical to \code{C<$T_1$>} if $T_0$ and $T_1$ have the same normal form
24650-
(up to the identity of bound variables), and the objects are otherwise
24685+
!!!TODO!!!
24686+
24687+
Any two instances which are otherwise identical except for their
24688+
generic type arguments shall be considered identical if those generic
24689+
type arguments compare equal using the definition of runtime type
24690+
object equality defined above. That is, comparison (or
24691+
canonicalization) of constant instances of generic classes is
24692+
performed relative to the normal forms of their generic type
24693+
arguments. Hence, an instance of \code{$C$<$T_0$>} compares identical
24694+
to \code{C<$T_1$>} if $T_0$ and $T_1$ have the same normal form (up to
24695+
the identity of bound variables), and the objects are otherwise
2465124696
identical.
2465224697

2465324698
Implementations of the Dart runtime semantics rely on canonicalization of

0 commit comments

Comments
 (0)