Skip to content

Commit abca38c

Browse files
authored
Adjust several locations where required types are discussed (#2884)
Adjusted several locations where required types are discussed
1 parent 2a3a253 commit abca38c

File tree

1 file changed

+128
-38
lines changed

1 file changed

+128
-38
lines changed

accepted/future-releases/0546-patterns/feature-specification.md

Lines changed: 128 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Author: Bob Nystrom
44

55
Status: Accepted
66

7-
Version 2.23 (see [CHANGELOG](#CHANGELOG) at end)
7+
Version 2.24 (see [CHANGELOG](#CHANGELOG) at end)
88

99
Note: This proposal is broken into a couple of separate documents. See also
1010
[records][] and [exhaustiveness][].
@@ -630,7 +630,7 @@ It is a compile-time error if:
630630
element) will ever match. Duplicate keys are most likely a typo in the
631631
code.*
632632

633-
* Any two record keys which both have primitive `==` are equal. *Since
633+
* Any two record keys which both have primitive equality are equal. *Since
634634
records don't have defined identity, we can't use the previous rule to
635635
detect identical records. But records do support an equality test known at
636636
compile time if all of their fields do, so we use that.*
@@ -639,7 +639,7 @@ It is a compile-time error if:
639639

640640
* The `...` element is not the last element in the map pattern.
641641

642-
*Note that we don't require map keys to have primitive `==` methods to enable
642+
*Note that we don't require map keys to have primitive equality, to enable
643643
more flexibility in key types. If the keys have user-defined `==` methods, then
644644
it's possible to have keys that are equal according to those `==` methods, but
645645
the compiler won't detect it.*
@@ -687,8 +687,8 @@ Field subpatterns can be in one of three forms:
687687
variable with the same name.
688688

689689
As a convenience, the identifier can be omitted and inferred from `pattern`.
690-
In this case the subpattern must be a variable pattern which may be wrapped
691-
in a unary pattern. The field name is then inferred from the name in the
690+
In this case the subpattern must be a variable pattern which may be wrapped
691+
in a unary pattern. The field name is then inferred from the name in the
692692
variable pattern. These pairs of patterns are each equivalent:
693693

694694
```dart
@@ -1869,7 +1869,7 @@ contexts, and the pattern type schema is only used in irrefutable contexts.
18691869
18701870
Once the value a pattern is matched against has a static type (which means
18711871
downwards inference on it using the pattern's context type schema is complete),
1872-
we can type check the pattern.
1872+
we can type check the pattern and fill in missing parts (e.g., type arguments).
18731873
18741874
Also variable, list, map, record, and object patterns only match a value of a
18751875
certain *required type*. These patterns are prohibited in an irrefutable context
@@ -1884,27 +1884,56 @@ var [int a, b] = <num>[1, 2]; // List<num>.
18841884

18851885
To type check a pattern `p` being matched against a value of type `M`:
18861886

1887-
* **Logical-or** and **logical-and**: Type check each branch using `M` as the
1888-
matched value type.
1887+
* **Logical-or**: Type check the first subpattern using `M` as the
1888+
matched value type; type check the second subpattern using the matched value
1889+
which is obtained from the assumption that the first operand failed to
1890+
match *(this may cause promotion, e.g., when the left pattern is `==
1891+
null`)*. The required type of the pattern is `Object?`.
1892+
*The context types will be used to perform checks on each operand, whose
1893+
required types may be more strict.*
1894+
1895+
* **Logical-and**: Type check the first operand using `M` as the matched
1896+
value type, and type check the second operand using the (possibly promoted)
1897+
matched value type obtained from the match-succeeded continuation of the
1898+
first operand. The required type of the pattern is `Object?`.
1899+
*The chosen matched value type will be used to perform checks on each
1900+
operand, whose required types may be more strict.*
1901+
1902+
* **Relational**: Consider the relational pattern `op c` where `op` is one
1903+
of the following operators: `==`, `!=`, `<`, `<=`, `>=`, `>`, and `c` is an
1904+
expression.
18891905

1890-
* **Relational**:
1906+
A compile-time error occurs if `M` is `void`.
1907+
1908+
If `M` is `dynamic` or `Never`: Type check `c` in context `_`; an error
1909+
occurs if `c` is not a constant expression; no further checks are
1910+
performed. Otherwise *(when `M` is not `dynamic` or `Never`)*:
1911+
1912+
1. A compile-time error occurs if `M` does not have an operator `op`,
1913+
and there is no available and applicable extension operator `op`.
1914+
Let `A` be the type of the formal parameter of the given operator
1915+
declaration, and let `R` be the return type.
1916+
1917+
2. A compile-time error occurs if `R` is not assignable to `bool`.
18911918

1892-
1. Let `C` be the static type of the right operand constant expression.
1919+
3. Type check `c` with context type `A?` when `op` is `==` or `!=`, and
1920+
with context type `A` otherwise. A compile-time error occurs if
1921+
`c` is not a constant expression. Let `C` be the static type of `c`.
18931922

1894-
2. If the operator is a comparison (`<`, `<=`, `>`, or `>=`), then it is a
1895-
compile-time error if:
1923+
4. If `op` is `==` or `!=` then a compile-time error occurs if `C` is not
1924+
assignable to `A?`. Otherwise `op` is `<`, `<=`, `>=`, or `>`, and a
1925+
compile-time error occurs if `C` is not assignable to `A`.
18961926

1897-
* `M` does not define that operator,
1898-
* `C` is not assignable to the operator's parameter type,
1899-
* or if the operator's return type is not assignable to `bool`.
1927+
*The language screens out `null` before calling the underlying `==`
1928+
method, which is why `A?` is the allowed type for equality checks. Since
1929+
`Object` declares `==` to accept `Object` on the right, this compile-time
1930+
error can only happen if a user-defined class has an override of `==` with a
1931+
`covariant` parameter.*
19001932

1901-
3. Else the operator is `==` or `!=`. It is a compile-time error if `C` is
1902-
not assignable to `T?` where `T` is `M`'s `==` method parameter type.
1903-
*The language screens out `null` before calling the underlying `==`
1904-
method, which is why `T?` is the allowed type. Since Object declares
1905-
`==` to accept `Object` on the right, this compile-time error can only
1906-
happen if a user-defined class has an override of `==` with a
1907-
`covariant` parameter.*
1933+
The required type of `p` is `Object?`. *The static checks mentioned above
1934+
may give rise to compile-time errors, but there is no static type which
1935+
would give rise to exactly those checks, so we cannot specify the desired
1936+
checks simply by using any particular required type.*
19081937

19091938
* **Cast**:
19101939

@@ -1913,6 +1942,8 @@ To type check a pattern `p` being matched against a value of type `M`:
19131942

19141943
2. Type-check the subpattern using `X` as the matched value type.
19151944

1945+
The required type of `p` is `Object?`.
1946+
19161947
* **Null-check** or **null-assert**:
19171948

19181949
1. Let `N` be [**NonNull**][nonnull](`M`).
@@ -1926,8 +1957,8 @@ To type check a pattern `p` being matched against a value of type `M`:
19261957
int-to-double, and implicit generic function instantiation.*
19271958

19281959
*Note that the pattern's value must be a constant, but there is no longer a
1929-
restriction that it must have a primitive operator `==`. Unlike switch cases
1930-
in current Dart, you can have a constant with a user-defined operator `==`
1960+
restriction that it must have primitive equality. Unlike switch cases in
1961+
current Dart, you can have a constant with a user-defined operator `==`
19311962
method. This lets you use constant patterns for user-defined types with
19321963
custom value semantics.*
19331964

@@ -1979,7 +2010,7 @@ To type check a pattern `p` being matched against a value of type `M`:
19792010
static type of the variable introduced by `p`.
19802011
19812012
* **Parenthesized**: Type-check the inner subpattern using `M` as the matched
1982-
value type.
2013+
value type. The required type of `p` is the required type of the subpattern.
19832014
19842015
* **List**:
19852016
@@ -2063,8 +2094,8 @@ To type check a pattern `p` being matched against a value of type `M`:
20632094
* **Object**:
20642095
20652096
1. Resolve the object name to a type `X`. It is a compile-time error if the
2066-
name does not refer to a type. Apply downwards inference from `M` to
2067-
infer type arguments for `X` if needed.
2097+
name does not refer to a type. Apply downwards inference with context
2098+
type `M` to infer type arguments for `X`, if needed.
20682099
20692100
2. For each field subpattern of `p`, with name `n` and subpattern `f`:
20702101
@@ -2084,16 +2115,16 @@ To type check a pattern `p` being matched against a value of type `M`:
20842115
20852116
If `p` with required type `T` is in an irrefutable context:
20862117
2087-
* It is a compile-time error if `M` is not assignable to `T`. *Destructuring,
2088-
variable, and identifier patterns can only be used in declarations and
2089-
assignments if we can statically tell that the destructuring and variable
2090-
binding won't fail to match (though it may still throw at runtime if the
2091-
matched value type is `dynamic`).*
2118+
* If `M` is not a subtype of `T` and `M` is not `dynamic` then an attempt to
2119+
insert an implicit coercion is made before the pattern binds the value,
2120+
tests the value's type, destructures the value, or invokes a function with
2121+
the value as a target or argument.
2122+
2123+
*Coercions are described in a separate section below, named 'Coercions'.*
20922124
2093-
* Else if `M` is not a subtype of `T` then an implicit coercion or cast is
2094-
inserted before the pattern binds the value, tests the value's type,
2095-
destructures the value, or invokes a function with the value as a target or
2096-
argument.
2125+
If a coercion is inserted, this yields a new matched value type which is
2126+
the value of `M` used in the next step. If no coercion is inserted, the
2127+
next step proceeds with the already given `M`.
20972128
20982129
*Each pattern that requires a certain type can be thought of as an
20992130
"assignment point" where an implicit coercion may happen when a value flows
@@ -2107,18 +2138,23 @@ If `p` with required type `T` is in an irrefutable context:
21072138
*Here no coercion is performed on the record pattern since `(x: dynamic)` is
21082139
a subtype of `(x: Object?)` (the record pattern's required type). But an
21092140
implicit cast from `dynamic` is inserted when the destructured `x` field
2110-
flows into the inner `String _` pattern since `dynamic` is not a subtype of
2141+
flows into the inner `String _` pattern, since `dynamic` is not a subtype of
21112142
`String`. In this example, the cast will fail and throw an exception.*
21122143
21132144
```dart
21142145
T id<T>(T t) => t;
21152146
var record = (x: id);
21162147
var (x: int Function(int) _) = record;
2148+
var list = [id];
2149+
var [int Function(int) idInt && String Function(String) idString] = list;
21172150
```
21182151
21192152
*Here, again no coercion is applied to the record flowing in to the record
21202153
pattern, but a generic instantiation is inserted when the destructured field
2121-
`x` field flows into the inner `int Function(int) _` pattern.*
2154+
`x` flows into the inner `int Function(int) _` pattern. Similarly, no
2155+
coercion is applied to the list, but generic function instantiations are
2156+
applied when the list element flows into each of the operands of the
2157+
logical-and pattern.*
21222158
21232159
*We only insert coercions in irrefutable contexts:*
21242160
@@ -2131,6 +2167,55 @@ If `p` with required type `T` is in an irrefutable context:
21312167
a _cast_ from `dynamic` to `String` and instead let the `String s` pattern
21322168
_test_ the value's type, which then fails to match.*
21332169
2170+
* Next, it is a compile-time error if `M` is not assignable to `T`.
2171+
*Destructuring, variable, and identifier patterns can only be used in
2172+
declarations and assignments if we can statically tell that the
2173+
destructuring and variable binding won't fail to match (though it may still
2174+
throw at runtime if the matched value type is `dynamic`).*
2175+
2176+
### Coercions
2177+
2178+
The language specification documents do not yet define a unified concept of
2179+
_coercions_, and they do not define what it means to _attempt to insert a
2180+
coercion_. However, the following is intended to establish these concepts
2181+
in a sufficiently precise manner to enable the implementation of patterns:
2182+
2183+
The language supports the following mechanisms, which are the currently
2184+
existing _coercions_:
2185+
2186+
- Implicit generic function instantiation.
2187+
- Implicit tear-off of a `.call` method.
2188+
- Implicit tear-off of a `.call` method, which is then generically instantiated.
2189+
2190+
These mechanisms are applied at specific locations *(known as assignment
2191+
points)*, and they are enabled by specific pairs of context types and
2192+
expression types.
2193+
2194+
*For example, implicit generic function instantiation is applied to an
2195+
expression `e` whose type is a generic function type `G` in the case where
2196+
the context type is a non-generic function type `F`, and `e` occurs at an
2197+
assignment point. A list of actual type arguments are selected by type
2198+
inference, yielding the expression `e<T1, .. Tk>`, such that the resulting
2199+
expression has a type which is a subtype of `F`. If the type inference
2200+
fails, or the resulting type is not a subtype of `F` then a compile-time
2201+
error occurs. The implicit tear-off proceeds in a similar manner; it
2202+
transforms `e` to `e.call` when the static type of `e` is an interface type
2203+
that has a method named `call`, and the context type is a function type or
2204+
`Function`.*
2205+
2206+
An _attempt to insert a coercion_ is the procedure which is described above. It
2207+
may end in an application of the mechanism, or it may end in a compile-time
2208+
error.
2209+
2210+
*In the context of pattern type checking, the compile-time error will
2211+
generally report a lack of assignability, not, e.g., a failed type
2212+
inference.*
2213+
2214+
*Note that the ability for an integer literal to have the type `double` is not a
2215+
coercion *(for example `double d = 1;` makes `1` an integer literal with type
2216+
`double`)*. Similarly, an implicit downcast from `dynamic` is not considered a
2217+
coercion.*
2218+
21342219
### Pattern uses (static semantics)
21352220
21362221
It is a compile-time error if the type of an expression in a guard clause is not
@@ -3523,6 +3608,11 @@ Here is one way it could be broken down into separate pieces:
35233608
35243609
## Changelog
35253610
3611+
### 2.24
3612+
3613+
- Specify the required type of patterns in cases where this was left implicit.
3614+
- Specify the handling of coercions during irrefutable pattern matching.
3615+
35263616
### 2.23
35273617
35283618
- Suggest warnings that implementations may want to report.

0 commit comments

Comments
 (0)