Skip to content

Commit a3eeae1

Browse files
committed
Type Type
1 parent d35b17d commit a3eeae1

File tree

1 file changed

+130
-86
lines changed

1 file changed

+130
-86
lines changed

specification/dartLangSpec.tex

Lines changed: 130 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -836,10 +836,13 @@ \section{Overview}
836836
Type annotations declare the types of
837837
variables and functions (including methods and constructors).
838838
\item
839-
%% TODO(eernst): Change when integrating instantiate-to-bounds.md.
840839
Type annotations may be omitted, in which case they are generally
841-
filled in with the type \DYNAMIC{}
840+
filled in using type inference, or using the type \DYNAMIC{}
842841
(\ref{typeDynamic}).
842+
\commentary{%
843+
Type inference will be specified in a future version of this document
844+
(\ref{overview}).%
845+
}
843846
\end{enumerate}%
844847
}
845848

@@ -3446,9 +3449,8 @@ \subsubsection{The Operator `=='}
34463449
which was originally obtained by evaluation of a literal symbol or
34473450
a constant invocation of a constructor of the \code{Symbol} class
34483451
has a primitive operator \lit{==}.
3449-
\item Every instance of type \code{Type}
3450-
which was originally obtained by evaluating a constant type literal
3451-
(\ref{dynamicTypeSystem})
3452+
\item Every instance of type \code{Type} which is a reified type
3453+
(\ref{typeType})
34523454
has a primitive operator \lit{==}.
34533455
\item An instance $o$ has a primitive operator \lit{==}
34543456
if the dynamic type of $o$ is a class $C$,
@@ -7654,12 +7656,7 @@ \subsection{Instantiation to Bound}
76547656
For instance, with the declaration \code{Type listType() => List;},
76557657
evaluation of the raw type expression \code{List} in the body yields
76567658
an instance of class \code{Type} reifying \code{List<dynamic>},
7657-
because \code{List} is subject to instantiation to bound.
7658-
Note that \code{List<dynamic>} is not syntactically an expression,
7659-
but it is still possible to get access to
7660-
a \code{Type} instance reifying \code{List<dynamic>}
7661-
without instantiation to bound,
7662-
because it can be the value of a type variable.%
7659+
because \code{List} is subject to instantiation to bound.%
76637660
}
76647661

76657662
\rationale{%
@@ -8374,7 +8371,9 @@ \subsection{Constants}
83748371
a mixin or a type alias that is not qualified by a deferred prefix,
83758372
is a potentially constant and constant expression.
83768373
\commentary{%
8377-
The constant expression always evaluates to a \code{Type} object.
8374+
The constant expression always evaluates to a \code{Type} object
8375+
which is a reified type
8376+
(\ref{typeType}).
83788377
For example, if $C$ is the name of a class or type alias,
83798378
the expression \code{$C$} is a constant,
83808379
and if $C$ is imported with a prefix $p$, \code{$p$.$C$} is
@@ -17327,7 +17326,8 @@ \subsection{Identifier Reference}
1732717326
\item
1732817327
If $D$ is a class, mixin, or type alias,
1732917328
the value of $e$ is an object implementing the class \code{Type}
17330-
which reifies the corresponding type.
17329+
which reifies the corresponding type
17330+
(\ref{typeType}).
1733117331
\item
1733217332
If $D$ is a type parameter $X$ then the value of $e$ is
1733317333
the value of the actual type argument corresponding to $X$
@@ -20917,41 +20917,6 @@ \subsection{Dynamic Type System}
2091720917
(\ref{actualTypes}).%
2091820918
}
2091920919

20920-
\LMHash{}%
20921-
When types are reified as instances of the built-in class \code{Type},
20922-
those objects override the \lit{==} operator
20923-
inherited from the \code{Object} class, so that
20924-
two \code{Type} objects are equal according to operator \lit{==}
20925-
if{}f the corresponding types are subtypes of each other.
20926-
20927-
\commentary{%
20928-
For example, the \code{Type} objects for the types
20929-
\DYNAMIC{} and \code{Object} are equal to each other
20930-
and hence \code{dynamic\,==\,Object} must evaluate to \TRUE.
20931-
No constraints are imposed on the built-in function \code{identical},
20932-
so \code{identical(dynamic, Object)} may be \TRUE{} or \FALSE.
20933-
20934-
Similarly, \code{Type} instances for distinct type alias declarations
20935-
declaring a name for the same function type are equal:%
20936-
}
20937-
20938-
\begin{dartCode}
20939-
\TYPEDEF{} F = \VOID{} \FUNCTION{}<X>(X);
20940-
\TYPEDEF{} G = \VOID{} \FUNCTION{}<Y>(Y);
20941-
\\
20942-
\VOID{} main() \{
20943-
assert(F == G);
20944-
\}
20945-
\end{dartCode}
20946-
20947-
\LMHash{}%
20948-
\commentary{%
20949-
Instances of \code{Type} can be obtained in various ways,
20950-
for example by using reflection,
20951-
by reading the \code{runtimeType} of an object,
20952-
or by evaluating a \emph{type literal} expression.%
20953-
}
20954-
2095520920
\LMHash{}%
2095620921
An expression is a \emph{type literal} if it is an identifier,
2095720922
or a qualified identifier,
@@ -22836,7 +22801,7 @@ \subsection{Type Never}
2283622801
}
2283722802

2283822803

22839-
\subsection{Type \code{Null}}
22804+
\subsection{Type Null}
2284022805
\LMLabel{typeNull}
2284122806

2284222807
\LMHash{}%
@@ -22882,6 +22847,109 @@ \subsection{Type \code{Null}}
2288222847
}
2288322848

2288422849

22850+
\subsection{Type Type}
22851+
\LMLabel{typeType}
22852+
22853+
\LMHash{}%
22854+
The Dart runtime supports a very limited kind of introspective reflection
22855+
for all programs
22856+
(\commentary{%
22857+
that is, without including any reflection support mechanisms,
22858+
e.g., importing \code{dart:mirrors},
22859+
or using reflection related code generation%
22860+
}).
22861+
In particular, evaluation of a type literal as an expression yields
22862+
an object whose run-time type is a subtype of the built-in type \code{Type}.
22863+
System libraries may deliver such objects as well
22864+
(\commentary{e.g., the method \code{runtimeType} on \code{Object}}).
22865+
If an object $o$ is obtained in this manner
22866+
as a reification of the Dart type $T$,
22867+
we say that $o$ is a \Index{reified type},
22868+
and we say that $o$ \IndexCustom{reifies}{type!reifies} $T$.
22869+
22870+
%% TODO(eernst): Define "same type" in one location in this spec, use it here.
22871+
\LMHash{}%
22872+
A reified type identifies the underlying Dart type in the sense that
22873+
it supports equality tests with other reified types as follows.
22874+
Let $o_1$ and $o_2$ be reified types that reify $S_1$ respectively $S_2$,
22875+
and let $o_3$ be an object which is not a reified type.
22876+
Let $U_j$ be the transitive alias expansion of $S_j$, for $j \in 1 .. 3$,
22877+
and let $v_j$ be a fresh variable whose value is $o_j$, for $j \in 1 .. 3$.
22878+
It is then guaranteed that \code{$v_1$ == $v_2$} if{}f
22879+
\NormalizedTypeOf{$U_1$} and \NormalizedTypeOf{$U_2$}
22880+
are syntactically equal,
22881+
up to equivalence of bound variables
22882+
and up to designations of the same type using different syntax
22883+
(\commentary{e.g., \code{C} and \code{prefix.C} may denote the same type}).
22884+
Conversely, \code{$v_1$ == $v_3$} will yield false.
22885+
22886+
\commentary{%
22887+
Note that we do not equate primitive top types.
22888+
For example,
22889+
reified types reifying \code{List<\VOID>} and \code{List<\DYNAMIC>}
22890+
are not equal.
22891+
However, a type variable which is declared by a function type
22892+
is treated as if it were consistently renamed to a fresh name,
22893+
thus making types identical if possible
22894+
(also known as alpha equivalence).
22895+
For example:%
22896+
}
22897+
22898+
\begin{dartCode}
22899+
\TYPEDEF{} F = \VOID{} \FUNCTION{}<X>(X);
22900+
\TYPEDEF{} G = \VOID{} \FUNCTION{}<Y>(Y);
22901+
\\
22902+
\VOID{} main() \{
22903+
print(F == G); // \comment{Prints 'true'.}
22904+
\}
22905+
\end{dartCode}
22906+
22907+
\commentary{%
22908+
Note that reified types have a primitive operator \lit{==}
22909+
(\ref{theOperatorEqualsEquals}).
22910+
This property cannot be assumed for arbitrary expressions of type \code{Type}.
22911+
For instance, we can declare
22912+
\code{\CLASS\,\,MyType\,\,\EXTENDS\,\,Type \{\ldots\}}
22913+
and override operator \lit{==}.%
22914+
}
22915+
22916+
\LMHash{}%
22917+
Let $e_1$ and $e_2$ be constant expressions
22918+
(\ref{constants})
22919+
evaluating to $o_1$ respectively $o_2$,
22920+
which are reified types reifying the Dart types $S_1$ respecively $S_2$.
22921+
Let $v_1$ and $v_2$ be fresh variables bound to $o_1$ respectively $o_2$
22922+
We then have \code{identical($v_1$, $v_2$)} if{}f
22923+
\code{$S_1$\,\,==\,\,$S_2$}.
22924+
22925+
\commentary{%
22926+
In other words, constant reified types are canonicalized.
22927+
For runtime implementations which implement identity by choosing a
22928+
canonical representative for the equivalence class of equal instances,
22929+
the choice of what type object to canonicalize to is not
22930+
observable in the language.
22931+
}
22932+
22933+
\rationale{%
22934+
As mentioned at the beginning of this section,
22935+
reified types support a very limited kind of introspective reflection.
22936+
In particular, we can compare reified types for equality,
22937+
and in the case where two reified types are equal
22938+
it is known that they reify types which are subtypes of each other
22939+
(that is, they are ``the same type'' with respect to subtyping).
22940+
But we cannot compare reified types for any inequality, that is,
22941+
we cannot determine whether one is a subtype of the other.
22942+
It is also impossible to deconstruct a reified type.
22943+
E.g., we cannot obtain the reified type for \code{$T$}
22944+
by performing operations on a given reified type for \code{List<$T$>}.
22945+
This design was chosen in order to ensure that Dart programs
22946+
do not incur the substantial implications in terms of
22947+
program size and run-time performance
22948+
that are very difficult to avoid
22949+
when a more powerful form of reflection is supported.%
22950+
}
22951+
22952+
2288522953
\subsection{Function Types}
2288622954
\LMLabel{functionTypes}
2288722955

@@ -22934,7 +23002,7 @@ \subsection{Function Types}
2293423002
}
2293523003

2293623004

22937-
\subsection{Type \FUNCTION}
23005+
\subsection{Type Function}
2293823006
\LMLabel{functionType}
2293923007

2294023008
\LMHash{}%
@@ -22975,7 +23043,7 @@ \subsection{Type \FUNCTION}
2297523043
}
2297623044

2297723045

22978-
\subsection{Type \DYNAMIC}
23046+
\subsection{Type dynamic}
2297923047
\LMLabel{typeDynamic}
2298023048

2298123049
\LMHash{}%
@@ -24105,44 +24173,20 @@ \subsubsection{Null promotion}
2410524173
These are extended as per
2410624174
[separate proposal](https://github.com/dart-lang/language/blob/master/resources/type-system/flow-analysis.md).
2410724175

24108-
\subsubsection{Runtime type equality operator}
24109-
24110-
!!!TODO!!!
24111-
24112-
Two objects $T_1$ and $T_2$ which are instances of \code{Type} (that
24113-
is, runtime type objects) are considered equal if and only if the
24114-
runtime type objects $T_1$ and $T_2$ corresponds to the types $S_1$
24115-
and $S_2$ respectively, and the normal forms \NormalizedTypeOf{$S_1$}
24116-
and \NormalizedTypeOf{$S_2$} are syntactically equal up to equivalence
24117-
of bound variables. Note that we do not equate primitive top types.
24118-
\code{List<\VOID>} and \code{List<\DYNAMIC>} are still considered
24119-
distinct runtime type objects. Note that we also do not equate
24120-
function types which differ in the placement of \REQUIRED{} on
24121-
parameter types.
24122-
24123-
\subsubsection{Constant evaluation and canonicalization}
24124-
24125-
\paragraph{Type literals}
24126-
24127-
Two constant type literals $T_1$ and $T_2$ compare as identical if they
24128-
are equal using the definition of runtime type equality specified above.
24129-
24130-
For runtime implementations which implement identity by choosing a
24131-
canonical representative for the equivalence class of equal instances,
24132-
the choice of what type object to canonicalize to is not
24133-
observable in the language.
2413424176

2413524177
\paragraph{Constant instances}
2413624178

24137-
Any two
24138-
instances which are otherwise identical except for their generic type arguments
24139-
shall be considered identical if those generic type arguments compare equal
24140-
using the definition of runtime type object equality defined above. That is,
24141-
comparison (or canonicalization) of constant instances of generic classes is
24142-
performed relative to the normal forms of their generic type arguments.
24143-
Hence, an instance of
24144-
\code{$C$<$T_0$>} compares identical to \code{C<$T_1$>} if $T_0$ and $T_1$ have the same normal form
24145-
(up to the identity of bound variables), and the objects are otherwise
24179+
!!!TODO!!!
24180+
24181+
Any two instances which are otherwise identical except for their
24182+
generic type arguments shall be considered identical if those generic
24183+
type arguments compare equal using the definition of runtime type
24184+
object equality defined above. That is, comparison (or
24185+
canonicalization) of constant instances of generic classes is
24186+
performed relative to the normal forms of their generic type
24187+
arguments. Hence, an instance of \code{$C$<$T_0$>} compares identical
24188+
to \code{C<$T_1$>} if $T_0$ and $T_1$ have the same normal form (up to
24189+
the identity of bound variables), and the objects are otherwise
2414624190
identical.
2414724191

2414824192
Implementations of the Dart runtime semantics rely on canonicalization of

0 commit comments

Comments
 (0)