Skip to content

Commit e2703f8

Browse files
munificenteernstg
andauthored
[patterns] Specify that coercions don't happen during destructuring. (#2926)
* [patterns] Specify that coercions don't happen during destructuring. Fix #2914. * Update accepted/future-releases/0546-patterns/feature-specification.md Co-authored-by: Erik Ernst <[email protected]> --------- Co-authored-by: Erik Ernst <[email protected]>
1 parent abca38c commit e2703f8

File tree

1 file changed

+40
-114
lines changed

1 file changed

+40
-114
lines changed

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

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

55
Status: Accepted
66

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

99
Note: This proposal is broken into a couple of separate documents. See also
1010
[records][] and [exhaustiveness][].
@@ -1687,8 +1687,9 @@ To orchestrate this, type inference on patterns proceeds in three phases:
16871687
Using the pattern's type schema as a context type (if not in a matching
16881688
context), infer missing types on the value expression. This is the existing
16891689
type inference rules on expressions. It yields a complete static type for
1690-
the matched value. This process may also insert implicit coercions and casts
1691-
from `dynamic` in the matched value expression.
1690+
the matched value. As usual, when a context type is applied to an
1691+
expression, the process may also insert implicit coercions and casts from
1692+
`dynamic` in the matched value expression.
16921693

16931694
*For example:*
16941695

@@ -1708,28 +1709,38 @@ To orchestrate this, type inference on patterns proceeds in three phases:
17081709
17091710
3. **Calculate the static type of the pattern.** Using that value type, recurse
17101711
through the pattern again downwards to the leaf subpatterns filling in any
1711-
missing types in the pattern. This process may also insert implicit
1712-
coercions and casts from `dynamic` when values flow into a pattern during
1713-
matching.
1712+
missing types in the pattern. This process may also insert casts from
1713+
`dynamic` when values flow into a pattern during matching.
17141714
17151715
*For example:*
17161716
17171717
```dart
1718-
T id<T>(T t) => t;
1719-
(T Function<T>(T), dynamic) record = (id, 'str');
1720-
var (int Function(int) f, String s) = record;
1718+
(dynamic, dynamic) record = (123, 'str');
1719+
var (int n, String s) = record;
17211720
```
17221721
17231722
*Since the right-hand is not a record literal, we can't use the pattern's
17241723
context type schema to insert coercions when the record is being created.
1725-
However, the matched value type `(T Function<T>(T), dynamic)` is allowed by
1726-
the record pattern's required type `(Object?, Object?)`, the field matched
1727-
value type `T Function<T>(T)` is allowed by the field required type `int
1728-
Function(int)`, and the field matched value type `dynamic` is allowed by the
1729-
field required type `String)`. So the declaration is valid. Coercions are
1730-
inserted after destructuring each record field before passing them to the
1731-
field subpatterns. At runtime, when the record is destructured during
1732-
matching, the coercions are applied. This is specified below.*
1724+
However, the matched value type `(dynamic, dynamic)` is allowed by the
1725+
record pattern's required type `(Object?, Object?)`, and the matched
1726+
value type `dynamic` for each field is allowed by the required types
1727+
of the fields, i.e., `int` and `String`, so the declaration is
1728+
valid. Casts from dynamic are inserted after destructuring each record field
1729+
before passing them to the field subpatterns.*
1730+
1731+
However, implicit call tear-off and implicit generic function instantiations
1732+
are *not* inserted during destructuring. *Those implicit coercions are only
1733+
inserted in _value expressions_ based on a pattern's context type schema,
1734+
not during destructuring. For example:*
1735+
1736+
```dart
1737+
T id<T>(T t) => t;
1738+
(T Function<T>(T),) record = (id,);
1739+
var (int Function(int) f,) = record; // ERROR.
1740+
```
1741+
1742+
*This is a compile-time error since the record field type `T Function<T>(T)`
1743+
is not allowed by the field subpattern required type `int Function(int)`.*
17331744
17341745
#### Pattern context type schema
17351746
@@ -2115,106 +2126,16 @@ To type check a pattern `p` being matched against a value of type `M`:
21152126
21162127
If `p` with required type `T` is in an irrefutable context:
21172128
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'.*
2124-
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`.
2128-
2129-
*Each pattern that requires a certain type can be thought of as an
2130-
"assignment point" where an implicit coercion may happen when a value flows
2131-
in during matching. Examples:*
2132-
2133-
```dart
2134-
var record = (x: 1 as dynamic);
2135-
var (x: String _) = record;
2136-
```
2137-
2138-
*Here no coercion is performed on the record pattern since `(x: dynamic)` is
2139-
a subtype of `(x: Object?)` (the record pattern's required type). But an
2140-
implicit cast from `dynamic` is inserted when the destructured `x` field
2141-
flows into the inner `String _` pattern, since `dynamic` is not a subtype of
2142-
`String`. In this example, the cast will fail and throw an exception.*
2129+
* If `M` is `dynamic` and `T` is not `dynamic`, then an implicit cast from
2130+
`dynamic` to `T` is made before the pattern binds the value, tests the
2131+
value's type, destructures the value, or invokes a function with the value
2132+
as a target or argument. *During destructuring, an implicit cast from
2133+
`dynamic` is allowed, which may fail and throw an exception at runtime.*
21432134
2144-
```dart
2145-
T id<T>(T t) => t;
2146-
var record = (x: id);
2147-
var (x: int Function(int) _) = record;
2148-
var list = [id];
2149-
var [int Function(int) idInt && String Function(String) idString] = list;
2150-
```
2151-
2152-
*Here, again no coercion is applied to the record flowing in to the record
2153-
pattern, but a generic instantiation is inserted when the destructured field
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.*
2158-
2159-
*We only insert coercions in irrefutable contexts:*
2160-
2161-
```dart
2162-
dynamic d = 1;
2163-
if (d case String s) print('then') else print('else');
2164-
```
2165-
2166-
*This prints "else" instead of throwing an exception because we don't insert
2167-
a _cast_ from `dynamic` to `String` and instead let the `String s` pattern
2168-
_test_ the value's type, which then fails to match.*
2169-
2170-
* Next, it is a compile-time error if `M` is not assignable to `T`.
2135+
* Else, it is a compile-time error if `M` is not a subtype of `T`.
21712136
*Destructuring, variable, and identifier patterns can only be used in
21722137
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.*
2138+
destructuring and variable binding won't fail to match.*
22182139
22192140
### Pattern uses (static semantics)
22202141
@@ -3608,6 +3529,11 @@ Here is one way it could be broken down into separate pieces:
36083529
36093530
## Changelog
36103531
3532+
### 2.25
3533+
3534+
- Call tear-off and generic function instantiations are not inserted during
3535+
destructuring.
3536+
36113537
### 2.24
36123538
36133539
- Specify the required type of patterns in cases where this was left implicit.

0 commit comments

Comments
 (0)