[XL] Change in dart/sdk[main]: Add documentation for new diagnostics

34 views
Skip to first unread message

Brian Wilkerson (Gerrit)

unread,
Mar 2, 2023, 3:44:24 PM3/2/23
to Konstantin Shcheglov, dart-analys...@google.com, dart-fe-te...@google.com, dart-uxr...@google.com, rev...@dartlang.org, Brian Wilkerson

Attention is currently required from: Konstantin Shcheglov.

Brian Wilkerson would like Konstantin Shcheglov to review this change.

View Change

Add documentation for new diagnostics

I have not yet run the analyzer's generators just to keep the generated
version of the changes out of the review.

There are 10 parser diagnostics that are not being documented:
- ParserErrorCode.INVALID_CONSTANT_CONST_PREFIX
- ParserErrorCode.INVALID_CONSTANT_PATTERN_BINARY
- ParserErrorCode.INVALID_CONSTANT_PATTERN_DUPLICATE_CONST
- ParserErrorCode.INVALID_CONSTANT_PATTERN_EMPTY_RECORD_LITERAL
- ParserErrorCode.INVALID_CONSTANT_PATTERN_GENERIC
- ParserErrorCode.INVALID_CONSTANT_PATTERN_NEGATION
- ParserErrorCode.INVALID_CONSTANT_PATTERN_UNARY
- ParserErrorCode.FINAL_MIXIN_CLASS
- ParserErrorCode.INTERFACE_MIXIN_CLASS
- ParserErrorCode.SEALED_MIXIN_CLASS

Let me know if you think any of those need documentation.

Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
---
M pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
M pkg/analyzer/messages.yaml
M pkg/analyzer/test/verify_diagnostics_test.dart
M pkg/front_end/messages.yaml
4 files changed, 1,754 insertions(+), 39 deletions(-)

diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
index 32f9fb2..daae08b 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -3072,9 +3072,9 @@
const MessageCode messageEmptyRecordTypeNamedFieldsList = const MessageCode(
"EmptyRecordTypeNamedFieldsList",
index: 129,
- problemMessage: r"""Record type named fields list can't be empty.""",
- correctionMessage:
- r"""Try adding a record type named field to the list.""");
+ problemMessage:
+ r"""The list of named fields in a record type can't be empty.""",
+ correctionMessage: r"""Try adding a named field to the list.""");

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeEncoding = messageEncoding;
@@ -10982,7 +10982,7 @@
const MessageCode("RecordLiteralOnePositionalFieldNoTrailingComma",
index: 127,
problemMessage:
- r"""Record literal with one field requires a trailing comma.""",
+ r"""A record literal with exactly one positional field requires a trailing comma.""",
correctionMessage: r"""Try adding a trailing comma.""");

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -10994,7 +10994,7 @@
const MessageCode("RecordLiteralZeroFieldsWithTrailingComma",
index: 128,
problemMessage:
- r"""Record literal without fields can't have a trailing comma.""",
+ r"""A record literal without fields can't have a trailing comma.""",
correctionMessage: r"""Try removing the trailing comma.""");

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -11006,7 +11006,7 @@
const MessageCode("RecordTypeOnePositionalFieldNoTrailingComma",
index: 131,
problemMessage:
- r"""Record type with one entry requires a trailing comma.""",
+ r"""A record type with exactly one positional field requires a trailing comma.""",
correctionMessage: r"""Try adding a trailing comma.""");

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -11018,7 +11018,7 @@
const MessageCode("RecordTypeZeroFieldsButTrailingComma",
index: 130,
problemMessage:
- r"""Record type without fields can't have a trailing comma.""",
+ r"""A record type without fields can't have a trailing comma.""",
correctionMessage: r"""Try removing the trailing comma.""");

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml
index fc3db9c..cbd0189 100644
--- a/pkg/analyzer/messages.yaml
+++ b/pkg/analyzer/messages.yaml
@@ -1133,6 +1133,50 @@
comment: |-
Parameters:
0: the name of the base class being implemented
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when either a class declaration or a
+ mixin declaration is used in an `extends`, `implements`, `with`, or `on`
+ clause in a way that isn't allowed given the modifiers on the declaration.
+
+ The message indicates how the declaration is being used and why it isn't
+ allowed.
+
+ #### Example
+
+ Given a file named `a.dart` that defines a base class `A`:
+
+ ```dart
+ %uri="lib/a.dart"
+ base class A {}
+ ```
+
+ The following code produces this diagnostic because the class `B`
+ implements the class `A`, but the `base` modifier prevents `A` from being
+ implemented outside of the library where it's defined:
+
+ ```dart
+ import 'a.dart';
+
+ final class B implements [!A!] {}
+ ```
+
+ #### Common fixes
+
+ If a different type should be used, then replace the type:
+
+ ```dart
+ class B implements C {}
+ class C {}
+ ```
+
+ If there isn't a different type that would be appropriate, then remove the
+ type, and possibly the whole clause:
+
+ ```dart
+ class B {}
+ ```
BASE_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY:
sharedName: INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
problemMessage: "The mixin '{0}' can't be implemented outside of its library because it's a base mixin."
@@ -1598,10 +1642,40 @@
int y = x as int;
```
CLASS_USED_AS_MIXIN:
- problemMessage: "The class '{0}' can't be used as a mixin because it isn't a mixin class nor a mixin."
+ problemMessage: "The class '{0}' can't be used as a mixin because it's neither a mixin class nor a mixin."
comment: |-
Parameters:
0: the name of the class being used as a mixin
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a class is used in the `with`
+ clause and that class is neither a `mixin class` nor a `mixin`.
+
+ #### Example
+
+ The following code produces this diagnostic because :
+
+ ```dart
+ class M {}
+ class C with [!M!] {}
+ ```
+
+ #### Common fixes
+
+ If the class can be a pure mixin, then change `class` to `mixin`:
+
+ ```dart
+ mixin M {}
+ class C with M {}
+ ```
+
+ If the class needs to be both a class and a mixin, then add `mixin`:
+
+ ```dart
+ mixin class M {}
+ class C with M {}
+ ```
CLASS_INSTANTIATION_ACCESS_TO_INSTANCE_MEMBER:
sharedName: CLASS_INSTANTIATION_ACCESS_TO_MEMBER
problemMessage: "The instance member '{0}' can't be accessed on a class instantiation."
@@ -1731,6 +1805,84 @@
problemMessage: Constant values from a deferred library can't be used in patterns.
correctionMessage: Try removing the keyword 'deferred' from the import.
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a pattern contains a value that
+ is declared in a library that is imported using a deferred import.
+ Constants are evaluated at compile time, and values from deferred
+ libraries aren't available at compile time.
+
+ For more information, see the language tour's coverage of
+ [deferred loading](https://dart.dev/guides/language/language-tour#lazily-loading-a-library).
+
+ #### Example
+
+ Given a file (`a.dart`) that defines the constant `zero`:
+
+ ```dart
+ %uri="lib/a.dart"
+ const zero = 0;
+ ```
+
+ The following code produces this diagnostic because the constant pattern
+ `a.zero` is imported using a deferred import:
+
+ ```dart
+ import 'a.dart' deferred as a;
+
+ void f(int x) {
+ switch (x) {
+ case a.[!zero!]:
+ // ...
+ break;
+ }
+ }
+ ```
+
+ #### Common fixes
+
+ If you need to reference the constant from the imported library, then
+ remove the `deferred` keyword:
+
+ ```dart
+ import 'a.dart' as a;
+
+ void f(int x) {
+ switch (x) {
+ case a.zero:
+ // ...
+ break;
+ }
+ }
+ ```
+
+ If you need to reference the constant from the imported library and also
+ need the imported library to be deferred, then rewrite the switch
+ statement as a sequence of `if` statements:
+
+ ```dart
+ import 'a.dart' deferred as a;
+
+ void f(int x) {
+ if (x == a.zero) {
+ // ...
+ }
+ }
+ ```
+
+ If you don't need to reference the constant, then replace the case
+ expression:
+
+ ```dart
+ void f(int x) {
+ switch (x) {
+ case 0:
+ // ...
+ break;
+ }
+ }
+ ```
SET_ELEMENT_FROM_DEFERRED_LIBRARY:
sharedName: COLLECTION_ELEMENT_FROM_DEFERRED_LIBRARY
problemMessage: "Constant values from a deferred library can't be used as values in a 'const' set literal."
@@ -2587,12 +2739,13 @@
#### Description

The analyzer produces this diagnostic when the class of object used as a
- key in a constant map literal implements the `==` operator. The
- implementation of constant maps uses the `==` operator, so any
- implementation other than the one inherited from `Object` requires
- executing arbitrary code at compile time, which isn't supported.
+ key in a constant map literal implements either the `==` operator, the
+ getter `hashCode`, or both. The implementation of constant maps uses both
+ the `==` operator and the `hashCode` getter, so any implementation other
+ than the ones inherited from `Object` requires executing arbitrary code at
+ compile time, which isn't supported.

- #### Example
+ #### Examples

The following code produces this diagnostic because the constant map
contains a key whose type is `C`, and the class `C` overrides the
@@ -2608,9 +2761,24 @@
const map = {[!C()!] : 0};
```

+ The following code produces this diagnostic because the constant map
+ contains a key whose type is `C`, and the class `C` overrides the
+ implementation of `hashCode`:
+
+ ```dart
+ class C {
+ const C();
+
+ int get hashCode => 3;
+ }
+
+ const map = {[!C()!] : 0};
+ ```
+
#### Common fixes

- If you can remove the implementation of `==` from the class, then do so:
+ If you can remove the implementation of `==` and `hashCode` from the
+ class, then do so:

```dart
class C {
@@ -2620,8 +2788,8 @@
const map = {C() : 0};
```

- If you can't remove the implementation of `==` from the class, then make
- the map be non-constant:
+ If you can't remove the implementation of `==` and `hashCode` from the
+ class, then make the map be non-constant:

```dart
class C {
@@ -2671,10 +2839,11 @@
#### Description

The analyzer produces this diagnostic when the class of object used as an
- element in a constant set literal implements the `==` operator. The
- implementation of constant sets uses the `==` operator, so any
- implementation other than the one inherited from `Object` requires
- executing arbitrary code at compile time, which isn't supported.
+ element in a constant set literal implements either the `==` operator, the
+ getter `hashCode`, or both. The implementation of constant sets uses both
+ the `==` operator and the `hashCode` getter, so any implementation other
+ than the ones inherited from `Object` requires executing arbitrary code at
+ compile time, which isn't supported.

#### Example

@@ -2692,9 +2861,24 @@
const set = {[!C()!]};
```

+ The following code produces this diagnostic because the constant set
+ contains an element whose type is `C`, and the class `C` overrides the
+ implementation of `hashCode`:
+
+ ```dart
+ class C {
+ const C();
+
+ int get hashCode => 3;
+ }
+
+ const map = {[!C()!]};
+ ```
+
#### Common fixes

- If you can remove the implementation of `==` from the class, then do so:
+ If you can remove the implementation of `==` and `hashCode` from the
+ class, then do so:

```dart
class C {
@@ -2704,8 +2888,8 @@
const set = {C()};
```

- If you can't remove the implementation of `==` from the class, then make
- the set be non-constant:
+ If you can't remove the implementation of `==` and `hashCode` from the
+ class, then make the set be non-constant:

```dart
class C {
@@ -2944,6 +3128,48 @@
problemMessage: The expression of a constant pattern must be a valid constant.
correctionMessage: Try making the expression a valid constant.
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a constant pattern has an
+ expression that isn't a valid constant.
+
+ #### Example
+
+ The following code produces this diagnostic because the constant pattern
+ `i` isn't a constant:
+
+ ```dart
+ void f(int e, int i) {
+ switch (e) {
+ case [!i!]:
+ break;
+ }
+ }
+ ```
+
+ #### Common fixes
+
+ If the value that should be matched is known, then replace the expression
+ with a constant:
+
+ ```dart
+ void f(int e, int i) {
+ switch (e) {
+ case 0:
+ break;
+ }
+ }
+ ```
+
+ If the value that should be matched isn't known, then rewrite the code to
+ not use a pattern:
+
+ ```dart
+ void f(int e, int i) {
+ if (e == i) {}
+ }
+ ```
CONTINUE_LABEL_INVALID:
previousName: CONTINUE_LABEL_ON_SWITCH
hasPublishedDocs: true
@@ -3455,6 +3681,37 @@
comment: |-
Parameters:
0: the duplicated name
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when either a record literal or a
+ record type annotation contains a field whose name is the same as a
+ previous field in the same literal or type.
+
+ #### Examples
+
+ The following code produces this diagnostic because the record literal has
+ two fields named `a`:
+
+ ```dart
+ var r = (a: 1, [!a!]: 2);
+ ```
+
+ The following code produces this diagnostic because the record type
+ annotation has two fields named `a`, one a positional field and the other
+ a named field:
+
+ ```dart
+ void f((int a, {int [!a!]}) r) {}
+ ```
+
+ #### Common fixes
+
+ Rename one or both of the fields:
+
+ ```dart
+ var r = (a: 1, b: 2);
+ ```
DUPLICATE_FIELD_FORMAL_PARAMETER:
problemMessage: "The field '{0}' can't be initialized by multiple parameters in the same constructor."
correctionMessage: Try removing one of the parameters, or using different fields.
@@ -3597,21 +3854,196 @@
comment: |-
Parameters:
0: the name of the variable
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a pattern variable is assigned
+ more than one value in a pattern assignment.
+
+ #### Example
+
+ The following code produces this diagnostic because the variable `a` is
+ assigned twice in the pattern `(a, a)`:
+
+ ```dart
+ int f((int, int) r) {
+ int a;
+ (a, [!a!]) = r;
+ return a;
+ }
+ ```
+
+ #### Common fixes
+
+ If you need to capture all of the values, then use a unique variable for
+ each of the patterns being matched:
+
+ ```dart
+ int f((int, int) r) {
+ int a, b;
+ (a, b) = r;
+ return a + b;
+ }
+ ```
+
+ If some of the values don't need to be captured, then use a wildcard
+ pattern for the ones you don't need:
+
+ ```dart
+ int f((int, int) r) {
+ int a;
+ (_, a) = r;
+ return a;
+ }
+ ```
DUPLICATE_PATTERN_FIELD:
problemMessage: The field '{0}' is already matched in this pattern.
correctionMessage: Try removing the duplicate field.
comment: |-
Parameters:
0: the name of the field
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a record pattern matches the
+ same field more than once and when an object pattern matches the same
+ getter more than once.
+
+ #### Examples
+
+ The following code produces this diagnostic because the record field `a`
+ is matched twice in the same record pattern:
+
+ ```dart
+ void f(({int a, int b}) r) {
+ switch (r) {
+ case (a: 1, [!a!]: 2):
+ return;
+ }
+ }
+ ```
+
+ The following code produces this diagnostic because the getter `f` is
+ matched twice in the same object pattern:
+
+ ```dart
+ void f(Object o) {
+ switch (0) {
+ case C(f: 1, [!f!]: 2):
+ return;
+ }
+ }
+ class C {
+ int? f;
+ }
+ ```
+
+ #### Common fixes
+
+ If the pattern should match for more than one value of the duplicated
+ field, then use a logical-or pattern:
+
+ ```dart
+ void f(({int a, int b}) r) {
+ switch (r) {
+ case (a: 1, b: _) || (a: 2, b: _):
+ break;
+ }
+ }
+ ```
+
+ If the pattern should match against multiple fields, then change the name
+ of one of the fields:
+
+ ```dart
+ void f(({int a, int b}) r) {
+ switch (r) {
+ case (a: 1, b: 2):
+ return;
+ }
+ }
+ ```
DUPLICATE_REST_ELEMENT_IN_PATTERN:
problemMessage: At most one rest element is allowed in a list or map pattern.
correctionMessage: Try removing the duplicate rest element.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when there's more than one rest
+ pattern in either a list or map pattern. The first rest pattern will
+ capture all of the otherwise uncaptured values, so there's nothing left
+ for the other rest patterns to capture.
+
+ #### Example
+
+ The following code produces this diagnostic because there are two rest
+ patterns in the list pattern:
+
+ ```dart
+ void f(List<int> x) {
+ if (x case [0, ..., [!...!]]) {}
+ }
+ ```
+
+ #### Common fixes
+
+ Remove all but one of the rest patterns:
+
+ ```dart
+ void f(List<int> x) {
+ if (x case [0, ...]) {}
+ }
+ ```
DUPLICATE_VARIABLE_PATTERN:
problemMessage: The variable '{0}' is already defined in this pattern.
correctionMessage: Try renaming the variable.
comment: |-
Parameters:
0: the name of the variable
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a branch of a logical-and
+ pattern declares a variable that is already declared in an earlier branch
+ of the same pattern.
+
+ #### Example
+
+ The following code produces this diagnostic because the variable `a` is
+ declared in both branches of the logical-and pattern:
+
+ ```dart
+ void f((int, int) r) {
+ if (r case (var a, 0) && (0, var [!a!])) {
+ print(a);
+ }
+ }
+ ```
+
+ #### Common fixes
+
+ If you need to capture the matched value in multiple branches, then change
+ the names of the variables so that they are unique:
+
+ ```dart
+ void f((int, int) r) {
+ if (r case (var a, 0) && (0, var b)) {
+ print(a + b);
+ }
+ }
+ ```
+
+ If you only need to capture the matched value on one branch, then remove
+ the variable pattern from all but one branch, integrating the guard
+ (`when`) clauses if there are any:
+
+ ```dart
+ void f((int, int) r) {
+ if (r case (var a, 0) && (0, var _)) {
+ print(a);
+ }
+ }
+ ```
ENUM_CONSTANT_SAME_NAME_AS_ENCLOSING:
problemMessage: "The name of the enum constant can't be the same as the enum's name."
correctionMessage: Try renaming the constant.
@@ -3880,12 +4312,76 @@
problemMessage: Two keys in a map pattern can't be equal.
correctionMessage: Change or remove the duplicate key.
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic a key in a map pattern is the same
+ as a previous key in the same map pattern. The same key can't be matched
+ twice.
+
+ #### Example
+
+ The following code produces this diagnostic because the key `'a'` appears
+ twice:
+
+ ```dart
+ void f(Map<String, int> x) {
+ if (x case {'a': 1, [!'a'!]: 2}) {}
+ }
+ ```
+
+ #### Common fixes
+
+ If you are trying to match two different keys, then change one of the keys
+ in the pattern:
+
+ ```dart
+ void f(Map<String, int> x) {
+ if (x case {'a': 1, 'b': 2}) {}
+ }
+ ```
+
+ If you are trying to match the same key, but allow any one of multiple
+ patterns to match, the use a logical-or pattern:
+
+ ```dart
+ void f(Map<String, int> x) {
+ if (x case {'a': 1 || 2}) {}
+ }
+ ```
EXPECTED_ONE_LIST_PATTERN_TYPE_ARGUMENTS:
problemMessage: List patterns require one type argument or none, but {0} found.
correctionMessage: Try adjusting the number of type arguments.
comment: |-
Parameters:
0: the number of provided type arguments
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a list pattern has more than
+ one type argument. The pattern can have either one type argument or zero
+ type arguments, but can't have more than one.
+
+ #### Example
+
+ The following code produces this diagnostic because the list pattern
+ (`[0]`) has two type arguments:
+
+ ```dart
+ void f(Object x) {
+ if (x case [!<int, int>!][0]) {}
+ }
+ ```
+
+ #### Common fixes
+
+ Remove all but one of the type arguments:
+
+ ```dart
+ void f(Object x) {
+ if (x case <int>[0]) {}
+ }
+ ```
EXPECTED_ONE_LIST_TYPE_ARGUMENTS:
problemMessage: "List literals require one type argument or none, but {0} found."
correctionMessage: Try adjusting the number of type arguments.
@@ -3979,6 +4475,34 @@
comment: |-
Parameters:
0: the number of provided type arguments
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a map pattern has either one
+ type argument or more than two type arguments. The pattern can have either
+ two type arguments or zero type arguments, but can't have any other
+ number.
+
+ #### Example
+
+ The following code produces this diagnostic because the map pattern
+ (`<int>{}`) has one type argument:
+
+ ```dart
+ void f(Object x) {
+ if (x case [!<int>!]{}) {}
+ }
+ ```
+
+ #### Common fixes
+
+ Add or remove type arguments until there are two:
+
+ ```dart
+ void f(Object x) {
+ if (x case <int, int>{}) {}
+ }
+ ```
EXPORT_INTERNAL_LIBRARY:
problemMessage: "The library '{0}' is internal and can't be exported."
hasPublishedDocs: true
@@ -6205,12 +6729,199 @@
comment: |-
Parameters:
0: the name of the pattern variable
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a pattern variable that is
+ declared on both branches of a logical-or pattern has a different type on
+ one branch than on the other. It is also produced when the variable has a
+ different finality on one branch than on the other. The two are required
+ to have the same type and finality so that the type and finality of the
+ variable can be known in code that's guarded by the logical-or pattern.
+
+ #### Examples
+
+ The following code produces this diagnostic because the variable `a` is
+ defined to be an `int` on one branch and a `double` on the other:
+
+ ```dart
+ void f(Object? x) {
+ if (x case (int a) || (double [!a!])) {
+ print(a);
+ }
+ }
+ ```
+
+ The following code produces this diagnostic because the variable `a` is
+ `final` in the first branch and isn't `final` in the second branch:
+
+ ```dart
+ void f(Object? x) {
+ if (x case (final int a) || (int [!a!])) {
+ print(a);
+ }
+ }
+ ```
+
+ #### Common fixes
+
+ If the finality of the variable is different, decide whether it should be
+ `final` or not `final` and make the cases consistent:
+
+ ```dart
+ void f(Object? x) {
+ if (x case (int a) || (int a)) {
+ print(a);
+ }
+ }
+ ```
+
+ If the type of the variable is different and the type isn't critical to
+ the condition being matched, then ensure that the variable has the same
+ type on both branches:
+
+ ```dart
+ void f(Object? x) {
+ if (x case (num a) || (num a)) {
+ print(a);
+ }
+ }
+ ```
+
+ If the type of the variable is different and the type is critical to the
+ condition being matched, then consider breaking the condition into
+ multiple `if` statements or `case` clauses:
+
+ ```dart
+ void f(Object? x) {
+ if (x case int a) {
+ print(a);
+ } else if (x case double a) {
+ print(a);
+ }
+ }
+ ```
INCONSISTENT_PATTERN_VARIABLE_SHARED_CASE_SCOPE:
problemMessage: "The variable '{0}' doesn't have the same type and/or finality in all cases that share this body."
correctionMessage: Try declaring the variable pattern with the same type and finality in all cases.
comment: |-
Parameters:
0: the name of the pattern variable
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when there are multiple case clauses
+ in a switch statement and at least one of them declares a variable that is
+ referenced in the shared statement, but the variable is either not
+ declared in all of the case clauses or it is declared in inconsistent
+ ways.
+
+ If the variable isn't declared in all of the case clauses, then it won't
+ have a value when one of the clauses that doesn't declare the variable is
+ the one that matched.
+
+ If the variable is declared in inconsistent ways, either being `final` in
+ some cases and not `final` in others or having a different type in
+ different cases, then the semantics of what the type or finality of the
+ variable should be are not defined.
+
+ #### Examples
+
+ The following code produces this diagnostic because the variable `a` is
+ only declared in one of the case clauses, and won't have a value if the
+ second clause is the one that matched `x`:
+
+ ```dart
+ void f(Object? x) {
+ switch (x) {
+ case int a when a > 0:
+ case 0:
+ [!a!];
+ }
+ }
+ ```
+
+ The following code produces this diagnostic because the variable `a`,
+ while being assigned in all of the case clauses, doesn't have then same
+ type associated with it in every clause:
+
+ ```dart
+ void f(Object? x) {
+ switch (x) {
+ case int a when a < 0:
+ case num a when a > 0:
+ [!a!];
+ }
+ }
+ ```
+
+ The following code produces this diagnostic because the variable `a` is
+ `final` in the first case clause and isn't `final` in the second case
+ clause:
+
+ ```dart
+ void f(Object? x) {
+ switch (x) {
+ case final int a when a < 0:
+ case int a when a > 0:
+ [!a!];
+ }
+ }
+ ```
+
+ #### Common fixes
+
+ If the variable isn't declared in all of the cases, and you need to
+ reference it in the statements, then declare it in the other cases:
+
+ ```dart
+ void f(Object? x) {
+ switch (x) {
+ case int a when a > 0:
+ case int a when a == 0:
+ a;
+ }
+ }
+ ```
+
+ If the variable isn't declared in all of the cases, and you don't need to
+ reference it in the statements, then remove the references to it and
+ remove the declarations from the other cases:
+
+ ```dart
+ void f(int x) {
+ switch (x) {
+ case > 0:
+ case 0:
+ }
+ }
+ ```
+
+ If the type of the variable is different, decide type the variable should
+ have and make the cases consistent:
+
+ ```dart
+ void f(Object? x) {
+ switch (x) {
+ case num a when a < 0:
+ case num a when a > 0:
+ a;
+ }
+ }
+ ```
+
+ If the finality of the variable is different, decide whether it should be
+ `final` or not `final` and make the cases consistent:
+
+ ```dart
+ void f(Object? x) {
+ switch (x) {
+ case final int a when a < 0:
+ case final int a when a > 0:
+ a;
+ }
+ }
+ ```
INITIALIZER_FOR_NON_EXISTENT_FIELD:
problemMessage: "'{0}' isn't a field in the enclosing class."
correctionMessage: "Try correcting the name to match an existing field, or defining a field named '{0}'."
@@ -7168,6 +7879,71 @@
problemMessage: Record field names can't be the same as a member from 'Object'.
correctionMessage: Try using a different name for the field.
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when either a record literal or a
+ record type annotation has a field whose name is invalid. The name is
+ invalid if it is
+ - the same as one of the members defined on `Object`
+ - private (starts with `_`)
+ - the same as the name of a positional field (an exception is made if the
+ field is a positional field with the specified name)
+
+ #### Examples
+
+ The following code produces this diagnostic because the record literal has
+ a field named `toString`, which is a method defined on `Object`:
+
+ ```dart
+ var r = (a: 1, [!toString!]: 4);
+ ```
+
+ The following code produces this diagnostic because the record type
+ annotation has a field named `hashCode`, which is a getter defined on
+ `Object`:
+
+ ```dart
+ void f(({int a, int [!hashCode!]}) r) {}
+ ```
+
+ The following code produces this diagnostic because the record literal has
+ a private field named `_a`:
+
+ ```dart
+ var r = ([!_a!]: 1, b: 2);
+ ```
+
+ The following code produces this diagnostic because the record type
+ annotation has a private field named `_a`:
+
+ ```dart
+ void f(({int [!_a!], int b}) r) {}
+ ```
+
+ The following code produces this diagnostic because the record literal has
+ a field named `$1`, which is also the name of a different positional
+ parameter:
+
+ ```dart
+ var r = ([!$1!]: 2, 1);
+ ```
+
+ The following code produces this diagnostic because the record type
+ annotation has a field named `$1`, which is also the name of a different
+ positional parameter:
+
+ ```dart
+ void f((int, String, {int [!$1!]}) r) {}
+ ```
+
+ #### Common fixes
+
+ Rename the field:
+
+ ```dart
+ var r = (a: 1, d: 4);
+ ```
INVALID_FIELD_NAME_PRIVATE:
sharedName: INVALID_FIELD_NAME
problemMessage: Record field names can't be private.
@@ -8540,6 +9316,65 @@
MISSING_OBJECT_PATTERN_GETTER_NAME:
problemMessage: The getter name is not specified explicitly, and the pattern is not a variable.
correctionMessage: Try specifying the getter name explicitly, or using a variable pattern.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when an object pattern has a
+ property matcher that doesn't have either a getter name before the colon
+ or a variable pattern from which the getter name can be inferred.
+
+ #### Example
+
+ The following code produces this diagnostic because there is no getter
+ name before the colon in the object pattern (`C(: 0)`):
+
+ ```dart
+ abstract class C {
+ int get f;
+ }
+
+ void f(C c) {
+ switch (c) {
+ case C([!: 0!]):
+ break;
+ }
+ }
+ ```
+
+ #### Common fixes
+
+ If you need to use the actual value of the property within the pattern's
+ scope, then add a variable pattern where the name of the variable is the
+ same as the name of the property being matched:
+
+ ```dart
+ abstract class C {
+ int get f;
+ }
+
+ void f(C c) {
+ switch (c) {
+ case C(: var f):
+ print(f);
+ }
+ }
+ ```
+
+ If you don't need to use the actual value of the property within the
+ pattern's scope, then add the name of the property before the colon:
+
+ ```dart
+ abstract class C {
+ int get f;
+ }
+
+ void f(C c) {
+ switch (c) {
+ case C(f: 0):
+ break;
+ }
+ }
+ ```
MISSING_REQUIRED_ARGUMENT:
problemMessage: "The named parameter '{0}' is required, but there's no corresponding argument."
correctionMessage: Try adding the required argument.
@@ -8581,6 +9416,65 @@
comment: |-
Parameters:
0: the name of the variable pattern
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when one branch of a logical-or
+ pattern doesn't declare a variable that is declared on the other branch of
+ the same pattern.
+
+ #### Example
+
+ The following code produces this diagnostic because the right-hand side of
+ the logical-or pattern doesn't declare the variable `a`:
+
+ ```dart
+ void f((int, int) r) {
+ if (r case (var a, 0) || [!(0, _)!]) {
+ print(a);
+ }
+ }
+ ```
+
+ #### Common fixes
+
+ If the variable needs to be referenced in the controlled statements, then
+ add a declaration of the variable to every branch of the logical-or
+ pattern:
+
+ ```dart
+ void f((int, int) r) {
+ if (r case (var a, 0) || (0, var a)) {
+ print(a);
+ }
+ }
+ ```
+
+ If the variable doesn't need to be reference in the controlled statements,
+ then remove the declaration of the variable from every branch of the
+ logical-or pattern:
+
+ ```dart
+ void f((int, int) r) {
+ if (r case (_, 0) || (0, _)) {
+ print('found a zero');
+ }
+ }
+ ```
+
+ If the variable needs to be referenced if one branch of the pattern
+ matches but not when the other matches, then break the pattern into two
+ pieces:
+
+ ```dart
+ void f((int, int) r) {
+ if (r case (var a, 0)) {
+ print(a);
+ } else if (r case (0, _)) {
+ print('found a zero');
+ }
+ }
+ ```
MIXINS_SUPER_CLASS:
sharedName: IMPLEMENTS_SUPER_CLASS
problemMessage: "'{0}' can't be used in both the 'extends' and 'with' clauses."
@@ -9881,6 +10775,40 @@
problemMessage: Key expressions in map patterns must be constants.
correctionMessage: Try using constants instead.
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a key in a map pattern isn't a
+ constant expression.
+
+ #### Example
+
+ The following code produces this diagnostic because the key `A()` isn't a
+ constant:
+
+ ```dart
+ void f(Object x) {
+ if (x case {[!A()!]: 0}) {}
+ }
+
+ class A {
+ const A();
+ }
+ ```
+
+ #### Common fixes
+
+ Use a constant for the key:
+
+ ```dart
+ void f(Object x) {
+ if (x case {const A(): 0}) {}
+ }
+
+ class A {
+ const A();
+ }
+ ```
NON_CONSTANT_MAP_VALUE:
problemMessage: The values in a const map literal must be constant.
correctionMessage: "Try removing the keyword 'const' from the map literal."
@@ -9921,6 +10849,36 @@
problemMessage: The relational pattern expression must be a constant.
correctionMessage: Try using a constant instead.
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when the value in a relational
+ pattern expression isn't a constant expression.
+
+ #### Example
+
+ The following code produces this diagnostic because the operand of the `>`
+ operator, `a`, isn't a constant:
+
+ ```dart
+ final a = 0;
+
+ void f(int x) {
+ if (x case > [!a!]) {}
+ }
+ ```
+
+ #### Common fixes
+
+ Replace the value with a constant expression:
+
+ ```dart
+ const a = 0;
+
+ void f(int x) {
+ if (x case > a) {}
+ }
+ ```
NON_CONSTANT_SET_ELEMENT:
problemMessage: The values in a const set literal must be constants.
correctionMessage: "Try removing the keyword 'const' from the set literal."
@@ -9972,6 +10930,46 @@
Parameters:
0: the type of the switch scrutinee
1: the unmatched space
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a `switch` statement that is
+ switching over an exhastive type, such as an enum, doesn't have a case
+ that will match one or more of the possible values of the type, such as
+ the constants defined by the enum.
+
+ #### Example
+
+ The following code produces this diagnostic because the switch statement
+ doesn't have a case for the constant `E.three`:
+
+ ```dart
+ enum E { one, two, three }
+
+ void f(E e) {
+ [!switch!] (e) {
+ case E.one:
+ case E.two:
+ }
+ }
+ ```
+
+ #### Common fixes
+
+ Add a case for each of the constants that aren't currently being matched:
+
+ ```dart
+ enum E { one, two, three }
+
+ void f(E e) {
+ switch (e) {
+ case E.one:
+ case E.two:
+ break;
+ case E.three:
+ }
+ }
+ ```
NON_FINAL_FIELD_IN_ENUM:
problemMessage: Enums can only declare final fields.
correctionMessage: Try making the field final.
@@ -11341,8 +12339,60 @@
part of 'test.dart';
```
PATTERN_ASSIGNMENT_NOT_LOCAL_VARIABLE:
- problemMessage: Only local variables or formal parameters can be used in pattern assignments.
+ problemMessage: Only local variables can be assigned in pattern assignments.
correctionMessage: Try assigning to a local variable.
+ comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a pattern assignment assigns a
+ value to anything other than a local variable. Patterns can't assign to
+ fields or top-level variables.
+
+ #### Example
+
+ The following code produces this diagnostic because the field `x` is being
+ assigned a value in a pattern assignment:
+
+ ```dart
+ class C {
+ var x = 0;
+
+ void f((int, int) r) {
+ ([!x!], _) = r;
+ }
+ }
+ ```
+
+ #### Common fixes
+
+ If the code is cleaner when using a pattern assignment, then rewrite the
+ code to assign the value to a local variable, assigning the non-local
+ variable separately:
+
+ ```dart
+ class C {
+ var x = 0;
+
+ void f((int, int) r) {
+ var (a, _) = r;
+ x = a;
+ }
+ }
+ ```
+
+ If the code is cleaner without using a pattern assignment, then rewrite
+ the code to not use a pattern assignment:
+
+ ```dart
+ class C {
+ var x = 0;
+
+ void f((int, int) r) {
+ x = r.$1;
+ }
+ }
+ ```
PATTERN_TYPE_MISMATCH_IN_IRREFUTABLE_CONTEXT:
problemMessage: "The matched value of type '{0}' isn't assignable to the required type '{1}'."
correctionMessage: "Try changing the required type of the pattern, or the matched value type."
@@ -11350,9 +12400,85 @@
Parameters:
0: the matched type
1: the required type
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when the type of the value on the
+ right-hand side of a pattern assignment or pattern declaration isn't
+ assignable to the type required by the pattern being assigned to.
+
+ The analyzer produces this diagnostic when the type of the value being
+ matched isn't assignable to the type required by the
+ [irrefutable pattern][] being used to match it.
+
+ #### Example
+
+ The following code produces this diagnostic because `x` might not be a
+ `String` and hence might not match the object pattern:
+
+ ```dart
+ void f(Object x) {
+ var [!String(length: a)!] = x;
+ print(a);
+ }
+ ```
+
+ #### Common fixes
+
+ Change the code so that the type of the expression on the right-hand side
+ matches the type required by the pattern:
+
+ ```dart
+ void f(String x) {
+ var String(length: a) = x;
+ print(a);
+ }
+ ```
PATTERN_VARIABLE_ASSIGNMENT_INSIDE_GUARD:
problemMessage: Pattern variables can't be assigned inside the guard of the enclosing guarded pattern.
correctionMessage: Try assigning to a different variable.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a pattern variable is assigned
+ a value inside a guard (`when`) clause.
+
+ #### Example
+
+ The following code produces this diagnostic because the variable `a` is
+ assigned a value inside the guard clause:
+
+ ```dart
+ void f(int x) {
+ if (x case var a when ([!a!] = 1) > 0) {
+ print(a);
+ }
+ }
+ ```
+
+ #### Common fixes
+
+ If there's a value you need to capture, then assign it to a different
+ variable:
+
+ ```dart
+ void f(int x) {
+ var b;
+ if (x case var a when (b = 1) > 0) {
+ print(a + b);
+ }
+ }
+ ```
+
+ If there isn't a value you need to capture, then remove the assignment:
+
+ ```dart
+ void f(int x) {
+ if (x case var a when 1 > 0) {
+ print(a);
+ }
+ }
+ ```
POSITIONAL_SUPER_FORMAL_PARAMETER_WITH_POSITIONAL_ARGUMENT:
problemMessage: Positional super parameters can't be used when the super constructor invocation has a positional argument.
correctionMessage: Try making all the positional parameters passed to the super constructor be either all super parameters or all normal parameters.
@@ -12452,15 +13578,176 @@
REFUTABLE_PATTERN_IN_IRREFUTABLE_CONTEXT:
problemMessage: Refutable patterns can't be used in an irrefutable context.
correctionMessage: Try using an if-case, a 'switch' statement, or a 'switch' expression instead.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a [refutable pattern][] is used
+ in a context where only an [irrefutable pattern][] is allowed.
+
+ The refutable patterns that are disallowed are
+ - logical-or
+ - relational
+ - null-check
+ - constant
+
+ The contexts that are checked are
+ - pattern-based variable declarations
+ - pattern-based for loops
+ - assignments with a pattern on the left-hand side
+
+ #### Example
+
+ The following code produces this diagnostic because the null-check
+ pattern, which is a refutable pattern, is in a pattern-based variable
+ declaration, which doesn't allow refutable patterns:
+
+ ```dart
+ void f(int? x) {
+ var ([!_?!]) = x;
+ }
+ ```
+
+ #### Common fixes
+
+ Rewrite the code to not use a refutable pattern in an irrefutable context.
RELATIONAL_PATTERN_OPERATOR_RETURN_TYPE_NOT_ASSIGNABLE_TO_BOOL:
problemMessage: The return type of operators used in relational patterns must be assignable to 'bool'.
correctionMessage: Try updating the operator declaration to return 'bool'.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a relational pattern references
+ an operator that doesn't produce a value of type `bool`.
+
+ #### Example
+
+ The following code produces this diagnostic because the operator `>`, used
+ in the relational pattern `> c2`, returns a value of type `int` rather
+ than a `bool`:
+
+ ```dart
+ class C {
+ const C();
+
+ int operator >(C c) => 3;
+
+ bool operator <(C c) => false;
+ }
+
+ const C c2 = C();
+
+ void f(C c1) {
+ if (c1 case [!>!] c2) {}
+ }
+ ```
+
+ #### Common fixes
+
+ If there's a different operator that should be used, then change the
+ operator:
+
+ ```dart
+ class C {
+ const C();
+
+ int operator >(C c) => 3;
+
+ bool operator <(C c) => false;
+ }
+
+ const C c2 = C();
+
+ void f(C c1) {
+ if (c1 case < c2) {}
+ }
+ ```
+
+ If the operator is expected to return `bool`, then update the declaration
+ of the operator:
+
+ ```dart
+ class C {
+ const C();
+
+ bool operator >(C c) => true;
+
+ bool operator <(C c) => false;
+ }
+
+ const C c2 = C();
+
+ void f(C c1) {
+ if (c1 case > c2) {}
+ }
+ ```
REST_ELEMENT_WITH_SUBPATTERN_IN_MAP_PATTERN:
problemMessage: A rest element in a map pattern can't have a subpattern.
correctionMessage: Try removing the subpattern.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a rest pattern in a map pattern
+ has a subpattern. In Dart, there is no notion of a subset of a map, so
+ there isn't anything to match against the subpattern.
+
+ #### Example
+
+ The following code produces this diagnostic because the rest pattern has a
+ subpattern:
+
+ ```dart
+ void f(Map<String, int> m) {
+ switch (m) {
+ case {'a': var a, ... [!> 0!]}:
+ print(a);
+ }
+ }
+ ```
+
+ #### Common fixes
+
+ Remove the subpattern:
+
+ ```dart
+ void f(Map<String, int> m) {
+ switch (m) {
+ case {'a': var a, ...}:
+ print(a);
+ }
+ }
+ ```
REST_ELEMENT_NOT_LAST_IN_MAP_PATTERN:
problemMessage: A rest element in a map pattern must be the last element.
correctionMessage: Try moving the rest element to be the last element.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a map pattern contains entries
+ after a rest pattern. The rest pattern will match map entries whose keys
+ aren't matched by any of the entries in the pattern. To make those
+ semantics clear the language requires that the rest pattern be the last
+ entry in the list.
+
+ #### Example
+
+ The following code produces this diagnostic because the rest pattern is
+ followed by another map pattern entry (`0: _`):
+
+ ```dart
+ void f(Map<int, String> x) {
+ if (x case {[!...!], 0: _}) {}
+ }
+ ```
+
+ #### Common fixes
+
+ Move the rest pattern to the end of the map pattern:
+
+ ```dart
+ void f(Map<int, String> x) {
+ if (x case {0: _, ...}) {}
+ }
+ ```
RETHROW_OUTSIDE_CATCH:
problemMessage: A rethrow must be inside of a catch clause.
correctionMessage: "Try moving the expression into a catch clause, or using a 'throw' expression."
@@ -12897,6 +14184,32 @@
0: the name of the subtype that is not 'base', 'final', or 'sealed'
1: the name of the supertype which is 'base' or 'final'
2: the modifier on the supertype
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a class or mixin isn't either
+ `base`, `final` or `sealed`, but it has a supertype, either direct or
+ indirect, that is either `base` or `final`.
+
+ #### Example
+
+ The following code produces this diagnostic because the class `B` is a
+ subtype of `A`, and `A` is a `base` class, but `B` is neither `base`,
+ `final` or `sealed`:
+
+ ```dart
+ base class A {}
+ class [!B!] extends A {}
+ ```
+
+ #### Common fixes
+
+ Add either `base`, `final` or `sealed` to the class or mixin declaration:
+
+ ```dart
+ base class A {}
+ final class B extends A {}
+ ```
SUPER_FORMAL_PARAMETER_TYPE_IS_NOT_SUBTYPE_OF_ASSOCIATED:
problemMessage: The type '{0}' of this parameter isn't a subtype of the type '{1}' of the associated super constructor parameter.
correctionMessage: Try removing the explicit type annotation from the parameter.
@@ -15515,6 +16828,35 @@
VARIABLE_PATTERN_KEYWORD_IN_DECLARATION_CONTEXT:
problemMessage: Variable patterns in declaration context can't specify 'var' or 'final' keyword.
correctionMessage: Try removing the keyword.
+ comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a variable pattern is used
+ within a declaration context.
+
+ #### Example
+
+ The following code produces this diagnostic because the variable patterns
+ in the record pattern are in a declaration context:
+
+ ```dart
+ void f((int, int) r) {
+ var ([!var x!], var y) = r;
+ print(x + y);
+ }
+ ```
+
+ #### Common fixes
+
+ Remove the `var` or `final` keyword(s) within the variable pattern:
+
+ ```dart
+ void f((int, int) r) {
+ var (x, y) = r;
+ print(x + y);
+ }
+ ```
VARIABLE_TYPE_MISMATCH:
problemMessage: "A value of type '{0}' can't be assigned to a const variable of type '{1}'."
correctionMessage: "Try using a subtype, or removing the 'const' keyword"
@@ -18718,6 +20060,42 @@
correctionMessage: Try removing the set literal around the expression.
hasPublishedDocs: false
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a function that has a return
+ type of `void`, `Future<void>`, or `FutureOr<void>` uses an expression
+ function body (`=>`) and the returned value is a literal set containing.
+
+ There is no value in returning a value from a `void` function, though the
+ language allows it. In this particular case it's often due to a
+ misunderstanding about the syntax. The braces aren't necessary and can be
+ removed.
+
+ #### Example
+
+ The following code produces this diagnostic because the closure being
+ passed to `g` has a return type of `void`, but is returning a set:
+
+ ```dart
+ void f() {
+ g(() => [!{1}!]);
+ }
+
+ void g(void Function() p) {}
+ ```
+
+ #### Common fixes
+
+ Remove the braces from around the value:
+
+ ```dart
+ void f() {
+ g(() => 1);
+ }
+
+ void g(void Function() p) {}
+ ```
UNNECESSARY_TYPE_CHECK_FALSE:
sharedName: UNNECESSARY_TYPE_CHECK
problemMessage: "Unnecessary type check; the result is always 'false'."
@@ -18762,7 +20140,74 @@
comment: No parameters.
UNREACHABLE_SWITCH_CASE:
problemMessage: "This case is covered by the previous cases."
+ correctionMessage: Try removing the case clause, or restructuring the preceding patterns.
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a `case` clause in a `switch`
+ statement doesn't match anything because all of the matchable values are
+ matched by an earlier `case` clause.
+
+ #### Example
+
+ The following code produces this diagnostic because the pattern `< 3` will
+ match any values less than `3`, which includes `1`, so the pattern `== 1`
+ will never be reached with a value that could match it:
+
+ ```dart
+ void f(int x) {
+ switch (x) {
+ case < 3:
+ break;
+ case == [!1:
+ break;!]
+ }
+ }
+ ```
+
+ #### Common fixes
+
+ If the flagged case needs to be handled differently than the cases before
+ it, then reorder the `case` clauses to allow it to be reached:
+
+ ```dart
+ void f(int x) {
+ switch (x) {
+ case == 1:
+ break;
+ case < 3:
+ break;
+ }
+ }
+ ```
+
+ If a simple reordering won't solve the problem, then enhance the preceding
+ patterns so that they won't incorrectly match the `case` clause being
+ flagged:
+
+ ```dart
+ void f(int x) {
+ switch (x) {
+ case < 3 && != 1:
+ break;
+ case == 1:
+ break;
+ }
+ }
+ ```
+
+ If the flagged case doesn't need to be handled differently, then remove
+ it:
+
+ ```dart
+ void f(int x) {
+ switch (x) {
+ case < 3:
+ break;
+ }
+ }
+ ```
UNUSED_ELEMENT:
problemMessage: "The declaration '{0}' isn't referenced."
correctionMessage: "Try removing the declaration of '{0}'."
@@ -20161,10 +21606,63 @@
problemMessage: The null-assert pattern will have no effect because the matched type isn't nullable.
correctionMessage: Try replacing the null-assert pattern with its nested pattern.
comment: No parameters.
+
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a null-assert pattern is used
+ to match a value that isn't nullable.
+
+ #### Example
+
+ The following code produces this diagnostic because the variable `x` isn't
+ nullable:
+
+ ```dart
+ void f(int x) {
+ if (x case var a[!!!] when a > 0) {}
+ }
+ ```
+
+ #### Common fixes
+
+ Remove the null assert pattern:
+
+ ```dart
+ void f(int x) {
+ if (x case var a when a > 0) {}
+ }
+ ```
UNNECESSARY_NULL_CHECK_PATTERN:
problemMessage: The null-check pattern will have no effect because the matched type isn't nullable.
correctionMessage: Try replacing the null-check pattern with its nested pattern.
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a null-check pattern is used to
+ match a value that isn't nullable.
+
+ #### Example
+
+ The following code produces this diagnostic because the value `x` isn't
+ nullable:
+
+ ```dart
+ void f(int x) {
+ if (x case var a[!?!] when a > 0) {}
+ }
+ ```
+
+ #### Common fixes
+
+ Remove the null assert pattern:
+
+ ```dart
+ void f(int x) {
+ if (x case var a when a > 0) {}
+ }
+ ```
WarningCode:
ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER:
problemMessage: "The argument type '{0}' can't be assigned to the parameter type '{1} Function(Object)' or '{1} Function(Object, StackTrace)'."
@@ -20403,6 +21901,44 @@
Parameters:
0: the matched value type
1: the constant value type
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a constant pattern can never
+ match the value being matched because the type of the constant is known to
+ never match the type of the value being matched.
+
+ #### Example
+
+ The following code produces this diagnostic because the type of the
+ constant pattern `(true)` is `bool`, and the type of the value being
+ matched (`x`) is `int`, and a Boolean can never match an integer:
+
+ ```dart
+ void f(int x) {
+ if (x case [!true!]) {}
+ }
+ ```
+
+ #### Common fixes
+
+ If the type of the value is correct, then rewrite the pattern to be
+ compatible:
+
+ ```dart
+ void f(int x) {
+ if (x case 3) {}
+ }
+ ```
+
+ If the type of the constant is correct, then rewrite the value to be
+ compatible:
+
+ ```dart
+ void f(bool x) {
+ if (x case true) {}
+ }
+ ```
DEAD_CODE:
aliasFor: HintCode.DEAD_CODE
comment: This is the new replacement for [HintCode.DEAD_CODE].
diff --git a/pkg/analyzer/test/verify_diagnostics_test.dart b/pkg/analyzer/test/verify_diagnostics_test.dart
index 0f9b0e0..6d6d830 100644
--- a/pkg/analyzer/test/verify_diagnostics_test.dart
+++ b/pkg/analyzer/test/verify_diagnostics_test.dart
@@ -189,15 +189,23 @@
} else if (snippet.indexOf(errorRangeStart, rangeEnd) > 0) {
_reportProblem('More than one error range in example');
}
+ String content;
+ try {
+ content = snippet.substring(0, rangeStart) +
+ snippet.substring(rangeStart + errorRangeStart.length, rangeEnd) +
+ snippet.substring(rangeEnd + errorRangeEnd.length);
+ } on RangeError catch (exception) {
+ _reportProblem(exception.message.toString());
+ content = '';
+ }
return _SnippetData(
- snippet.substring(0, rangeStart) +
- snippet.substring(rangeStart + errorRangeStart.length, rangeEnd) +
- snippet.substring(rangeEnd + errorRangeEnd.length),
- rangeStart,
- rangeEnd - rangeStart - 2,
- auxiliaryFiles,
- experiments,
- languageVersion);
+ content,
+ rangeStart,
+ rangeEnd - rangeStart - 2,
+ auxiliaryFiles,
+ experiments,
+ languageVersion,
+ );
}

/// Extract the snippets of Dart code from [documentationParts] that are
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 64c9c80..8176c15 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -337,10 +337,36 @@
}

RecordLiteralOnePositionalFieldNoTrailingComma:
- problemMessage: "Record literal with one field requires a trailing comma."
+ problemMessage: "A record literal with exactly one positional field requires a trailing comma."
correctionMessage: "Try adding a trailing comma."
analyzerCode: ParserErrorCode.RECORD_LITERAL_ONE_POSITIONAL_NO_TRAILING_COMMA
index: 127
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a record literal with a single
+ positional field doesn't have a trailing comma after the field.
+
+ In some locations a record literal with a single positional field could
+ also be a parenthesized expression. A trailing comma is required to
+ disambiguate these two valid interpretations.
+
+ #### Example
+
+ The following code produces this diagnostic because the record literal has
+ one positional field but doesn't have a trailing comma:
+
+ ```dart
+ var r = const (1[!)!];
+ ```
+
+ #### Common fixes
+
+ Add a trailing comma:
+
+ ```dart
+ var r = const (1,);
+ ```
experiments: records
script: >
main() {
@@ -348,10 +374,39 @@
}

RecordLiteralZeroFieldsWithTrailingComma:
- problemMessage: "Record literal without fields can't have a trailing comma."
+ problemMessage: "A record literal without fields can't have a trailing comma."
correctionMessage: "Try removing the trailing comma."
analyzerCode: ParserErrorCode.EMPTY_RECORD_LITERAL_WITH_COMMA
index: 128
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a record literal that has no
+ fields has a trailing comma. Empty record literals can't contain a comma.
+
+ #### Example
+
+ The following code produces this diagnostic because the empty record
+ literal has a trailing comma:
+
+ ```dart
+ var r = ([!,!]);
+ ```
+
+ #### Common fixes
+
+ If the record is intended to be empty, then remove the comma:
+
+ ```dart
+ var r = ();
+ ```
+
+ If the record is intended to have one or more fields, then add the
+ expressions used to compute the values of those fields:
+
+ ```dart
+ var r = (3, 4);
+ ```
experiments: records
script: >
main() {
@@ -359,10 +414,40 @@
}

EmptyRecordTypeNamedFieldsList:
- problemMessage: "Record type named fields list can't be empty."
- correctionMessage: "Try adding a record type named field to the list."
+ problemMessage: "The list of named fields in a record type can't be empty."
+ correctionMessage: "Try adding a named field to the list."
analyzerCode: ParserErrorCode.EMPTY_RECORD_TYPE_NAMED_FIELDS_LIST
index: 129
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a record type has an empty list
+ of named fields.
+
+ #### Example
+
+ The following code produces this diagnostic because the record type has an
+ empty list of named fields:
+
+ ```dart
+ void f((int, int, {[!}!]) r) {}
+ ```
+
+ #### Common fixes
+
+ If the record is intended to have named fields, then add the types and
+ names of the fields:
+
+ ```dart
+ void f((int, int, {int z}) r) {}
+ ```
+
+ If the record isn't intended to have named fields, then remove the curly
+ braces:
+
+ ```dart
+ void f((int, int) r) {}
+ ```
experiments: records
script: >
main() {
@@ -370,10 +455,39 @@
}

RecordTypeZeroFieldsButTrailingComma:
- problemMessage: "Record type without fields can't have a trailing comma."
+ problemMessage: "A record type without fields can't have a trailing comma."
correctionMessage: "Try removing the trailing comma."
analyzerCode: ParserErrorCode.EMPTY_RECORD_TYPE_WITH_COMMA
index: 130
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a record type that has no
+ fields has a trailing comma. Empty record types can't contain a comma.
+
+ #### Example
+
+ The following code produces this diagnostic because the empty record type
+ has a trailing comma:
+
+ ```dart
+ void f(([!,!]) r) {}
+ ```
+
+ #### Common fixes
+
+ If the record type is intended to be empty, then remove the comma:
+
+ ```dart
+ void f(() r) {}
+ ```
+
+ If the record type is intended to have one or more fields, then add the
+ types of those fields:
+
+ ```dart
+ void f((int, int) r) {}
+ ```
experiments: records
script: >
main() {
@@ -381,10 +495,36 @@
}

RecordTypeOnePositionalFieldNoTrailingComma:
- problemMessage: "Record type with one entry requires a trailing comma."
+ problemMessage: "A record type with exactly one positional field requires a trailing comma."
correctionMessage: "Try adding a trailing comma."
analyzerCode: ParserErrorCode.RECORD_TYPE_ONE_POSITIONAL_NO_TRAILING_COMMA
index: 131
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a record type annotation with a
+ single positional field doesn't have a trailing comma after the field.
+
+ In some locations a record type with a single positional field could also
+ be a parenthesized expression. A trailing comma is required to
+ disambiguate these two valid interpretations.
+
+ #### Example
+
+ The following code produces this diagnostic because the record type has
+ one positional field, but doesn't have a trailing comma:
+
+ ```dart
+ void f((int[!)!] r) {}
+ ```
+
+ #### Common fixes
+
+ Add a trailing comma:
+
+ ```dart
+ void f((int,) r) {}
+ ```
experiments: records
script: >
main() {
@@ -802,10 +942,41 @@
- "abstract class C {abstract late var f;}"

AbstractSealedClass:
- index: 132
problemMessage: "A class can't be declared both 'sealed' and 'abstract'."
correctionMessage: "Try removing the 'abstract' or 'sealed' keyword."
analyzerCode: ParserErrorCode.ABSTRACT_SEALED_CLASS
+ index: 132
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a class is declared using both
+ the modifier `abstract` and the modifier `sealed`. Sealed classes are
+ implicitly abstract, so explicitly using both modifiers is not allowed.
+
+ #### Example
+
+ The following code produces this diagnostic because the class `C` is
+ declared using both `abstract` and `sealed`:
+
+ ```dart
+ abstract [!sealed!] class C {}
+ ```
+
+ #### Common fixes
+
+ If the class should be abstract but not sealed, then remove the `sealed`
+ modifier:
+
+ ```dart
+ abstract class C {}
+ ```
+
+ If the class should be both abstract and sealed, then remove the
+ `abstract` modifier:
+
+ ```dart
+ sealed class C {}
+ ```
experiments: sealed-class
script:
- "sealed abstract class C {}"

To view, visit change 286524. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: sdk
Gerrit-Branch: main
Gerrit-Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
Gerrit-Change-Number: 286524
Gerrit-PatchSet: 1
Gerrit-Owner: Brian Wilkerson <brianwi...@google.com>
Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
Gerrit-Attention: Konstantin Shcheglov <sche...@google.com>
Gerrit-MessageType: newchange

Brian Wilkerson (Gerrit)

unread,
Mar 2, 2023, 3:44:24 PM3/2/23
to Brian Wilkerson, dart-analys...@google.com, dart-fe-te...@google.com, dart-uxr...@google.com, rev...@dartlang.org, Konstantin Shcheglov

Attention is currently required from: Konstantin Shcheglov.

View Change

3 comments:

  • Patchset:

    • Patch Set #1:

      Please look these over primarily for technical correctness. Of course, if you have any other comments those would also be appreciated.

  • File pkg/analyzer/messages.yaml:

    • Patch Set #1, Line 4010: Example

      This example generates two diagnostics, but I'm not sure why the second occurs:
      ```
      CompileTimeErrorCode.DUPLICATE_VARIABLE_PATTERN (58, 1) The variable 'a' is already defined in this pattern.
      HintCode.UNUSED_LOCAL_VARIABLE (58, 1) The value of the local variable 'a' isn't used.
      ```

    • Patch Set #1, Line 20152: Example

      This example currently isn't generating any diagnostics (although I think it used to, because I wouldn't have guessed the highlight range). Is that a result of switching to the temporary exhaustiveness algorithm?

To view, visit change 286524. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: sdk
Gerrit-Branch: main
Gerrit-Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
Gerrit-Change-Number: 286524
Gerrit-PatchSet: 1
Gerrit-Owner: Brian Wilkerson <brianwi...@google.com>
Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
Gerrit-Attention: Konstantin Shcheglov <sche...@google.com>
Gerrit-Comment-Date: Thu, 02 Mar 2023 20:44:21 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Gerrit-MessageType: comment

Brian Wilkerson (Gerrit)

unread,
Mar 3, 2023, 10:49:23 AM3/3/23
to Brian Wilkerson, dart-analys...@google.com, dart-fe-te...@google.com, dart-uxr...@google.com, rev...@dartlang.org, Konstantin Shcheglov

Attention is currently required from: Konstantin Shcheglov.

View Change

1 comment:

To view, visit change 286524. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: sdk
Gerrit-Branch: main
Gerrit-Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
Gerrit-Change-Number: 286524
Gerrit-PatchSet: 1
Gerrit-Owner: Brian Wilkerson <brianwi...@google.com>
Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
Gerrit-Attention: Konstantin Shcheglov <sche...@google.com>
Gerrit-Comment-Date: Fri, 03 Mar 2023 15:49:15 +0000

Konstantin Shcheglov (Gerrit)

unread,
Mar 3, 2023, 12:47:39 PM3/3/23
to Brian Wilkerson, dart-analys...@google.com, dart-fe-te...@google.com, dart-uxr...@google.com, rev...@dartlang.org

Attention is currently required from: Brian Wilkerson.

Patch set 2:Code-Review +1

View Change

2 comments:

  • File pkg/analyzer/messages.yaml:

    • This example generates two diagnostics, but I'm not sure why the second occurs: […]

      Each `DeclaredVariablePattern` has its own element, and only one them is referenced in `print()`.

    • This example currently isn't generating any diagnostics (although I think it used to, because I woul […]

      It seems highly probable to me that the temporary exhaustiveness algorithm does not support this. But I'm also not sure that the full exhaustiveness algorithm will support it. I probably don't have enough knowledge here, as I did not review all exhaustiveness implementation.

To view, visit change 286524. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: sdk
Gerrit-Branch: main
Gerrit-Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
Gerrit-Change-Number: 286524
Gerrit-PatchSet: 2
Gerrit-Owner: Brian Wilkerson <brianwi...@google.com>
Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
Gerrit-Attention: Brian Wilkerson <brianwi...@google.com>
Gerrit-Comment-Date: Fri, 03 Mar 2023 17:47:35 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: Yes
Comment-In-Reply-To: Brian Wilkerson <brianwi...@google.com>
Gerrit-MessageType: comment

Brian Wilkerson (Gerrit)

unread,
Mar 3, 2023, 1:37:56 PM3/3/23
to Marya Belanger, dart-analys...@google.com, dart-fe-te...@google.com, dart-uxr...@google.com, rev...@dartlang.org, Brian Wilkerson, Konstantin Shcheglov

Attention is currently required from: Konstantin Shcheglov, Marya Belanger.

Brian Wilkerson would like Marya Belanger to review this change.

View Change

Add documentation for new diagnostics

I have not yet run the analyzer's generators just to keep the generated
version of the changes out of the review.

There are 10 parser diagnostics that are not being documented:
- ParserErrorCode.INVALID_CONSTANT_CONST_PREFIX
- ParserErrorCode.INVALID_CONSTANT_PATTERN_BINARY
- ParserErrorCode.INVALID_CONSTANT_PATTERN_DUPLICATE_CONST
- ParserErrorCode.INVALID_CONSTANT_PATTERN_EMPTY_RECORD_LITERAL
- ParserErrorCode.INVALID_CONSTANT_PATTERN_GENERIC
- ParserErrorCode.INVALID_CONSTANT_PATTERN_NEGATION
- ParserErrorCode.INVALID_CONSTANT_PATTERN_UNARY
- ParserErrorCode.FINAL_MIXIN_CLASS
- ParserErrorCode.INTERFACE_MIXIN_CLASS
- ParserErrorCode.SEALED_MIXIN_CLASS

Let me know if you think any of those need documentation.

Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
---
M pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
M pkg/analyzer/lib/src/dart/error/hint_codes.g.dart
M pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
M pkg/analyzer/lib/src/error/codes.g.dart

M pkg/analyzer/messages.yaml
M pkg/analyzer/test/verify_diagnostics_test.dart
M pkg/front_end/messages.yaml
7 files changed, 1,810 insertions(+), 52 deletions(-)

diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart
index b36de29..5c4e88c 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart
@@ -349,6 +349,9 @@
static const HintCode UNREACHABLE_SWITCH_CASE = HintCode(
'UNREACHABLE_SWITCH_CASE',
"This case is covered by the previous cases.",
+ correctionMessage:
+ "Try removing the case clause, or restructuring the preceding "
+ "patterns.",
);

/// Parameters:
diff --git a/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart b/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
index 1adae6b..9f8e58f 100644
--- a/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
+++ b/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
@@ -465,20 +465,20 @@
static const ParserErrorCode EMPTY_RECORD_LITERAL_WITH_COMMA =
ParserErrorCode(
'EMPTY_RECORD_LITERAL_WITH_COMMA',
- "Record literal without fields can't have a trailing comma.",
+ "A record literal without fields can't have a trailing comma.",
correctionMessage: "Try removing the trailing comma.",
);

static const ParserErrorCode EMPTY_RECORD_TYPE_NAMED_FIELDS_LIST =
ParserErrorCode(
'EMPTY_RECORD_TYPE_NAMED_FIELDS_LIST',
- "Record type named fields list can't be empty.",
- correctionMessage: "Try adding a record type named field to the list.",
+ "The list of named fields in a record type can't be empty.",
+ correctionMessage: "Try adding a named field to the list.",
);

static const ParserErrorCode EMPTY_RECORD_TYPE_WITH_COMMA = ParserErrorCode(
'EMPTY_RECORD_TYPE_WITH_COMMA',
- "Record type without fields can't have a trailing comma.",
+ "A record type without fields can't have a trailing comma.",
correctionMessage: "Try removing the trailing comma.",
);

@@ -1532,14 +1532,16 @@
static const ParserErrorCode RECORD_LITERAL_ONE_POSITIONAL_NO_TRAILING_COMMA =
ParserErrorCode(
'RECORD_LITERAL_ONE_POSITIONAL_NO_TRAILING_COMMA',
- "Record literal with one field requires a trailing comma.",
+ "A record literal with exactly one positional field requires a trailing "
+ "comma.",
correctionMessage: "Try adding a trailing comma.",
);

static const ParserErrorCode RECORD_TYPE_ONE_POSITIONAL_NO_TRAILING_COMMA =
ParserErrorCode(
'RECORD_TYPE_ONE_POSITIONAL_NO_TRAILING_COMMA',
- "Record type with one entry requires a trailing comma.",
+ "A record type with exactly one positional field requires a trailing "
+ "comma.",
correctionMessage: "Try adding a trailing comma.",
);

diff --git a/pkg/analyzer/lib/src/error/codes.g.dart b/pkg/analyzer/lib/src/error/codes.g.dart
index 364cc2d..65316d9 100644
--- a/pkg/analyzer/lib/src/error/codes.g.dart
+++ b/pkg/analyzer/lib/src/error/codes.g.dart
@@ -415,8 +415,8 @@
/// 0: the name of the class being used as a mixin
static const CompileTimeErrorCode CLASS_USED_AS_MIXIN = CompileTimeErrorCode(
'CLASS_USED_AS_MIXIN',
- "The class '{0}' can't be used as a mixin because it isn't a mixin class "
- "nor a mixin.",
+ "The class '{0}' can't be used as a mixin because it's neither a mixin "
+ "class nor a mixin.",
);

static const CompileTimeErrorCode CONCRETE_CLASS_HAS_ENUM_SUPERINTERFACE =
@@ -3864,11 +3864,11 @@
hasPublishedDocs: true,
);

+ /// No parameters.
static const CompileTimeErrorCode PATTERN_ASSIGNMENT_NOT_LOCAL_VARIABLE =
CompileTimeErrorCode(
'PATTERN_ASSIGNMENT_NOT_LOCAL_VARIABLE',
- "Only local variables or formal parameters can be used in pattern "
- "assignments.",
+ "Only local variables can be assigned in pattern assignments.",
correctionMessage: "Try assigning to a local variable.",
);

@@ -3906,36 +3906,39 @@
static const CompileTimeErrorCode
PATTERN_VARIABLE_SHARED_CASE_SCOPE_DIFFERENT_FINALITY_OR_TYPE =
CompileTimeErrorCode(
- 'PATTERN_VARIABLE_SHARED_CASE_SCOPE_DIFFERENT_FINALITY_OR_TYPE',
+ 'INVALID_PATTERN_VARIABLE_IN_SHARED_CASE_SCOPE',

"The variable '{0}' doesn't have the same type and/or finality in all "
         "cases that share this body.",

correctionMessage:
"Try declaring the variable pattern with the same type and finality in "
         "all cases.",
+ uniqueName: 'PATTERN_VARIABLE_SHARED_CASE_SCOPE_DIFFERENT_FINALITY_OR_TYPE',
);

/// Parameters:
/// 0: the name of the pattern variable
static const CompileTimeErrorCode
PATTERN_VARIABLE_SHARED_CASE_SCOPE_HAS_LABEL = CompileTimeErrorCode(
- 'PATTERN_VARIABLE_SHARED_CASE_SCOPE_HAS_LABEL',
+ 'INVALID_PATTERN_VARIABLE_IN_SHARED_CASE_SCOPE',
"The variable '{0}' is not available because there is a label or 'default' "
"case.",
correctionMessage:
"Try removing the label, or providing the 'default' case with its own "
"body.",
+ uniqueName: 'PATTERN_VARIABLE_SHARED_CASE_SCOPE_HAS_LABEL',
);

/// Parameters:
/// 0: the name of the pattern variable
static const CompileTimeErrorCode
PATTERN_VARIABLE_SHARED_CASE_SCOPE_NOT_ALL_CASES = CompileTimeErrorCode(
- 'PATTERN_VARIABLE_SHARED_CASE_SCOPE_NOT_ALL_CASES',
+ 'INVALID_PATTERN_VARIABLE_IN_SHARED_CASE_SCOPE',
"The variable '{0}' is available in some, but not all cases that share "
"this body.",

correctionMessage:
"Try declaring the variable pattern with the same type and finality in "
         "all cases.",
+ uniqueName: 'PATTERN_VARIABLE_SHARED_CASE_SCOPE_NOT_ALL_CASES',
);

/// No parameters.
@@ -5218,6 +5221,7 @@
hasPublishedDocs: true,
);

+ /// No parameters.
static const CompileTimeErrorCode
VARIABLE_PATTERN_KEYWORD_IN_DECLARATION_CONTEXT = CompileTimeErrorCode(
'VARIABLE_PATTERN_KEYWORD_IN_DECLARATION_CONTEXT',
diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml
index a8d6857..10b8d78 100644
@@ -6205,6 +6729,78 @@
   INITIALIZER_FOR_NON_EXISTENT_FIELD:
problemMessage: "'{0}' isn't a field in the enclosing class."
correctionMessage: "Try correcting the name to match an existing field, or defining a field named '{0}'."
@@ -7162,6 +7758,71 @@
@@ -8534,6 +9195,65 @@
@@ -8575,6 +9295,65 @@
@@ -9875,6 +10654,40 @@
@@ -9915,6 +10728,36 @@
@@ -9966,6 +10809,46 @@
@@ -11335,8 +12218,60 @@
@@ -11344,22 +12279,247 @@
   PATTERN_VARIABLE_SHARED_CASE_SCOPE_DIFFERENT_FINALITY_OR_TYPE:
+ sharedName: INVALID_PATTERN_VARIABLE_IN_SHARED_CASE_SCOPE

problemMessage: "The variable '{0}' doesn't have the same type and/or finality in all cases that share this body."
correctionMessage: Try declaring the variable pattern with the same type and finality in all cases.
comment: |-
Parameters:
0: the name of the pattern variable
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when there are multiple case clauses
+ in a switch statement and at least one of them declares a variable that is
+ referenced in the shared statement, but the variable is either not
+ declared in all of the case clauses or it is declared in inconsistent
+ ways.
+
+ If the variable isn't declared in all of the case clauses, then it won't
+ have a value when one of the clauses that doesn't declare the variable is
+      the one that matched. This includes the situation where one of the case
+ clauses is the `default` clause.

+
+ If the variable is declared in inconsistent ways, either being `final` in
+ some cases and not `final` in others or having a different type in
+ different cases, then the semantics of what the type or finality of the
+ variable should be are not defined.
+
+ #### Examples
+
+ The following code produces this diagnostic because the variable `a` is
+ only declared in one of the case clauses, and won't have a value if the
+ second clause is the one that matched `x`:
+
+ ```dart
+ void f(Object? x) {
+ switch (x) {
+ case int a when a > 0:
+ case 0:
+ [!a!];
+ }
+ }
+ ```
+
+      The following code produces this diagnostic because the variable `a` isn't
+ declared in the `default` clause, and won't have a value if the body is
+ executed because none of the other clauses matched `x`:

+
+ ```dart
+ void f(Object? x) {
+ switch (x) {
+ case int a when a > 0:
+          default:

+ [!a!];
+ }
+ }
+ ```
+
+      The following code produces this diagnostic because the variable `a` won't
+ have a value if the body is executed because a different group of cases
+ caused control to continue at the label:

+
+ ```dart
+ void f(Object? x) {
+ switch (x) {
+          someLabel:

+ case int a when a > 0:
+ [!a!];
+          case int a when a < 0:
+            continue someLabel;
   PATTERN_VARIABLE_SHARED_CASE_SCOPE_HAS_LABEL:
+ sharedName: INVALID_PATTERN_VARIABLE_IN_SHARED_CASE_SCOPE
problemMessage: "The variable '{0}' is not available because there is a label or 'default' case."
correctionMessage: Try removing the label, or providing the 'default' case with its own body.

comment: |-
Parameters:
0: the name of the pattern variable
   PATTERN_VARIABLE_SHARED_CASE_SCOPE_NOT_ALL_CASES:
+ sharedName: INVALID_PATTERN_VARIABLE_IN_SHARED_CASE_SCOPE
problemMessage: "The variable '{0}' is available in some, but not all cases that share this body."

correctionMessage: Try declaring the variable pattern with the same type and finality in all cases.
comment: |-
@@ -12464,15 +13624,176 @@
@@ -12909,6 +14230,32 @@
@@ -15527,6 +16874,35 @@
@@ -18730,6 +20106,42 @@
@@ -18774,7 +20186,74 @@
@@ -20173,10 +21652,63 @@
@@ -20415,6 +21947,44 @@

To view, visit change 286524. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: sdk
Gerrit-Branch: main
Gerrit-Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
Gerrit-Change-Number: 286524
Gerrit-PatchSet: 2
Gerrit-Owner: Brian Wilkerson <brianwi...@google.com>
Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
Gerrit-Reviewer: Marya Belanger <mbel...@google.com>
Gerrit-Attention: Konstantin Shcheglov <sche...@google.com>
Gerrit-Attention: Marya Belanger <mbel...@google.com>
Gerrit-MessageType: newchange

Brian Wilkerson (Gerrit)

unread,
Mar 3, 2023, 1:37:57 PM3/3/23
to Brian Wilkerson, dart-analys...@google.com, dart-fe-te...@google.com, dart-uxr...@google.com, rev...@dartlang.org, Marya Belanger, Konstantin Shcheglov

Attention is currently required from: Konstantin Shcheglov, Marya Belanger.

View Change

2 comments:

  • File pkg/analyzer/messages.yaml:

    • Each `DeclaredVariablePattern` has its own element, and only one them is referenced in `print()`.

      That makes sense, but if the variable is invalid it seems like it isn't useful to the user to be told that the variable isn't being referenced (because it isn't in scope and hence it isn't possible for it to be referenced).

    • It seems highly probable to me that the temporary exhaustiveness algorithm does not support this. […]

      I guess we have two choices:

      • wait and see what the full exhaustiveness implementation will catch and update the example as necessary, or
      • choose a less compelling case that's already being caught.

      I'd prefer to have a compelling case because I don't think users will be tripped up by the trivial cases, and I think it will be harder for them to make the leap from a trivial case to their own non-trivial case, but opinions are welcome.

To view, visit change 286524. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: sdk
Gerrit-Branch: main
Gerrit-Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
Gerrit-Change-Number: 286524
Gerrit-PatchSet: 2
Gerrit-Owner: Brian Wilkerson <brianwi...@google.com>
Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
Gerrit-Reviewer: Marya Belanger <mbel...@google.com>
Gerrit-Attention: Konstantin Shcheglov <sche...@google.com>
Gerrit-Attention: Marya Belanger <mbel...@google.com>
Gerrit-Comment-Date: Fri, 03 Mar 2023 18:37:53 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Comment-In-Reply-To: Konstantin Shcheglov <sche...@google.com>

Konstantin Shcheglov (Gerrit)

unread,
Mar 3, 2023, 2:38:12 PM3/3/23
to Brian Wilkerson, dart-analys...@google.com, dart-fe-te...@google.com, dart-uxr...@google.com, rev...@dartlang.org, Marya Belanger

Attention is currently required from: Brian Wilkerson, Marya Belanger.

View Change

2 comments:

  • File pkg/analyzer/messages.yaml:

    • I guess we have two choices: […]

      I tried this with full implementation, and it does not work there.
      It might be worth asking in the chat, whether we are going to get such precision.

To view, visit change 286524. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: sdk
Gerrit-Branch: main
Gerrit-Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
Gerrit-Change-Number: 286524
Gerrit-PatchSet: 2
Gerrit-Owner: Brian Wilkerson <brianwi...@google.com>
Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
Gerrit-Reviewer: Marya Belanger <mbel...@google.com>
Gerrit-Attention: Marya Belanger <mbel...@google.com>
Gerrit-Attention: Brian Wilkerson <brianwi...@google.com>
Gerrit-Comment-Date: Fri, 03 Mar 2023 19:38:08 +0000

Marya Belanger (Gerrit)

unread,
Mar 6, 2023, 2:09:29 PM3/6/23
to Brian Wilkerson, dart-analys...@google.com, dart-fe-te...@google.com, dart-uxr...@google.com, rev...@dartlang.org, Konstantin Shcheglov

Attention is currently required from: Brian Wilkerson.

View Change

1 comment:

To view, visit change 286524. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: sdk
Gerrit-Branch: main
Gerrit-Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
Gerrit-Change-Number: 286524
Gerrit-PatchSet: 2
Gerrit-Owner: Brian Wilkerson <brianwi...@google.com>
Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
Gerrit-Reviewer: Marya Belanger <mbel...@google.com>
Gerrit-Attention: Brian Wilkerson <brianwi...@google.com>
Gerrit-Comment-Date: Mon, 06 Mar 2023 19:09:26 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Gerrit-MessageType: comment

Marya Belanger (Gerrit)

unread,
Mar 6, 2023, 2:10:51 PM3/6/23
to Brian Wilkerson, dart-analys...@google.com, dart-fe-te...@google.com, dart-uxr...@google.com, rev...@dartlang.org, Konstantin Shcheglov

Attention is currently required from: Brian Wilkerson.

View Change

1 comment:

  • File pkg/analyzer/messages.yaml:

To view, visit change 286524. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: sdk
Gerrit-Branch: main
Gerrit-Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
Gerrit-Change-Number: 286524
Gerrit-PatchSet: 2
Gerrit-Owner: Brian Wilkerson <brianwi...@google.com>
Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
Gerrit-Reviewer: Marya Belanger <mbel...@google.com>
Gerrit-Attention: Brian Wilkerson <brianwi...@google.com>
Gerrit-Comment-Date: Mon, 06 Mar 2023 19:10:48 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Comment-In-Reply-To: Marya Belanger <mbel...@google.com>
Gerrit-MessageType: comment

Brian Wilkerson (Gerrit)

unread,
Mar 6, 2023, 6:17:42 PM3/6/23
to Brian Wilkerson, dart-analys...@google.com, dart-fe-te...@google.com, dart-uxr...@google.com, rev...@dartlang.org, Marya Belanger, Konstantin Shcheglov

Attention is currently required from: Marya Belanger.

View Change

1 comment:

  • File pkg/analyzer/messages.yaml:

    • Sorry, here's the link specifically to "Refutable pattern": https://dart. […]

      Thanks! I'll update the generator to produce the link data and update the docs when I address your review comments, after you've had a chance to make comments.

To view, visit change 286524. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: sdk
Gerrit-Branch: main
Gerrit-Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
Gerrit-Change-Number: 286524
Gerrit-PatchSet: 2
Gerrit-Owner: Brian Wilkerson <brianwi...@google.com>
Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
Gerrit-Reviewer: Marya Belanger <mbel...@google.com>
Gerrit-Attention: Marya Belanger <mbel...@google.com>
Gerrit-Comment-Date: Mon, 06 Mar 2023 23:17:38 +0000

Marya Belanger (Gerrit)

unread,
Mar 13, 2023, 9:23:17 PM3/13/23
to Brian Wilkerson, dart-analys...@google.com, dart-fe-te...@google.com, dart-uxr...@google.com, rev...@dartlang.org, Konstantin Shcheglov

Attention is currently required from: Brian Wilkerson.

View Change

38 comments:

    •       The analyzer produces this diagnostic when either a class declaration or a

    •       mixin declaration is used in an `extends`, `implements`, `with`, or `on`

    •       clause in a way that isn't allowed given the modifiers on the declaration.

    • Possibly just a knowledge gap on my part: To me, a class/mixin "declaration" means where it's declared, like:

            base class A {}

      Then after that, any reference to the class/mixin is just its name, not the declaration. Idk if using "declaration" to refer to the class/mixin outside of the actual line declaring it is standard terminology, but if not, I think we should instead say:
            ...when either a class or mixin is used in an
      `extends`, `implements`, `with`, or `on` clause...

      And the rest can stay the same ("...given the modifiers on the declaration" makes sense because modifiers are part of the declaration statement, not the inheritance clause).

      Building from that assumption, maybe add that we're referring to what would be the superclass in those inheritance clauses:

            The analyzer produces this diagnostic when an `extends`, `implements`,
      `with`, or `on` clause attempts to <inherit from>/<implement>
      a class or mixin in a way that isn't allowed given the modifiers on
      <that class or mixin's>/<its> declaration.
    • Patch Set #2, Line 1143:

    •       The message indicates how the declaration is being used and why it isn't

    •       allowed.

      The message specifies how the declaration is being used and why it isn't
      allowed.

      (assuming this line is meant to say that the specific modifier/use issue will be clarified in the message, since this will come up for different reasons)
    • Patch Set #2, Line 1148: Given a file named `a.dart` that defines a base class `A`:

      Let's standardize everywhere it says "given a file":

            Given a file `a.dart` that defines a base class `A`:
    • Patch Set #2, Line 1165: #### Common fixes

      If a user is getting this message, isn't it technically because the owner of the other library deliberately didn't want them to do whatever they're trying to do?

      I feel like clarifying that at the start might reduce some ambiguity here, since there's really no "fix", the answer is just "you can't do that":

            Use of this type is restricted outside of its declaring library.
      If a different, unrestricted type is available that can provide
      similar functionality, then replace the type:

      And for the second part: If you remove the type, wouldn't you have to remove the whole clause anyway?
            ```dart
      class B implements <nothing here because we removed the type> {}
      // assuming that wouldn't work ^
      ```

      So maybe say:

    •       If there isn't a different type that would be appropriate,
    •       The analyzer produces this diagnostic when a class is used in the `with`

    •       clause and that class is neither a `mixin class` nor a `mixin`.

    • The analyzer produces this diagnostic when a class that is neither a
      `mixin class` nor a `mixin` is used in a `with` clause.
    • Patch Set #2, Line 1657: The following code produces this diagnostic because :

      Extra space typo

            The following code produces this diagnostic because:
    • Patch Set #2, Line 1811:

    •       The analyzer produces this diagnostic when a pattern contains a value that

    •       is declared in a library that is imported using a deferred import.

    •       Constants are evaluated at compile time, and values from deferred

    •       libraries aren't available at compile time.

    • Restructured to make it a little easier to track the cause and effect:

    •       The analyzer produces this diagnostic when a pattern contains a value
    •       declared in a different library, and that library is imported using a 
      deferred import.
      Constants are evaluated at compile time, but values from deferred

    • libraries aren't available at compile time.
    • Also, is it that constants are evaluated at compile time, or constant patterns specifically?

            Constant <values in patterns> are evaluated at compile time,
      but values from deferred libraries aren't available at compile time.
    • Patch Set #2, Line 1816:

    •       For more information, see the language tour's coverage of

    •       If you need to reference the constant from the imported library, then

    •       remove the `deferred` keyword:

      I think I mentioned this earlier, but is this just about constants or is it because it's a constant in a pattern that the availability doesn't line up? If it's the latter, should this line be:

    •       If you need to reference the constant from the imported library
    •       <in your pattern>, then remove the `deferred` keyword:

      If it's the former (this is just because constants and deferred library load times don't line up), then I'd imagine there's already a diagnostic that covers this same issue, and a patterns specific diagnostic isn't really necessary.

    • Patch Set #2, Line 1861:

      then rewrite the switch


    • statement as a sequence of `if` statements:

    • Hmm... I think this answers my question about whether this is patterns-specific or not. I assume `if` is a "fix" because a series of if statements aren't patterns.

      So, if the mismatched-load times issue really is because a constant *in a pattern* is evaluated earlier than a deferred library, then that should be explicitly stated (see my first comment under Description and first comment under Common fixes for this diagnostic)

    • Patch Set #2, Line 2745:

    • requires executing arbitrary code at

    •       compile time, which isn't supported.

    • I wonder if "requires executing arbitrary code" is necessary here. Is that just a Dart/compiler implementation detail, or does it have more to do with user code? If the former, maybe remove that part and say:

    •       The implementation of constant maps uses both
    •       the `==` operator and the `hashCode` getter, so any implementation other
    •       If you can't remove the implementation of `==` and `hashCode` from the

    •       class, then make the map be non-constant:

    • If you can't remove the implementation of `==` and `hashCode` from the
    • requires executing arbitrary code at

    •       compile time, which isn't supported.

    • whose name is the same as a

    •       previous field in the same literal or type.

    • "previous" here makes it seem like order matters, complicating the description, but I can't imagine why it might. Does the diagnostic warn on the second occurrence specifically, and if so, is it important that users know that's how it works? This could be simplified otherwise:

    •       The analyzer produces this diagnostic when either a record literal or a
    •       The analyzer produces this diagnostic when a pattern variable is assigned

    •       more than one value in a pattern assignment.

    • Would it be more accurate to say:

            The analyzer produces this diagnostic when a single pattern variable
      is assigned a value more than once in the same pattern assignment.
    • Patch Set #2, Line 3879: patterns

      Should this be "subpatterns"? The pattern is `(int, int)` but each `int` is a subpattern of `(int, int)` (I might be mistaken but I think this terminology matters)

    • Patch Set #2, Line 3888:


    • If some of the values don't need to be captured, then use a wildcard

    •       pattern for the ones you don't need:

    • If some of the values don't need to be captured, then use a wildcard
    •       pattern `_` <to avoid having to bind the value to a variable> /
      <that doesn't bind to a variable>:
    • Patch Set #2, Line 3909: once and

      ...more than once, <add comma> <or> when an object pattern...

      I'm going with "or" over "and", because I'm assuming both of those clauses don't need to be true for this diagnostic to fire, just either one.
    • Patch Set #2, Line 3949: case (a: 1, b: _) || (a: 2, b: _):

      Neat!

    • Patch Set #2, Line 3973:

    • The first rest pattern will

    •       capture all of the otherwise uncaptured values, so there's nothing left

    •       for the other rest patterns to capture.

    • Nothing really wrong in the first place, I just thought "The first rest pattern..." makes it sound like a specific-to-this-occurrence description, when that's really just the definition of rest patterns. So I made it a tiny bit more generic:

      A rest pattern will capture any values unmatched by other subpatterns,
      making subsequent rest patterns unnecessary because there's nothing left
      to capture.
    • Patch Set #2, Line 4016:

            void f((int, int) r) {


    • if (r case (var a, 0) && (0, var [!a!])) {

    • This might be the only kind of structure where this diagnostic will show up, in which case it's fine, but I find this very hard to parse (here and under Commmon fixes). The description makes the diagnostic very clear, but this somehow detracts from that. (keep in mind I'm not as well-versed in Dart as our users probably are so maybe this is a pretty standard construct, just sharing my pov)

    • Patch Set #2, Line 4036:

       then remove


    • the variable pattern from all but one branch, integrating the guard

    •       (`when`) clauses if there are any:

    • Does "remove" necessitate the variable pattern be replaced with a wildcard, or is that just for simplicity's sake? Might be important to specify that.

      I'd like to see what you mean by "integrating a guard clause" in the example if it's not to complicated, or not a hype-edge case.

    • Patch Set #2, Line 4318:

    •       The analyzer produces this diagnostic a key in a map pattern is the same

    •       as a previous key in the same map pattern. The same key can't be matched

    •       twice.

      typo:

    •       The analyzer produces this diagnostic <when> a key in a map pattern 

    • Also, as I mentioned in a similar message about duplicates and use of "previous": can the wording be simplified like:
            The analyzer produces this diagnostic when a map pattern contains <more
      than one key with the same name>/<multiple identical keys>.
      The same key can't be matched twice.
    • Patch Set #2, Line 4349: if (x case {'a': 1 || 2}) {}

      Interesting syntax. Would `if (x case {'a': 1} || {'a': 2})` also work? Is this typical Dart syntax or something specific to do with map patterns/logical patterns?

    • Patch Set #2, Line 4362:

    • The pattern can have either one type argument or zero

    •       type arguments, but can't have more than one.

    • nit: the order of this is bugging me

            List patterns can have either zero type arguments or one type argument,

    • but can't have more than one.
    • Patch Set #2, Line 4482: The pattern

      "Map patterns can have..."

    • Patch Set #2, Line 4499: Add or remove type arguments until there are two:

      "...until there are two, or none:"? Kind of weird because you can't "add" until there are "none", but maybe worth reiterating.

    • Patch Set #2, Line 6736: both branches

      nit: Can't there technically be multiple branches of logical-or/and patterns? I.e. not just two. Really nit-picking, but "multiple" might be a more accurate word than "both":

            ...declared on multiple branches of a logical-or pattern
      has a different type on different branches.
      ....
      A pattern variable declared on multiple branches of a logical-or
      pattern is required to have the same type and finality in each branch
      it's declared, so that the type and finality of the...
    • Patch Set #2, Line 7766:

            invalid if it is


    • - the same as one of the members defined on `Object`

    •       - private (starts with `_`)

    •       - the same as the name of a positional field (an exception is made if the

    •         field is a positional field with the specified name)

    • invalid if it is: <add colon>

    • - private (starts with `_`)
    •       - the same as one of the members defined on `Object`
    •       - the same as the name of a positional field (an exception is made if the
    •         field is a positional field with the specified name)

    •       The following code produces this diagnostic because the record literal has

    •       a field named `$1`, which is also the name of a different positional

    •       parameter:

      ```dart


    • var r = ([!$1!]: 2, 1);

    •       The analyzer produces this diagnostic when an object pattern has a

    •       property matcher that doesn't have either a getter name before the colon

    •       or a variable pattern from which the getter name can be inferred.

    • Maybe break into bullets, this is a tricky topic and it'd make the two conditions clearer:

    •       The analyzer produces this diagnostic when an object pattern has a
    •       property matcher that doesn't have either:
      - a getter name before the colon
      - a variable pattern from which the getter name can be inferred

      Also, I haven't heard the term "property matcher" before and couldn't exactly find its definition in the spec. Is this standard terminology we've agreed on for destructuring object properties, in a `case` or just wherever? Would be good to know for site docs :)
    • Patch Set #2, Line 9236: case C(: var f):

      Looking at the [slides](https://docs.google.com/presentation/d/1YvH-dJzgzVFDZ1c9cb70i-9IyNmvlKZUQmAOq-4B3d4/edit#slide=id.g16276789713_0_337) from the first patterns presentation (which I realize the syntax therein could've changed since they came out), for what I *think* is the same construct, or at least similar, its `(:var ..., :var ...)`. No space after the colon before `var`. Does that matter?

    • Patch Set #2, Line 9243: then add the name of the property before the colon:

      Is this the same as the previous fix, where the name needs to be "the same as the name of the property being matched"? Might be important to clarify

    • Patch Set #2, Line 9252: case C(f: 0):

      I'm confused by what this accomplishes/what it means to write it this way. Might need a link to wider scope docs, or maybe a line at the end of the fix description if it can be summed up succinctly, e.g.:

    •       If you don't need to use the actual value of the property within the
    •       pattern's scope, then add the name of the property before the colon 
    •       <so that ...> / <which causes ...> / <etc>

To view, visit change 286524. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: sdk
Gerrit-Branch: main
Gerrit-Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
Gerrit-Change-Number: 286524
Gerrit-PatchSet: 2
Gerrit-Owner: Brian Wilkerson <brianwi...@google.com>
Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
Gerrit-Reviewer: Marya Belanger <mbel...@google.com>
Gerrit-Attention: Brian Wilkerson <brianwi...@google.com>
Gerrit-Comment-Date: Tue, 14 Mar 2023 01:23:12 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Gerrit-MessageType: comment

Marya Belanger (Gerrit)

unread,
Mar 14, 2023, 5:19:28 PM3/14/23
to Brian Wilkerson, dart-analys...@google.com, dart-fe-te...@google.com, dart-uxr...@google.com, rev...@dartlang.org, Konstantin Shcheglov

Attention is currently required from: Brian Wilkerson.

Patch set 2:Code-Review +1

View Change

29 comments:

  • Patchset:

    • Patch Set #2:

      Ok, all done. I'm going to approve just so you can carry on in case I get busy, but of course I'm here to discuss or answer any questions if you need.

      Most of these reviews are in the form of me asking questions: the questions are usually rhetorical, they're just to show how I'm interpreting something and how other readers might, and then maybe to support my reasoning for how I rewrote something.

      Nothing major though! Thanks for looping me in, I enjoyed reading these and learned a lot.

  • File pkg/analyzer/messages.yaml:


    • } else if (r case (0, _)) {

    •           print('found a zero');
      }
      }



    • The following code produces this diagnostic because the key `A()` isn't a

    •       constant:

      ```dart
      void f(Object x) {


    • if (x case {[!A()!]: 0}) {}
      }

    •       class A {
      const A();
      }
      ```

      #### Common fixes



    • Use a constant for the key:

    •       ```dart
      void f(Object x) {


    • if (x case {const A(): 0}) {}
      }

    •       class A {
      const A();
      }
      ```

      Is this example making a point about:
      1. constant contexts? OR,
      2. the fact that constructor calls are ambiguous to patterns so need to be marked `const`?

      I initially didn't understand why line 10670 wouldn't be constant. So, I looked up "constant" in dart.dev and learned "constant constructors don't always create constants", because of constant contexts etc. So I assumed that's why constructing the `const A()` constructor needed an explicit `const` added.

      But then I found [this line](https://github.com/dart-lang/language/blob/master/accepted/future-releases/0546-patterns/feature-specification.md#constant-pattern:~:text=versus%20map%20patterns.-,Constructor%20calls,-are%20ambiguous%20with) in the spec; specifically "we require const constructor *calls* to be explicitly marked const."

      So, going back to my numbered list above, two possibilities here:

      1. (because constant contexts) If this is the most common situation that'll raise this diagnostic (misinterpreting constant context), then it's a great example and should be kept. Probably link to your [glossary entry](https://dart.dev/tools/diagnostic-messages#constant-context) for "constant".

          But if it's just that keys need to be constant, maybe use a simpler non-constant as the example? Like, remove the whole `class A` part and just use a simple non-constant (idk what that would be or if anything like that exists). I'm not a typical Dart user, so grain-of-salt, but maybe that would save someone from the relative rabbit hole I went down. 

      2. (because patterns) if the example doesn't work because constructor calls are ambiguous to patterns, then I think elaborating that in the description would clear all this up:

                The analyzer produces this diagnostic when a key in a map pattern is a 
      constant constructor call that isn't explicitly marked `const`, because
      constructor calls are ambiguous to patterns.
    • Patch Set #2, Line 10815:

            The analyzer produces this diagnostic when a `switch` statement that is


    • switching over an exhastive type, such as an enum, doesn't have a case

    •       that will match one or more of the possible values of the type, such as

    •       the constants defined by the enum.

    • Typo on "exhaustive", also rewording to simplify, in my opinion:

            The analyzer produces this diagnostic when a `switch` statement is
      switching over an exhaustive type, but doesn't
      <cover> / <address> / <have a case for> /
      all of the possible values that could flow into it.

      (or, "...when a `switch` statement switching over an exhaustive type
      is missing a case for one or more of the possible values that
      could flow through it.)

      This is a major simplification, but I think it makes the concept a lot clearer. Notice I removed any mention of enum from the description, since descriptions don't typically qualify themselves with examples. I don't think using enum to help the description is necessary anymore since my rewrite simplifies the concept well enough (again, in my opinion). I do think that we could instead add that point back in the example where it's relevant:
            #### Example

      The following code produces this diagnostic because the switch statement
      doesn't have a case for the value `E.three`, and enum is an exhaustive type:
    • Patch Set #2, Line 10823: constant

      The use of "constant" here and in the Common fixes section feels misleading. Yes, the values are constants in this arbitrary example, but is it necessary for exhaustiveness checking that the values all be constants? If not, I don't think the fact that they're constants in this example needs to be mentioned at all.

      Like, if this was switching over subtypes of a sealed class would you also call the subtypes constants? (honest question, I don't know what implicitly qualifies as a constant).

      If I'm making sense, then I'd replace "constant" with just "value", here and on line 10838

    • Patch Set #2, Line 10838: Add a case for each of the constants that aren't currently being matched:

      Would another fix be to add a `default` case, or wildcard? I believe that's true for exhaustiveness checking on sealed classes.

      It could follow this fix and say:

            If the missing value is unknown, add a default or wildcard case to catch it:
    • Patch Set #2, Line 12247:


    • If the code is cleaner when using a pattern assignment, then rewrite the

    •       code to assign the value to a local variable, assigning the non-local

    •       variable separately:

      ```dart
      class C {
      var x = 0;

      void f((int, int) r) {


    • var (a, _) = r;

    •       The analyzer produces this diagnostic when the type of the value on the

    •       right-hand side of a pattern assignment or pattern declaration isn't

    •       assignable to the type required by the pattern being assigned to.

    • I might misunderstand some nuance here, but isn't the whole last line just describing pattern matching? To me, since you've already said "pattern assignment and pattern declaration" it feels unnecessary.

    •       The analyzer produces this diagnostic when the type of the value on the
    •       right-hand side of a pattern assignment or pattern declaration doesn't 
      match the type required by the pattern in question.

      I also dislike using the verb "assign" twice after distinguishing "pattern assignment *and pattern declaration*". Assigning a value to a pattern, while colloquially obviously makes sense, is a totally different thing from *declaring* a new variable with a pattern. So it feels counterproductive to lump their capabilities together under the descriptor of only one.
    • Patch Set #2, Line 12289: The analyzer produces this diagnostic when the type of the value being

      Wait, why are there two descriptions? I'm only noticing this after reviewing the first paragraph 😄 I can't tell if they're describing different concepts or not, but if you're deciding between the two, this one (second) is more succinct.

    • Patch Set #2, Line 12340:

    •       If there's a value you need to capture, then assign it to a different

    •       variable:

      ```dart
      void f(int x) {
      var b;


    • if (x case var a when (b = 1) > 0) {

    •           print(a + b);
      }
      }
      ```

      I know the example is contrived, but would `if (x case var a = 1 when a > 0)` work? Maybe that way they wouldn't have to create a new variable?

    • Patch Set #2, Line 12371:

    •       The analyzer produces this diagnostic when there are multiple case clauses

    •       in a switch statement and at least one of them declares a variable that is

    •       referenced in the shared statement, but the variable is either not

    •       declared in all of the case clauses or it is declared in inconsistent

    •       ways.

      Before mentioning the "shared statement", I would explicitly clarify that these clauses are sharing a body:

            The analyzer produces this diagnostic when multiple case clauses
      in a switch statement share a body,

    • and at least one of them declares a variable that is
    •       referenced in the shared statement, but the variable is either not
    •       declared in all of the case clauses or it is declared in inconsistent

    • have a value if the body is executed because a different group of cases

    •       caused control to continue at the label:

    •       ```dart
      void f(Object? x) {
      switch (x) {
      someLabel:


    • case int a when a > 0:

    •             [!a!];


    • case int a when a < 0:

    •             continue someLabel;
      }
      }
      ```

      I wrote a long comment about how I didn't understand why `a` wouldn't persist to the label, since the second clause that flows to the label does declare `a`, but in the process learned that once a case clause continues to a label we've exited the case clause's scope, I guess? (and the label scope is like a new case clause scope?)

      So in lieu of that comment, I'd reword this to make it clearer that the second case "resets" the scope in a sense:

      The following code produces this diagnostic,
      despite both cases declaring `a`, because
      the body of the second case causes control to continue at the label,
      exiting the scope where `a` was declared, so `a` has no value.
    • Patch Set #2, Line 12463:

    •       If the variable isn't declared in all of the cases, and you need to

    •       reference it in the statements, then declare it in the other cases:

    •       ```dart
      void f(Object? x) {
      switch (x) {


    • case int a when a > 0:

    •           case int a when a == 0:

    •             a;
      }
      }
      ```

      This fix correlates to the first example, but what about the second example where the case that's missing a declaration is the `default` clause? I'm assuming you just can't declare a variable in any cases in a switch that has a `default` clause?

      So the answer or fix for that example would be either 1) don't declare the variable in the case clauses, or 2) declare the variable outside of the switch statement...? Is that worth adding (I know the examples/fixes here are already covering a lot, so just an idea)

      Edit: I noticed below that there is a problem message for when there's a default case, so I think it's a good idea to illustrate that "fix" here: "providing the 'default' case with its own body"

    • Patch Set #2, Line 12483: case > 0:

      Not familiar with this syntax; does this mean `case (x > 0)`?

    • Patch Set #2, Line 12489: decide type

      typo: "decide *the* type"

    • Patch Set #2, Line 13633: are

      I think we've been using a colon to lead up to bullet lists so far. If that's the case, "are" > "are:" (and do the same for the second bullet list too)

    • Patch Set #2, Line 13665:

            The analyzer produces this diagnostic when a relational pattern references


    • an operator that doesn't produce a value of type `bool`.

    •       #### Example

      The following code produces this diagnostic because the operator `>`, used


    • in the relational pattern `> c2`, returns a value of type `int` rather

    •       than a `bool`:

      ```dart
      class C {
      const C();



    • int operator >(C c) => 3;

    •         bool operator <(C c) => false;
      }

    •       const C c2 = C();

    •       void f(C c1) {


    • if (c1 case [!>!] c2) {}
      }

    •       ```

      Is overriding operators the only way this could occur? If so, maybe clarify that in the description:

            The analyzer produces this diagnostic when a relational pattern references
      an operator that doesn't produce a value of type `bool` because the operator
      has been overridden.
    • Patch Set #2, Line 13736:

    • In Dart, there is no notion of a subset of a map, so

    •       there isn't anything to match against the subpattern.

    •       The analyzer produces this diagnostic when a class or mixin isn't either

    •       `base`, `final` or `sealed`, but it has a supertype, either direct or

    •       indirect, that is either `base` or `final`.

    • nit: this explanation feels like it's being relayed in reverse. Probably just a personal preference thing, but I'd say:

            The analyzer produces this diagnostic when a class or mixin 
      has a direct or indirect supertype that is either `base` or `final`,
      but the class or mixin itself isn't marked either `base`, `final`,
      or `sealed`.
    • Patch Set #2, Line 20114: and the returned value is a literal set containing.

      Typo, not sure what the intended sentence was.

    • Patch Set #2, Line 20116:

    • There is no value in returning a value from a `void` function, though the

    •       language allows it.

      Obviously this makes sense, but the word "value" already carries a lot in these docs. Maybe something else:

            There is no benefit to returning...

      Returning a value from a `void` function <isn't beneficial> /
      <isn't useful> / <doesn't accomplish anything> / etc, though...
    • Patch Set #2, Line 20224: break;

      I know it's arbitrary, but since you said "if it needs to be handled differently", maybe handle it differently in some arbitrary way here so the code matches the explanation.

    • Patch Set #2, Line 21659: null-assert

      Something to consider in both this diagnostic and the following one: you hyphenated null-check/assert in the description, but not in the common fixes section (they're also hyphenated in their respective problem/correction messages). We should pick one format and stick with it.

    • Patch Set #2, Line 21705: assert

      typo: null *check* pattern

    • Patch Set #2, Line 21953:

    • when a constant pattern can never

    •       match the value being matched

    • Just to not repeat "match" twice so close in the same sentence:

            ...when a constant pattern can never match the value
      <being tested against it> / <it's being tested against>,
      because...

      Also I think "testing" values/patterns "against" each other is good phrasing to use anyway, so it'd be beneficial to inject that in wherever possible.

To view, visit change 286524. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: sdk
Gerrit-Branch: main
Gerrit-Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
Gerrit-Change-Number: 286524
Gerrit-PatchSet: 2
Gerrit-Owner: Brian Wilkerson <brianwi...@google.com>
Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
Gerrit-Reviewer: Marya Belanger <mbel...@google.com>
Gerrit-Attention: Brian Wilkerson <brianwi...@google.com>
Gerrit-Comment-Date: Tue, 14 Mar 2023 21:19:22 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: Yes
Gerrit-MessageType: comment

Brian Wilkerson (Gerrit)

unread,
Mar 15, 2023, 2:59:30 PM3/15/23
to Brian Wilkerson, dart-analys...@google.com, dart-fe-te...@google.com, dart-uxr...@google.com, rev...@dartlang.org, Marya Belanger, Konstantin Shcheglov

Attention is currently required from: Marya Belanger.

View Change

37 comments:

  • Patchset:

    • Patch Set #3:

      I have answers to most of your questions, and a few of my own. If you don't have time to iterate I can commit this now and we can iterate later.

  • File pkg/analyzer/messages.yaml:

    •       The analyzer produces this diagnostic when either a class declaration or a
      mixin declaration is used in an `extends`, `implements`, `with`, or `on`
      clause in a way that isn't allowed given the modifiers on the declaration.

    • I think it makes sense to only use "declaration" when we're talking about the actual declaration.

      And I don't have any objection to the final suggestion, but just wanted to verify a change in the approach. In the past I was asked to refer to what the code "does" rather than what the code is attempting to do, even when the code is invalid and doesn't do what the user likely expected it to do. The older style would rewrite your final suggested state as something along the lines of

      The analyzer produces this diagnostic when an `extends`, `implements`, `with`, or `on` clause uses a class or mixin in a way that isn't allowed given the modifiers on that class or mixin's declaration.

    • The message specifies how the declaration is being used and why it isn't […]

      Done.

    • Let's standardize everywhere it says "given a file": […]

      Done.

    • Patch Set #2, Line 1165: #### Common fixes

      If a user is getting this message, isn't it technically because the owner of the other library deliberately didn't want them to do whatever they're trying to do?

    • Yes, although the user might be the owner of the other library, and hence it's possible that the user didn't understand the implications of their choice when writing the other library.

      I feel like clarifying that at the start might reduce some ambiguity here ...

      Done.

    • And for the second part: If you remove the type, wouldn't you have to remove the whole clause anyway?

    • There can be multiple types in the `implements` and `with` clauses (`class A implements B, C with D, E {}`), so removing one of the types doesn't necessarily make the clause empty.

    • Patch Set #2, Line 1652:

            The analyzer produces this diagnostic when a class is used in the `with`
      clause and that class is neither a `mixin class` nor a `mixin`.

    • The analyzer produces this diagnostic when a class that is neither a […]

      Done

    • Patch Set #2, Line 1657: The following code produces this diagnostic because :

      Extra space typo […]

      Done

    • Patch Set #2, Line 1811:

            The analyzer produces this diagnostic when a pattern contains a value that
      is declared in a library that is imported using a deferred import.
      Constants are evaluated at compile time, and values from deferred
      libraries aren't available at compile time.

    • Changes made.

    • Also, is it that constants are evaluated at compile time, or constant patterns specifically?

    • All constants (static fields or top-level variables marked as `const`), are evaluated at compile time.

    • We actually just "unpacked" the language tour into separate pages per topic, so change link and word […]

      Done

      Note that this wasn't the only reference to that page. I've updated the other references as well.

    • Let's standardize the format everywhere it says "given a file": […]

      Done

    • Switch doesn't need break anymore ...

      I don't know either. The issue is that it's still required for any code that hasn't been converted to 3.0, which at the moment is almost all of the code in the world. Even after we release 3.0 it will take time for users to stop supporting earlier versions of the language.

      At what point will it confuse fewer users to not have a required `break` than it will to have an unnecessary `break`?

    • Patch Set #2, Line 1845:

            If you need to reference the constant from the imported library, then
      remove the `deferred` keyword:

    • I think I mentioned this earlier, but is this just about constants or is it because it's a constant […]

      It's the former.

      We have multiple diagnostics related to the use of constants from deferred libraries, depending on where the constant is being used. I'd be happy to unify them, but not in this round of changes.

    • So, if the mismatched-load times issue really is because a constant _in a pattern_ is evaluated earlier than a deferred library...

      It isn't.

      Expressions in a pattern are evaluated at compile-time. So are the expressions used to initialize a constant (static field or top-level variable marked with `const`) or to provide a default value for a parameter. But the expressions in an `if` statement are not evaluated at compile time, even if they would produce a constant value.

    • Is that just a Dart/compiler implementation detail, or does it have more to do with user code?

      I consider it to be more than an implementation detail in that it's part of the definition of the language.

      I have, in a few places, attempted to provide some justification for the rules in the hope that users would understand the language better. In this particular case I think it's valuable because if the user controls the class and wants to use it in a constant map, then they'll understand why they can't define an implementation for either of those methods, which might help them make a more informed decision about how to solve the issue.

      But if you think it would be better without the extra text, then I can remove it.

    • Patch Set #2, Line 2791:

            If you can't remove the implementation of `==` and `hashCode` from the
      class, then make the map be non-constant:

    • If you can't remove the implementation of `==` and `hashCode` from the […]

      Done

    • ... […]

      Done

    • "previous" here makes it seem like order matters, complicating the description, but I can't imagine […]

      The diagnostic is generated for all but the first field with that name, but you're right that the spec doesn't specify that. The only reason it might matter to the user is that we assume that the first field is the valid one and the rest are not, which can impact the way we treat the rest of the code. For example, given:
      ```
      void f(({int f, String f}) r) {
      r.f;
      }
      ```
      The reference to `r.f` will be interpreted to have the type `int`. If the value were used in a way that wasn't appropriate for an `int`, then there would be follow-on errors.

      I don't know whether the text helps the user understand this, or even whether it's useful for the user to understand this.

    • Patch Set #2, Line 3860:

            The analyzer produces this diagnostic when a pattern variable is assigned
      more than one value in a pattern assignment.

    • Would it be more accurate to say: […]

      Done

    • Should this be "subpatterns"? The pattern is `(int, int)` but each `int` is a subpattern of `(int, i […]

      I'm not sure how much it matters, but I do think it reads better. Done.

    • Patch Set #2, Line 3888:


      If some of the values don't need to be captured, then use a wildcard
      pattern for the ones you don't need:

    • If some of the values don't need to be captured, then use a wildcard […]

      Done

    • ...more than once, <add comma> <or> when an object pattern... […]

      Done

    • Patch Set #2, Line 3973:

      The first rest pattern will
      capture all of the otherwise uncaptured values, so there's nothing left
      for the other rest patterns to capture.

    • Nothing really wrong in the first place, I just thought "The first rest pattern... […]

      Done

    •       void f((int, int) r) {


    • if (r case (var a, 0) && (0, var [!a!])) {

    • ... maybe this is a pretty standard construct ...

      Well, not yet. We haven't released the feature, so there really isn't a standard yet. I'm not sure whether it will be a standard construct or not. It's kind of hard to guess how users will use patterns.

      The example has to have a logical-and pattern, with the same variable on both sides, and `var a && var a` seemed too contrived/pointless. The code surrounding the pattern could be changed to a switch if that would improve things. Depends on what it is about the example that detracts from the example.

    • Patch Set #2, Line 4036:

       then remove
      the variable pattern from all but one branch, integrating the guard
      (`when`) clauses if there are any:

    • Does "remove" necessitate the variable pattern be replaced with a wildcard ...

      It would help if I were more proficient with patterns, but I think the answer is "no". I think it's reasonable, for example, to have a variable pattern in a logical-and, such as `< 0 && var a`, and to replace that with `< 0`.

      I'd like to see what you mean by "integrating a guard clause" ...

      I think that was a misunderstanding on my part when I first wrote this. I don't think it's possible to have multiple `when` clauses to integrate. I've removed ", integrating the guard (`when`) clauses if there are any".

    • Would `if (x case {'a': 1} || {'a': 2})` also work?

      I believe that the answer is "yes", but there would be more duplication, so I'd probably discourage it.

    • Is this typical Dart syntax or something specific to do with map patterns/logical patterns?

    • It's specific to patterns. In a map pattern the keys are constants but the values are patterns. In a map literal the keys are constants, but the values are just expressions.

    • Patch Set #2, Line 4362:

      The pattern can have either one type argument or zero
      type arguments, but can't have more than one.

    • nit: the order of this is bugging me […]

      Done

    • "Map patterns can have... […]

      Done

    • "... […]

      That's why it ways "add or remove".

      Done.

    • nit: Can't there technically be multiple branches of logical-or/and patterns? I.e. not just two. […]

      Good question. I suspect that most users think of `a || b || c` as a single logical-or expression. Technically (based on the grammar), it's two logical-or expressions, one having the other logical-or as one of the operands.

      If we switch to talking about it as if there were multiple branches, then we probably need to say "all" rather than "multiple". For example,

        ...declared on all branches of a logical-or pattern
      doesn't have the same type on every branch.

      Let me know what you think.

    • Patch Set #2, Line 7766:

            invalid if it is
      - the same as one of the members defined on `Object`
      - private (starts with `_`)
      - the same as the name of a positional field (an exception is made if the
      field is a positional field with the specified name)

    • invalid if it is: <add colon> […]

      Done

    • Patch Set #2, Line 7803:

            The following code produces this diagnostic because the record literal has
      a field named `$1`, which is also the name of a different positional
      parameter:

      ```dart
      var r = ([!$1!]: 2, 1);
      ```

    • I thought that $1 would be reserved as the positional parameter for the first field, regardless of whether it's named or not.

      Every individual field can be either positional or it can be named, but it can't be both. The "position"/order of a named field is ignored. For example, in the record literal `(1, a: 2, 3)`, there are two positional fields and one named field. The name of the field whose value is `1`, is `$1`, and the name of the field whose value is `3`, is `$2` because it's the second positional field.

      Not sure whether we want to make changes to make that more obvious for the user.

    • Just writing this all out to confirm the example is accurate.

    • The example is accurate, but I have no problem changing it to match your suggestion if you think it would be better, so done.

    • Patch Set #2, Line 9201:

            The analyzer produces this diagnostic when an object pattern has a
      property matcher that doesn't have either a getter name before the colon
      or a variable pattern from which the getter name can be inferred.

    • Maybe break into bullets ...

      Done

      I haven't heard the term "property matcher" before ...

      I haven't either. In the spec it's sort of referred to as a pattern field:
      ```
      patternField ::= ( identifier? ':' )? pattern
      ```

      but I don't expect that users will be familiar with the language grammar. I'm happy to use any term you want for it, but that's the piece of the code I need to have a name for.

    • Looking at the [slides](https://docs.google. […]

      No, the space, or lack thereof, doesn't change the semantics of the code, so I've remove it.

      I also updated the text for the example because I realized that it was incomplete.

    • Is this the same as the previous fix, where the name needs to be "the same as the name of the proper […]

      The two fixes differ by how you provide a name for the getter, but yes, both are related to providing a getter name. Changed to

      then add the name of the property being matched before the colon

    • I'm confused by what this accomplishes/what it means to write it this way. […]

      The behavior of this code is to match if `c.f` returns a value that matches the constant pattern `0`.

      The behavior of the code in the previous fix was to match if `c.f` is any value and to bind that value to the pattern variable `f`.

      I have updated the first fix so that the value of `c.f` is still being checked (because otherwise the fix doesn't match the user's intent). Noe the first fix will match if `c.f` returns zero and will bind that value to the pattern variable `f`. (Though why you want to bind it to a variable in this case is beyond me.)

      I haven't added a more detailed explanation, so let me know if you now think we should add something.

    • Thanks! I'll update the generator to produce the link data and update the docs when I address your r […]

      Done

To view, visit change 286524. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: sdk
Gerrit-Branch: main
Gerrit-Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
Gerrit-Change-Number: 286524
Gerrit-PatchSet: 3
Gerrit-Owner: Brian Wilkerson <brianwi...@google.com>
Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
Gerrit-Reviewer: Marya Belanger <mbel...@google.com>
Gerrit-Attention: Marya Belanger <mbel...@google.com>
Gerrit-Comment-Date: Wed, 15 Mar 2023 18:59:25 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Comment-In-Reply-To: Konstantin Shcheglov <sche...@google.com>
Comment-In-Reply-To: Marya Belanger <mbel...@google.com>

Marya Belanger (Gerrit)

unread,
Mar 15, 2023, 9:38:24 PM3/15/23
to Brian Wilkerson, dart-analys...@google.com, dart-fe-te...@google.com, dart-uxr...@google.com, rev...@dartlang.org, Konstantin Shcheglov

Attention is currently required from: Brian Wilkerson.

Patch set 4:Code-Review +1

View Change

12 comments:

  • Patchset:

    • Patch Set #4:

      Have about half left to respond to, your reasoning and fixes lgtm so far!

  • File pkg/analyzer/messages.yaml:

    • Patch Set #2, Line 1139:

            The analyzer produces this diagnostic when either a class declaration or a
      mixin declaration is used in an `extends`, `implements`, `with`, or `on`
      clause in a way that isn't allowed given the modifiers on the declaration.

    • I think it makes sense to only use "declaration" when we're talking about the actual declaration. […]

      Aha, I actually did notice that style in some of the descriptions but wasn't exactly sure how to define it. That's good to know; definitely a worthwhile point to make in the future "how to write diagnostic messages" guide!

    • > Switch doesn't need break anymore ... […]

      Good point, I'd say leaving it for the foreseeable future is the best bet. If deprecating `break` ever gets added to a minor release years from now, that'll probably be the only thing to prompt us to remove it.

    • > So, if the mismatched-load times issue really is because a constant _in a pattern_ is evaluated ea […]

      Thanks for explaining, re-reading the back-and-forth in my comments/questions gave me a little whiplash so I appreciate your patience

    • > Is that just a Dart/compiler implementation detail, or does it have more to do with user code? […]

      No I think you should keep it. The statement seemed like filler ("arbitrary code" felt like a hand-wavey misdirection), but I understand what's going on a little better now and I think it's valuable for users to learn to reason about their architecture choices with some context.

    • which can impact the way we treat the rest of the code

      That makes sense to me.

      Now, this is super nit-picking, but "previous" feels like an odd word to describe this. Would "previously declared field" or "already-declared field" be more clear? Or is that over-specifying or assuming the context of the fields?

      If neither of those make sense and you can't think of anything else, "previous" is fine, especially since I can't exactly articulate why I don't like it.

    • > Would `if (x case {'a': 1} || {'a': 2})` also work? […]

      Thanks for explaining

    • Good question. I suspect that most users think of `a || b || c` as a single logical-or expression. […]

      Sure, I like "all". You'd have to update the rest of the paragraph too probably:

    •       It is also produced when the variable has a
    •       different finality on different branches. A pattern variable declared on             
      multiple branches of a logical-or pattern is required to have the same type

    • and finality in each branch it's declared, so that the type and finality of
    •       the variable can be known in code that's guarded by the logical-or pattern.
    • Patch Set #2, Line 7803:

            The following code produces this diagnostic because the record literal has
      a field named `$1`, which is also the name of a different positional
      parameter:

      ```dart
      var r = ([!$1!]: 2, 1);
      ```

    • Every individual field can be either positional or it can be named, but it can't be both

      That makes sense! Yes I think the updated example will help users understand it more quickly. Though the original could potentially teach them the same thing you explained to me, which would be really beneficial, but without your explanation it might also just confuse some people. I like the safer option.

    • Patch Set #2, Line 9201:

            The analyzer produces this diagnostic when an object pattern has a
      property matcher that doesn't have either a getter name before the colon
      or a variable pattern from which the getter name can be inferred.

    • > Maybe break into bullets ... […]

      Ok, we can either keep "property matcher" and I'll make sure to use that in the docs, OR, maybe "property matching pattern" or "field matching pattern" would be a little more intuitive/make it clearer which part we're talking about?

      Idk if changing it that way totally changes the meaning, though. I feel like there's a lot of very subtle nuance to pattern terminology since they can appear in so many places, so I'd be careful with that...

To view, visit change 286524. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: sdk
Gerrit-Branch: main
Gerrit-Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
Gerrit-Change-Number: 286524
Gerrit-PatchSet: 4
Gerrit-Owner: Brian Wilkerson <brianwi...@google.com>
Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
Gerrit-Reviewer: Marya Belanger <mbel...@google.com>
Gerrit-Attention: Brian Wilkerson <brianwi...@google.com>
Gerrit-Comment-Date: Thu, 16 Mar 2023 01:38:18 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: Yes

Marya Belanger (Gerrit)

unread,
Mar 16, 2023, 4:31:25 PM3/16/23
to Brian Wilkerson, dart-analys...@google.com, dart-fe-te...@google.com, dart-uxr...@google.com, rev...@dartlang.org, Konstantin Shcheglov

Attention is currently required from: Brian Wilkerson.

View Change

3 comments:

  • File pkg/analyzer/messages.yaml:

    • Patch Set #2, Line 9252: case C(f: 0):

      The behavior of this code is to match if `c. […]

      Oh I get it now. What the fix is actually accomplishing doesn't really matter, it's just to show how to properly write a property matcher, so the "why" doesn't need to be added. Thanks for explaining!

    • Done

  • File pkg/analyzer/messages.yaml:

To view, visit change 286524. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: sdk
Gerrit-Branch: main
Gerrit-Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
Gerrit-Change-Number: 286524
Gerrit-PatchSet: 4
Gerrit-Owner: Brian Wilkerson <brianwi...@google.com>
Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
Gerrit-Reviewer: Marya Belanger <mbel...@google.com>
Gerrit-Attention: Brian Wilkerson <brianwi...@google.com>
Gerrit-Comment-Date: Thu, 16 Mar 2023 20:31:20 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No

Brian Wilkerson (Gerrit)

unread,
Mar 17, 2023, 12:13:09 PM3/17/23
to Brian Wilkerson, dart-analys...@google.com, dart-fe-te...@google.com, dart-uxr...@google.com, rev...@dartlang.org, Marya Belanger, Konstantin Shcheglov

Attention is currently required from: Marya Belanger.

View Change

40 comments:

    •       The analyzer produces this diagnostic when either a class declaration or a
      mixin declaration is used in an `extends`, `implements`, `with`, or `on`
      clause in a way that isn't allowed given the modifiers on the declaration.

    • Aha, I actually did notice that style in some of the descriptions but wasn't exactly sure how to def […]

      Did you want to retain the older style, or move to a newer style?

    • Good point, I'd say leaving it for the foreseeable future is the best bet. […]

      Done

    • requires executing arbitrary code at
      compile time, which isn't supported.

    • Same question as previous diagnostic, maybe remove "requires executing arbitrary code at compile tim […]

      I think this has been resolve, but let me know if that's not true.

    • > which can impact the way we treat the rest of the code […]

      Changed to "previously declared field".

    • Honestly, I've done a tiny bit more reading on if-case since then and it's fine for me now. […]

      Done

    • Patch Set #2, Line 4318:

            The analyzer produces this diagnostic a key in a map pattern is the same
      as a previous key in the same map pattern. The same key can't be matched
      twice.

    • typo: […]

      Done

    • Sure, I like "all". You'd have to update the rest of the paragraph too probably: […]

      I removed "it's declared", but otherwise, done.

    • Patch Set #2, Line 7803:

            The following code produces this diagnostic because the record literal has
      a field named `$1`, which is also the name of a different positional
      parameter:

      ```dart
      var r = ([!$1!]: 2, 1);
      ```

    • > Every individual field can be either positional or it can be named, but it can't be both […]

      Done

    • Patch Set #2, Line 9201:

            The analyzer produces this diagnostic when an object pattern has a
      property matcher that doesn't have either a getter name before the colon
      or a variable pattern from which the getter name can be inferred.

    • ... maybe "property matching pattern" or "field matching pattern" ...

      The only problem I have with those is that it makes it sound like the whole "identifier ':' pattern" is a pattern, when it isn't.

      What do you think of not defining a term, but just describing the syntax instead? I'm thinking of something like

            The analyzer produces this diagnostic when, within an object pattern,
      the specification of a property and the pattern used to match the
      property's value doesn't have either:

    • if (r case (var a, 0)) {
      print(a);
      } else if (r case (0, _)) {
      print('found a zero');
      }
      }
      ```

    • Just bringing this up in case you care; it doesn't really have anything to do with this diagnostic a […]

      I care about almost everything :-)

      I think that's a good idea, but it isn't valid to write a switch expression by itself (in an expression statement), so I turned it into a switch statement.

    • Patch Set #2, Line 10662:


      #### Example

      The following code produces this diagnostic because the key `A()` isn't a
      constant:

      ```dart
      void f(Object x) {
      if (x case {[!A()!]: 0}) {}
      }

      class A {
      const A();
      }
      ```

      #### Common fixes

      Use a constant for the key:

      ```dart
      void f(Object x) {
      if (x case {const A(): 0}) {}
      }

      class A {
      const A();
      }
      ```

    • Is this example making a point about: […]

      Neither. The diagnostic occurs for any expression used as a map pattern key that isn't a valid constant expression. The key expression isn't in a constant context, so that's not the issue. Because the key is always an expression, the ambiguity with constructors and object patterns doesn't come into play.

      I could have picked any non-constant expression (such as a function invocation like `g(2)`), but I wanted something that could be converted to being a valid constant expression in some recognizable way (for example, there isn't any way to rewrite a function invocation that doesn't change the semantics of the code). The only things I could think of were a constructor invocation or a variable name (where the variable could be changed from `var` to `const`).

      We could rewrite the example to something like
      ```
      class C {
      static int f = 0;
        void m(Object x) {
      if (x case {[!f!]: 0}) {}
      }
      }
      ```
      and the fix could be
      ```
      class C {
      static const int f = 0;
        void m(Object x) {
      if (x case {f: 0}) {}
      }
      }
      ```

      Not sure which is better. Let me know what you think.

    • Patch Set #2, Line 10815:

            The analyzer produces this diagnostic when a `switch` statement that is
      switching over an exhastive type, such as an enum, doesn't have a case
      that will match one or more of the possible values of the type, such as
      the constants defined by the enum.

    • Typo on "exhaustive", also rewording to simplify, in my opinion: […]

      Done

    • Patch Set #2, Line 10823: constant

      The use of "constant" here and in the Common fixes section feels misleading. […]

      No it isn't necessary, but it is true. Enum constants are constants. The changes above (which includes replacing "constant" with "value") are done.

    • Would another fix be to add a `default` case, or wildcard? I believe that's true for exhaustiveness […]

      I added the example, because I think users should know about the option. But it comes with a disclaimer because there's an implication that they also need to be aware of.

    • Patch Set #2, Line 12247:


      If the code is cleaner when using a pattern assignment, then rewrite the
      code to assign the value to a local variable, assigning the non-local
      variable separately:

      ```dart
      class C {
      var x = 0;

      void f((int, int) r) {
      var (a, _) = r;
      x = a;
      }
      }
      ```

    • I think line 12257 `var (a, _) = r;` is no longer a pattern *assignment*, but now a pattern *declara […]

      Description changed.

    • Patch Set #2, Line 12285:

            The analyzer produces this diagnostic when the type of the value on the
      right-hand side of a pattern assignment or pattern declaration isn't
      assignable to the type required by the pattern being assigned to.

    • I might misunderstand some nuance here, but isn't the whole last line just describing pattern matchi […]

      Done

    • Patch Set #2, Line 12289: The analyzer produces this diagnostic when the type of the value being

    • Wait, why are there two descriptions? I'm only noticing this after reviewing the first paragraph 😄 […]

    • I'm not sure why there are two. The second is closer to right, but not quite there. It isn't the fact that it's an irrefutable pattern, it's the fact that the pattern required a specific type in order to match and it's being used in an irrefutable context.

      Anyway, I went with something very close to your suggestion above.

    • Patch Set #2, Line 12340:

            If there's a value you need to capture, then assign it to a different
      variable:

      ```dart
      void f(int x) {
      var b;
      if (x case var a when (b = 1) > 0) {
      print(a + b);
      }
      }
      ```

    • I know the example is contrived, but would `if (x case var a = 1 when a > 0)` work? Maybe that way t […]

      No, `var a = 1` isn't a valid pattern.

    • Patch Set #2, Line 12371:

            The analyzer produces this diagnostic when there are multiple case clauses
      in a switch statement and at least one of them declares a variable that is
      referenced in the shared statement, but the variable is either not
      declared in all of the case clauses or it is declared in inconsistent
      ways.


    • The following code produces this diagnostic because the variable `a` won't
      have a value if the body is executed because a different group of cases
      caused control to continue at the label:

      ```dart
      void f(Object? x) {
      switch (x) {
      someLabel:
      case int a when a > 0:
      [!a!];
      case int a when a < 0:
      continue someLabel;
      }
      }
      ```

    • I wrote a long comment about how I didn't understand why `a` wouldn't persist to the label, since th […]

      The issue is that the `a` in the first case clause and the `a` in the second case clause are different variables. Rather than try to explain this (which isn't important to understanding the diagnostic), I changed the name of the second variable.

    • Patch Set #2, Line 12463:

            If the variable isn't declared in all of the cases, and you need to
      reference it in the statements, then declare it in the other cases:

      ```dart
      void f(Object? x) {
      switch (x) {
      case int a when a > 0:
      case int a when a == 0:
      a;
      }
      }
      ```

    • I'm assuming you just can't declare a variable in any cases in a switch that has a default clause?

      Correct.

      ... 1) don't declare the variable in the case clauses ...

      That's the second fix.

      ... 2) declare the variable outside of the switch statement...?

      I suppose that would fix the problem -- basically the variable would hold the value of the expression following the `switch` keyword -- but it really doesn't make sense to have a `default` clause share code with a `case` clause. You can just delete the `case` clause and the semantics are unchanged.

      Let me know whether you'd still like to see changes made here.

    • No. The `> 0` is a relational pattern that will match if the value being switched over is greater than zero. The `(x > 0)` would be a constant pattern that would match if the value being switched over is the `bool` result of comparing `x` to zero.

    •       The analyzer produces this diagnostic when a relational pattern references
      an operator that doesn't produce a value of type `bool`.

      #### Example

      The following code produces this diagnostic because the operator `>`, used
      in the relational pattern `> c2`, returns a value of type `int` rather
      than a `bool`:

      ```dart
      class C {
      const C();

      int operator >(C c) => 3;

      bool operator <(C c) => false;
      }

      const C c2 = C();

      void f(C c1) {
      if (c1 case [!>!] c2) {}
      }
      ```

    • Is overriding operators the only way this could occur? If so, maybe clarify that in the description: […]

      No, and the operators in `C` aren't overriding any thing (because `Object` doesn't define any operators other than `==`), so it isn't the case for this example either.

    • Patch Set #2, Line 13736:

      In Dart, there is no notion of a subset of a map, so
      there isn't anything to match against the subpattern.

      I like this description, very clear definition that also explains the "why" of the diagnostic.

    • Thanks.

    •       The analyzer produces this diagnostic when a class or mixin isn't either
      `base`, `final` or `sealed`, but it has a supertype, either direct or
      indirect, that is either `base` or `final`.

    • nit: this explanation feels like it's being relayed in reverse. […]

      Done

    • Patch Set #2, Line 20114: and the returned value is a literal set containing.

    • Typo, not sure what the intended sentence was.

    • Added "a single element".

    • Obviously this makes sense, but the word "value" already carries a lot in these docs. […]

      Reworked, thanks.

    • I know it's arbitrary, but since you said "if it needs to be handled differently", maybe handle it d […]

      That's a good suggestion. I'm holding off on implementing it until I see whether I need an even bigger re-write (which depends on whether exhaustiveness checking will catch this case).

    • Something to consider in both this diagnostic and the following one: you hyphenated null-check/asser […]

      I agree. And it should be consistent with the rest of `dart.dev`. I don't have an easy way to find out which is more common.

      The patterns proposal uses the hyphen, and it was the smallest change to use that consistently here, but the diagnostic docs for non-pattern cases use 'null check' 8 times. I don't see any value in hyphenating the words, but I'll leave the final call up to the doc team.

    • when a constant pattern can never
      match the value being matched

    • Just to not repeat "match" twice so close in the same sentence: […]

      Done

  • File pkg/analyzer/messages.yaml:

    • "because.... […]

      Done

To view, visit change 286524. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: sdk
Gerrit-Branch: main
Gerrit-Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
Gerrit-Change-Number: 286524
Gerrit-PatchSet: 5
Gerrit-Owner: Brian Wilkerson <brianwi...@google.com>
Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
Gerrit-Reviewer: Marya Belanger <mbel...@google.com>
Gerrit-Attention: Marya Belanger <mbel...@google.com>
Gerrit-Comment-Date: Fri, 17 Mar 2023 16:13:05 +0000

Marya Belanger (Gerrit)

unread,
Mar 17, 2023, 2:13:16 PM3/17/23
to Brian Wilkerson, dart-analys...@google.com, dart-fe-te...@google.com, dart-uxr...@google.com, rev...@dartlang.org, Konstantin Shcheglov

Attention is currently required from: Brian Wilkerson.

Patch set 5:Code-Review +1

View Change

9 comments:

  • Patchset:

    • Patch Set #5:

      Thanks for taking the time to answer all my questions, learned a lot from this review!

  • File pkg/analyzer/messages.yaml:

    • Patch Set #2, Line 1139:

            The analyzer produces this diagnostic when either a class declaration or a
      mixin declaration is used in an `extends`, `implements`, `with`, or `on`
      clause in a way that isn't allowed given the modifiers on the declaration.

    • Did you want to retain the older style, or move to a newer style?

      I think the older style (what the code does instead of what it's attempting to do) is probably the best way to do it.

      I haven't had a chance to scrutinize the efficacy of that in all the messages, but even just conceptually it seems like the clearest, most straightforward way to present this type of information.

    • Patch Set #2, Line 9201:

            The analyzer produces this diagnostic when an object pattern has a
      property matcher that doesn't have either a getter name before the colon
      or a variable pattern from which the getter name can be inferred.

    • Patch Set #2, Line 9348:

            ```dart
      void f((int, int) r) {
      if (r case (var a, 0)) {
      print(a);
      } else if (r case (0, _)) {
      print('found a zero');
      }
      }
      ```

    • I care about almost everything :-) […]

      Great, I think it's a nice way to show it that way, albeit not necessary. And thanks for correcting the expression. Probably safe to assume that whenever I'm making a suggestion for a code change, it's basically pseudocode 😄

    • Patch Set #2, Line 10662:


      #### Example

      The following code produces this diagnostic because the key `A()` isn't a
      constant:

      ```dart
      void f(Object x) {
      if (x case {[!A()!]: 0}) {}
      }

      class A {
      const A();
      }
      ```

      #### Common fixes

      Use a constant for the key:

      ```dart
      void f(Object x) {
      if (x case {const A(): 0}) {}
      }

      class A {
      const A();
      }
      ```

    • Neither. […]

      Ok, thanks for explaining. The only thing that worries me about the original example is, I wonder if it's realistic to assume anyone would make the same connection that I did (thinking this has something to do with contexts or constructor calls).

      I came up with those ideas because after reading the description, my first question was "why", so I looked at the example. Because it's involving a constructor, and has an element of const scope to it just because there's a separate class, I came up with those ideas.

      I wouldn't suggest emphasizing "why" in the description either, because the answer is just "...because keys in map patterns can't be constant expressions". It's already as straightforward as possible (unless you start explaining why *that* is, which is info that's best left in the spec).

      So, if you think there's a chance a user might get all turned around like I did, then I'd say go with the rewrite you came up with. But I can also see now that my interpretation was overthinking it, and everything the user needs to know is right in the succinct description.

    • Patch Set #2, Line 12463:

            If the variable isn't declared in all of the cases, and you need to
      reference it in the statements, then declare it in the other cases:

      ```dart
      void f(Object? x) {
      switch (x) {
      case int a when a > 0:
      case int a when a == 0:
      a;
      }
      }
      ```

    • > I'm assuming you just can't declare a variable in any cases in a switch that has a default clause? […]

      Ok you're right, the way it's written is the most succinct way to sum up the fixes. No need to caveat for everything that could happen if it's not likely to happen

    • Patch Set #2, Line 13665:

            The analyzer produces this diagnostic when a relational pattern references
      an operator that doesn't produce a value of type `bool`.

      #### Example

      The following code produces this diagnostic because the operator `>`, used
      in the relational pattern `> c2`, returns a value of type `int` rather
      than a `bool`:

      ```dart
      class C {
      const C();

      int operator >(C c) => 3;

      bool operator <(C c) => false;
      }

      const C c2 = C();

      void f(C c1) {
      if (c1 case [!>!] c2) {}
      }
      ```

    • No, and the operators in `C` aren't overriding any thing (because `Object` doesn't define any operat […]

      Whoops, still lots of foundational learning to do, let alone all the new 3.0 features on top of it! Thanks for explaining

    • That's a good suggestion. […]

      Acknowledged

    • That's a good suggestion. […]

      Acknowledged

To view, visit change 286524. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: sdk
Gerrit-Branch: main
Gerrit-Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
Gerrit-Change-Number: 286524
Gerrit-PatchSet: 5
Gerrit-Owner: Brian Wilkerson <brianwi...@google.com>
Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
Gerrit-Reviewer: Marya Belanger <mbel...@google.com>
Gerrit-Attention: Brian Wilkerson <brianwi...@google.com>
Gerrit-Comment-Date: Fri, 17 Mar 2023 18:13:11 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: Yes

Brian Wilkerson (Gerrit)

unread,
Mar 17, 2023, 2:58:26 PM3/17/23
to Brian Wilkerson, dart-analys...@google.com, dart-fe-te...@google.com, dart-uxr...@google.com, rev...@dartlang.org, Marya Belanger, Konstantin Shcheglov

View Change

5 comments:

  • File pkg/analyzer/messages.yaml:

    • Patch Set #2, Line 1139:

            The analyzer produces this diagnostic when either a class declaration or a
      mixin declaration is used in an `extends`, `implements`, `with`, or `on`
      clause in a way that isn't allowed given the modifiers on the declaration.

    • I think the older style (what the code does instead of what it's attempting to do) is probably the b […]

      Done

    • Patch Set #2, Line 9201:

            The analyzer produces this diagnostic when an object pattern has a
      property matcher that doesn't have either a getter name before the colon
      or a variable pattern from which the getter name can be inferred.

    • I think that's great. […]

      Done

    • Patch Set #2, Line 10662:


      #### Example

      The following code produces this diagnostic because the key `A()` isn't a
      constant:

      ```dart
      void f(Object x) {
      if (x case {[!A()!]: 0}) {}
      }

      class A {
      const A();
      }
      ```

      #### Common fixes

      Use a constant for the key:

      ```dart
      void f(Object x) {
      if (x case {const A(): 0}) {}
      }

      class A {
      const A();
      }
      ```

    • Ok, thanks for explaining. […]

      I think I'll leave it as is for now because I think that having the change close to where the problem is reported makes it easier for users to identify what change was made. (I don't want it to be like one of those spot-the-differences puzzles. :-)

      Something to think about, that has been discussed before, is adding a way for users to thumbs-up or thumbs-down a particular diagnostic's docs so that we could find out which ones need more attention. Maybe something to consider with the re-org or the docs.

    • Patch Set #2, Line 12463:

            If the variable isn't declared in all of the cases, and you need to
      reference it in the statements, then declare it in the other cases:

      ```dart
      void f(Object? x) {
      switch (x) {
      case int a when a > 0:
      case int a when a == 0:
      a;
      }
      }
      ```

    • Ok you're right, the way it's written is the most succinct way to sum up the fixes. […]

      Acknowledged

    • Patch Set #2, Line 13665:

    •       The analyzer produces this diagnostic when a relational pattern references
      an operator that doesn't produce a value of type `bool`.

      #### Example

      The following code produces this diagnostic because the operator `>`, used
      in the relational pattern `> c2`, returns a value of type `int` rather
      than a `bool`:

      ```dart
      class C {
      const C();

      int operator >(C c) => 3;

      bool operator <(C c) => false;
      }

      const C c2 = C();

      void f(C c1) {
      if (c1 case [!>!] c2) {}
      }
      ```

    • Whoops, still lots of foundational learning to do, let alone all the new 3. […]

      Yeah, you really got dropped in the deep end. But your comments have been really good and I appreciate all of the feedback.

To view, visit change 286524. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: sdk
Gerrit-Branch: main
Gerrit-Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
Gerrit-Change-Number: 286524
Gerrit-PatchSet: 5
Gerrit-Owner: Brian Wilkerson <brianwi...@google.com>
Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
Gerrit-Reviewer: Marya Belanger <mbel...@google.com>
Gerrit-Comment-Date: Fri, 17 Mar 2023 18:58:20 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No

Brian Wilkerson (Gerrit)

unread,
Mar 17, 2023, 6:20:41 PM3/17/23
to Brian Wilkerson, dart-analys...@google.com, dart-fe-te...@google.com, dart-uxr...@google.com, rev...@dartlang.org, Marya Belanger, Konstantin Shcheglov

Patch set 6:Commit-Queue +2

View Change

2 comments:

  • Patchset:

    • Patch Set #6:

      I'm going to try to land this now. I'm happy to continue to iterate, but landing it will allow us to publish the updated version so that we can flip the flag before the deadline.

  • File pkg/analyzer/messages.yaml:

    • Patch Set #2, Line 20224: break;

      Acknowledged

      The exhaustiveness implementation has landed, and it isn't as powerful as I expected it to be. In particular, it won't catch overlapping ranges of integers.

      As a result I had to re-write the example and fixes.

To view, visit change 286524. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: sdk
Gerrit-Branch: main
Gerrit-Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
Gerrit-Change-Number: 286524
Gerrit-PatchSet: 6
Gerrit-Owner: Brian Wilkerson <brianwi...@google.com>
Gerrit-Reviewer: Brian Wilkerson <brianwi...@google.com>
Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
Gerrit-Reviewer: Marya Belanger <mbel...@google.com>
Gerrit-Comment-Date: Fri, 17 Mar 2023 22:20:34 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: Yes

Brian Wilkerson (Gerrit)

unread,
Mar 17, 2023, 6:44:17 PM3/17/23
to Johnni Winther, dart-analys...@google.com, dart-fe-te...@google.com, dart-uxr...@google.com, rev...@dartlang.org, Brian Wilkerson, Marya Belanger, Konstantin Shcheglov

Attention is currently required from: Johnni Winther.

Brian Wilkerson would like Johnni Winther to review this change.

View Change

Add documentation for new diagnostics

I have not yet run the analyzer's generators just to keep the generated
version of the changes out of the review.

There are 10 parser diagnostics that are not being documented:
- ParserErrorCode.INVALID_CONSTANT_CONST_PREFIX
- ParserErrorCode.INVALID_CONSTANT_PATTERN_BINARY
- ParserErrorCode.INVALID_CONSTANT_PATTERN_DUPLICATE_CONST
- ParserErrorCode.INVALID_CONSTANT_PATTERN_EMPTY_RECORD_LITERAL
- ParserErrorCode.INVALID_CONSTANT_PATTERN_GENERIC
- ParserErrorCode.INVALID_CONSTANT_PATTERN_NEGATION
- ParserErrorCode.INVALID_CONSTANT_PATTERN_UNARY
- ParserErrorCode.FINAL_MIXIN_CLASS
- ParserErrorCode.INTERFACE_MIXIN_CLASS
- ParserErrorCode.SEALED_MIXIN_CLASS

Let me know if you think any of those need documentation.

Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
---
M pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
M pkg/analyzer/lib/src/dart/error/hint_codes.g.dart
M pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
M pkg/analyzer/lib/src/error/codes.g.dart
M pkg/analyzer/messages.yaml
M pkg/analyzer/test/verify_diagnostics_test.dart
M pkg/analyzer/tool/diagnostics/diagnostics.md
M pkg/analyzer/tool/diagnostics/generate.dart
M pkg/front_end/messages.yaml
9 files changed, 3,858 insertions(+), 157 deletions(-)

diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
index 437b6dd..51ee886 100644

--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -3072,9 +3072,9 @@
const MessageCode messageEmptyRecordTypeNamedFieldsList = const MessageCode(
"EmptyRecordTypeNamedFieldsList",
index: 129,
- problemMessage: r"""Record type named fields list can't be empty.""",
- correctionMessage:
- r"""Try adding a record type named field to the list.""");
+ problemMessage:
+ r"""The list of named fields in a record type can't be empty.""",
+ correctionMessage: r"""Try adding a named field to the list.""");

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeEncoding = messageEncoding;
@@ -10983,7 +10983,7 @@

const MessageCode("RecordLiteralOnePositionalFieldNoTrailingComma",
index: 127,
problemMessage:
- r"""Record literal with one field requires a trailing comma.""",
+ r"""A record literal with exactly one positional field requires a trailing comma.""",
correctionMessage: r"""Try adding a trailing comma.""");

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -10995,7 +10995,7 @@

const MessageCode("RecordLiteralZeroFieldsWithTrailingComma",
index: 128,
problemMessage:
- r"""Record literal without fields can't have a trailing comma.""",
+ r"""A record literal without fields can't have a trailing comma.""",
correctionMessage: r"""Try removing the trailing comma.""");

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -11007,7 +11007,7 @@

const MessageCode("RecordTypeOnePositionalFieldNoTrailingComma",
index: 131,
problemMessage:
- r"""Record type with one entry requires a trailing comma.""",
+ r"""A record type with exactly one positional field requires a trailing comma.""",
correctionMessage: r"""Try adding a trailing comma.""");

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -11019,7 +11019,7 @@

const MessageCode("RecordTypeZeroFieldsButTrailingComma",
index: 130,
problemMessage:
- r"""Record type without fields can't have a trailing comma.""",
+ r"""A record type without fields can't have a trailing comma.""",
correctionMessage: r"""Try removing the trailing comma.""");

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart
index fb83e19..09395de 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart
@@ -293,6 +293,9 @@
index 0a5f7577..c56e212 100644
@@ -5239,6 +5242,7 @@

hasPublishedDocs: true,
);

+ /// No parameters.
static const CompileTimeErrorCode
VARIABLE_PATTERN_KEYWORD_IN_DECLARATION_CONTEXT = CompileTimeErrorCode(
'VARIABLE_PATTERN_KEYWORD_IN_DECLARATION_CONTEXT',
diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml
index 59584105..946f33a 100644
--- a/pkg/analyzer/messages.yaml
+++ b/pkg/analyzer/messages.yaml
@@ -308,14 +308,14 @@

#### Example

- Given a file named `a.dart` containing
+ Given a file `a.dart` containing

```dart
%uri="lib/a.dart"
class C {}
```

- And a file named `b.dart` containing
+ And a file `b.dart` containing

```dart
%uri="lib/b.dart"
@@ -1133,6 +1133,52 @@

comment: |-
Parameters:
0: the name of the base class being implemented
+ documentation: |-
+ #### Description
+
+      The analyzer produces this diagnostic when an `extends`, `implements`,
+ `with`, or `on` clause uses a class or mixin in a way that isn't allowed
+ given the modifiers on that class or mixin's declaration.
+
+ The message specifies how the declaration is being used and why it isn't

+ allowed.
+
+ #### Example
+
+      Given a file `a.dart` that defines a base class `A`:

+
+ ```dart
+ %uri="lib/a.dart"
+ base class A {}
+ ```
+
+ The following code produces this diagnostic because the class `B`
+ implements the class `A`, but the `base` modifier prevents `A` from being
+ implemented outside of the library where it's defined:
+
+ ```dart
+ import 'a.dart';
+
+ final class B implements [!A!] {}
+ ```
+
+ #### Common fixes
+
+      Use of this type is restricted outside of its declaring library. If a
+ different, unrestricted type is available that can provide similar
+ functionality, then replace the type:

+
+ ```dart
+ class B implements C {}
+ class C {}
+ ```
+
+ If there isn't a different type that would be appropriate, then remove the
+ type, and possibly the whole clause:
+
+ ```dart
+ class B {}
+ ```
BASE_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY:
sharedName: INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
problemMessage: "The mixin '{0}' can't be implemented outside of its library because it's a base mixin."
@@ -1598,10 +1644,41 @@

int y = x as int;
```
CLASS_USED_AS_MIXIN:
- problemMessage: "The class '{0}' can't be used as a mixin because it isn't a mixin class nor a mixin."
+ problemMessage: "The class '{0}' can't be used as a mixin because it's neither a mixin class nor a mixin."
comment: |-
Parameters:
0: the name of the class being used as a mixin
+ documentation: |-
+ #### Description
+
+      The analyzer produces this diagnostic when a class that is neither a
+ `mixin class` nor a `mixin` is used in a `with` clause.

+
+ #### Example
+
+      The following code produces this diagnostic because the class `M` is being
+ used as a mixin, but it isn't defined as a `mixin class`:

+
+ ```dart
+ class M {}
+ class C with [!M!] {}
+ ```
+
+ #### Common fixes
+
+ If the class can be a pure mixin, then change `class` to `mixin`:
+
+ ```dart
+ mixin M {}
+ class C with M {}
+ ```
+
+ If the class needs to be both a class and a mixin, then add `mixin`:
+
+ ```dart
+ mixin class M {}
+ class C with M {}
+ ```
CLASS_INSTANTIATION_ACCESS_TO_INSTANCE_MEMBER:
sharedName: CLASS_INSTANTIATION_ACCESS_TO_MEMBER
problemMessage: "The instance member '{0}' can't be accessed on a class instantiation."
@@ -1680,12 +1757,12 @@

deferred import. Constants are evaluated at compile time, and values from
deferred libraries aren't available at compile time.

-      For more information, see the language tour's coverage of
- [deferred loading](https://dart.dev/guides/language/language-tour#lazily-loading-a-library).
+ For more information, check out
+ [Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).

#### Example

- Given a file (`a.dart`) that defines the constant `zero`:
+ Given a file `a.dart` that defines the constant `zero`:

```dart
%uri="lib/a.dart"
@@ -1731,6 +1808,84 @@

problemMessage: Constant values from a deferred library can't be used in patterns.
correctionMessage: Try removing the keyword 'deferred' from the import.
comment: No parameters.
+ documentation: |-
+ #### Description
+
+      The analyzer produces this diagnostic when a pattern contains a value
+ declared in a different library, and that library is imported using a
+ deferred import. Constants are evaluated at compile time, but values from
+ deferred libraries aren't available at compile time.
+
+ For more information, check out
+ [Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).

+
+ #### Example
+
+      Given a file `a.dart` that defines the constant `zero`:
@@ -2376,8 +2531,8 @@
Constants are evaluated at compile time, and classes from deferred

libraries aren't available at compile time.

-      For more information, see the language tour's coverage of
- [deferred loading](https://dart.dev/guides/language/language-tour#lazily-loading-a-library).
+ For more information, check out
+ [Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).

#### Example

@@ -2504,8 +2659,8 @@

a deferred import. Constants are evaluated at compile time, and values from
deferred libraries aren't available at compile time.

-      For more information, see the language tour's coverage of
- [deferred loading](https://dart.dev/guides/language/language-tour#lazily-loading-a-library).
+ For more information, check out
+ [Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).

#### Example

@@ -2587,12 +2742,13 @@

#### Description

The analyzer produces this diagnostic when the class of object used as a
- key in a constant map literal implements the `==` operator. The
- implementation of constant maps uses the `==` operator, so any
- implementation other than the one inherited from `Object` requires
- executing arbitrary code at compile time, which isn't supported.
+ key in a constant map literal implements either the `==` operator, the
+ getter `hashCode`, or both. The implementation of constant maps uses both
+ the `==` operator and the `hashCode` getter, so any implementation other
+ than the ones inherited from `Object` requires executing arbitrary code at
+ compile time, which isn't supported.

- #### Example
+ #### Examples

The following code produces this diagnostic because the constant map
contains a key whose type is `C`, and the class `C` overrides the
@@ -2608,9 +2764,24 @@

const map = {[!C()!] : 0};
```

+ The following code produces this diagnostic because the constant map
+ contains a key whose type is `C`, and the class `C` overrides the
+ implementation of `hashCode`:
+
+ ```dart
+ class C {
+ const C();
+
+ int get hashCode => 3;
+ }
+
+ const map = {[!C()!] : 0};
+ ```
+
#### Common fixes

- If you can remove the implementation of `==` from the class, then do so:
+ If you can remove the implementation of `==` and `hashCode` from the
+ class, then do so:

```dart
class C {
@@ -2620,8 +2791,8 @@

const map = {C() : 0};
```

- If you can't remove the implementation of `==` from the class, then make
- the map be non-constant:
+      If you can't remove the implementation of `==` and `hashCode` from the
+ class, then make the map non-constant:

```dart
class C {
@@ -2671,10 +2842,11 @@

#### Description

The analyzer produces this diagnostic when the class of object used as an
- element in a constant set literal implements the `==` operator. The
- implementation of constant sets uses the `==` operator, so any
- implementation other than the one inherited from `Object` requires
- executing arbitrary code at compile time, which isn't supported.
+ element in a constant set literal implements either the `==` operator, the
+ getter `hashCode`, or both. The implementation of constant sets uses both
+      the `==` operator and the `hashCode` getter, so any implementation other
+ than the ones inherited from `Object` requires executing arbitrary code at
+ compile time, which isn't supported.

#### Example

@@ -2692,9 +2864,24 @@

const set = {[!C()!]};
```

+ The following code produces this diagnostic because the constant set
+ contains an element whose type is `C`, and the class `C` overrides the
+ implementation of `hashCode`:
+
+ ```dart
+ class C {
+ const C();
+
+ int get hashCode => 3;
+ }
+
+ const map = {[!C()!]};
+ ```
+
#### Common fixes

-      If you can remove the implementation of `==` from the class, then do so:
+      If you can remove the implementation of `==` and `hashCode` from the
+ class, then do so:

```dart
class C {
@@ -2704,8 +2891,8 @@

const set = {C()};
```

- If you can't remove the implementation of `==` from the class, then make
- the set be non-constant:
+ If you can't remove the implementation of `==` and `hashCode` from the
+      class, then make the set non-constant:

```dart
class C {
@@ -2944,6 +3131,48 @@
@@ -3183,12 +3412,12 @@
library. Extension methods are resolved at compile time, and extensions

from deferred libraries aren't available at compile time.

-      For more information, see the language tour's coverage of
- [deferred loading](https://dart.dev/guides/language/language-tour#lazily-loading-a-library).
+ For more information, check out
+ [Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).

#### Example

- Given a file (`a.dart`) that defines a named extension:
+ Given a file `a.dart` that defines a named extension:

```dart
%uri="lib/a.dart"
@@ -3455,6 +3684,37 @@

comment: |-
Parameters:
0: the duplicated name
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when either a record literal or a
+      record type annotation contains a field whose name is the same as a
+ previously declared field in the same literal or type.
@@ -3565,7 +3825,7 @@

#### Example

- Given a file named `part.dart` containing
+ Given a file `part.dart` containing

```dart
%uri="lib/part.dart"
@@ -3597,21 +3857,195 @@

comment: |-
Parameters:
0: the name of the variable
+ documentation: |-
+ #### Description
+
+      The analyzer produces this diagnostic when a single pattern variable is
+ assigned a value more than once in the same pattern assignment.

+
+ #### Example
+
+      The following code produces this diagnostic because the variable `a` is
+ assigned twice in the pattern `(a, a)`:
+
+ ```dart
+ int f((int, int) r) {
+ int a;
+ (a, [!a!]) = r;
+ return a;
+ }
+ ```
+
+ #### Common fixes
+
+ If you need to capture all of the values, then use a unique variable for
+      each of the subpatterns being matched:

+
+ ```dart
+ int f((int, int) r) {
+ int a, b;
+ (a, b) = r;
+ return a + b;
+ }
+ ```
+
+      If some of the values don't need to be captured, then use a wildcard
+ pattern `_` to avoid having to bind the value to a variable:

+
+ ```dart
+ int f((int, int) r) {
+ int a;
+ (_, a) = r;
+ return a;
+ }
+ ```
DUPLICATE_PATTERN_FIELD:
problemMessage: The field '{0}' is already matched in this pattern.
correctionMessage: Try removing the duplicate field.
comment: |-
Parameters:
       0: the name of the field

+ documentation: |-
+ #### Description
+
+      The analyzer produces this diagnostic when a record pattern matches the
+      same field more than once, or when an object pattern matches the same
+      pattern in either a list or map pattern. A rest pattern will capture any
+ values unmatched by other subpatterns, making subsequent rest patterns
+ unnecessary because there's nothing left to capture.

+
+ #### Example
+
+      the variable pattern from all but one branch:
+
+ ```dart
+ void f((int, int) r) {
+ if (r case (var a, 0) && (0, _)) {

+ print(a);
+ }
+ }
+ ```
ENUM_CONSTANT_SAME_NAME_AS_ENCLOSING:
problemMessage: "The name of the enum constant can't be the same as the enum's name."
correctionMessage: Try renaming the constant.
@@ -3880,12 +4314,75 @@

problemMessage: Two keys in a map pattern can't be equal.
correctionMessage: Change or remove the duplicate key.
comment: No parameters.
+ documentation: |-
+ #### Description
+
+      The analyzer produces this diagnostic when a map pattern contains more
+ than one key with the same name. The same key can't be matched twice.

+
+ #### Example
+
+      one type argument. List patterns can have either zero type arguments or
+ one type argument, but can't have more than one.

+
+ #### Example
+
+      The following code produces this diagnostic because the list pattern
+ (`[0]`) has two type arguments:
+
+ ```dart
+ void f(Object x) {
+ if (x case [!<int, int>!][0]) {}
+ }
+ ```
+
+ #### Common fixes
+
+ Remove all but one of the type arguments:
+
+ ```dart
+ void f(Object x) {
+ if (x case <int>[0]) {}
+ }
+ ```
EXPECTED_ONE_LIST_TYPE_ARGUMENTS:
problemMessage: "List literals require one type argument or none, but {0} found."
correctionMessage: Try adjusting the number of type arguments.
@@ -3979,6 +4476,34 @@

comment: |-
Parameters:
0: the number of provided type arguments
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a map pattern has either one
+      type argument or more than two type arguments. Map patterns can have
+ either two type arguments or zero type arguments, but can't have any other

+ number.
+
+ #### Example
+
+ The following code produces this diagnostic because the map pattern
+ (`<int>{}`) has one type argument:
+
+ ```dart
+ void f(Object x) {
+ if (x case [!<int>!]{}) {}
+ }
+ ```
+
+ #### Common fixes
+
+      Add or remove type arguments until there are two, or none:

+
+ ```dart
+ void f(Object x) {
+ if (x case <int, int>{}) {}
+ }
+ ```
EXPORT_INTERNAL_LIBRARY:
problemMessage: "The library '{0}' is internal and can't be exported."
hasPublishedDocs: true
@@ -4071,7 +4596,7 @@

#### Example

- Given a file named `part.dart` containing
+ Given a file `part.dart` containing

```dart
%uri="lib/part.dart"
@@ -6205,6 +6730,79 @@

comment: |-
Parameters:
0: the name of the pattern variable
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a pattern variable that is
+      declared on all branches of a logical-or pattern doesn't have the same
+ type on every branch. It is also produced when the variable has a
+ different finality on different branches. A pattern variable declared on
+ multiple branches of a logical-or pattern is required to have the same
+ type and finality in each branch, so that the type and finality of the
@@ -6826,8 +7424,8 @@
of an annotation. Annotations are evaluated at compile time, and values

from deferred libraries aren't available at compile time.

-      For more information, see the language tour's coverage of
- [deferred loading](https://dart.dev/guides/language/language-tour#lazily-loading-a-library).
+ For more information, check out
+ [Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).

#### Example

@@ -6878,8 +7476,8 @@
are evaluated at compile time, and constants from deferred libraries aren't
available at compile time.

- For more information, see the language tour's coverage of
- [deferred loading](https://dart.dev/guides/language/language-tour#lazily-loading-a-library).
+ For more information, check out
+ [Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).

#### Example

@@ -7162,6 +7760,71 @@

problemMessage: Record field names can't be the same as a member from 'Object'.
correctionMessage: Try using a different name for the field.
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when either a record literal or a
+ record type annotation has a field whose name is invalid. The name is
+ invalid if it is:
+      - private (starts with `_`)
+ - the same as one of the members defined on `Object`
+ - the same as the name of a positional field (an exception is made if the
+ field is a positional field with the specified name)

+
+ #### Examples
+
+      var r = (2, [!$1!]: 1);

+ ```
+
+ The following code produces this diagnostic because the record type
+ annotation has a field named `$1`, which is also the name of a different
+ positional parameter:
+
+ ```dart
+ void f((int, String, {int [!$1!]}) r) {}
+ ```
+
+ #### Common fixes
+
+ Rename the field:
+
+ ```dart
+ var r = (a: 1, d: 4);
+ ```
INVALID_FIELD_NAME_PRIVATE:
sharedName: INVALID_FIELD_NAME
problemMessage: Record field names can't be private.
@@ -8534,6 +9197,69 @@

MISSING_OBJECT_PATTERN_GETTER_NAME:
problemMessage: The getter name is not specified explicitly, and the pattern is not a variable.
correctionMessage: Try specifying the getter name explicitly, or using a variable pattern.
+ documentation: |-
+ #### Description
+
+      The analyzer produces this diagnostic when, within an object pattern, the
+ specification of a property and the pattern used to match the property's
+ value doesn't have either:
+ - a getter name before the colon
+ - a variable pattern from which the getter name can be inferred

+
+ #### Example
+
+      The following code produces this diagnostic because there is no getter
+      name before the colon and no variable pattern after the colon in the
+ object pattern (`C(:0)`):
+          case C(:var f) when f == 0:

+ print(f);
+ }
+ }
+ ```
+
+      If you don't need to use the actual value of the property within the
+ pattern's scope, then add the name of the property being matched before
+ the colon:

+
+ ```dart
+ abstract class C {
+ int get f;
+ }
+
+ void f(C c) {
+ switch (c) {
+ case C(f: 0):
+ break;
+ }
+ }
+ ```
MISSING_REQUIRED_ARGUMENT:
problemMessage: "The named parameter '{0}' is required, but there's no corresponding argument."
correctionMessage: Try adding the required argument.
@@ -8575,6 +9301,66 @@
+      If the variable doesn't need to be referenced in the controlled
+ statements, then remove the declaration of the variable from every branch
+ of the logical-or pattern:

+
+ ```dart
+ void f((int, int) r) {
+ if (r case (_, 0) || (0, _)) {
+ print('found a zero');
+ }
+ }
+ ```
+
+ If the variable needs to be referenced if one branch of the pattern
+ matches but not when the other matches, then break the pattern into two
+ pieces:
+
+ ```dart
+ void f((int, int) r) {
+        switch (r) {
+ case (var a, 0):
+ print(a);
+ case (0, _):

+ print('found a zero');
+ }
+ }
+ ```
MIXINS_SUPER_CLASS:
sharedName: IMPLEMENTS_SUPER_CLASS
problemMessage: "'{0}' can't be used in both the 'extends' and 'with' clauses."
@@ -9578,12 +10364,12 @@
constants referenced in case clauses need to be available at compile time,
and constants from deferred libraries aren't available at compile time.

- For more information, see the language tour's coverage of
- [deferred loading](https://dart.dev/guides/language/language-tour#lazily-loading-a-library).
+ For more information, check out
+ [Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).

#### Example

- Given a file (`a.dart`) that defines the constant `zero`:
+ Given a file `a.dart` that defines the constant `zero`:

```dart
%uri="lib/a.dart"
@@ -9707,12 +10493,12 @@
Default values need to be available at compile time, and constants from

deferred libraries aren't available at compile time.

-      For more information, see the language tour's coverage of
- [deferred loading](https://dart.dev/guides/language/language-tour#lazily-loading-a-library).
+ For more information, check out
+ [Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).

#### Example

- Given a file (`a.dart`) that defines the constant `zero`:
+ Given a file `a.dart` that defines the constant `zero`:

```dart
%uri="lib/a.dart"
@@ -9875,6 +10661,40 @@
+      Use a constant for the key:

+
+ ```dart
+ void f(Object x) {
+        if (x case {const A(): 0}) {}
+ }
+
+ class A {
+ const A();
+ }
+ ```
NON_CONSTANT_MAP_VALUE:
problemMessage: The values in a const map literal must be constant.
correctionMessage: "Try removing the keyword 'const' from the map literal."
@@ -9915,6 +10735,36 @@
@@ -9966,6 +10816,67 @@

Parameters:
0: the type of the switch scrutinee
1: the unmatched space
+ documentation: |-
+ #### Description
+
+      The analyzer produces this diagnostic when a `switch` statement switching
+ over an exhaustive type is missing a case for one or more of the possible
+ values that could flow through it.

+
+ #### Example
+
+      The following code produces this diagnostic because the switch statement
+ doesn't have a case for the value `E.three`, and `E` is an exhaustive
+ type:
+
+ ```dart
+
+ If the missing values don't need to be matched, then add a `default`
+ clause (or a wildcard pattern in a `switch` expression):

+
+ ```dart
+ enum E { one, two, three }
+
+ void f(E e) {
+ switch (e) {
+ case E.one:
+ case E.two:
+ break;
+          default:
+ }
+ }
+ ```
+
+ But be aware that adding a `default` clause or wildcard pattern will cause
+ any future values of the exhaustive type to also be handled, so you will
+ have lost the ability for the compiler to warn you if the `switch` needs
+ to be updated.

NON_FINAL_FIELD_IN_ENUM:
problemMessage: Enums can only declare final fields.
correctionMessage: Try making the field final.
@@ -11223,7 +12134,7 @@

#### Example

- Given a file named `part.dart` containing
+ Given a file `part.dart` containing

```dart
%uri="package:a/part.dart"
@@ -11261,7 +12172,7 @@

#### Example

- Given a file (`a.dart`) containing:
+ Given a file `a.dart` containing:

```dart
%uri="lib/a.dart"
@@ -11335,8 +12246,61 @@

part of 'test.dart';
```
PATTERN_ASSIGNMENT_NOT_LOCAL_VARIABLE:
- problemMessage: Only local variables or formal parameters can be used in pattern assignments.
+ problemMessage: Only local variables can be assigned in pattern assignments.
correctionMessage: Try assigning to a local variable.
+ comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a pattern assignment assigns a
+ value to anything other than a local variable. Patterns can't assign to
+ fields or top-level variables.
+
+ #### Example
+
+      If the code is cleaner when destructuring with a pattern, then rewrite the
+ code to assign the value to a local variable in a pattern declaration,
+ assigning the non-local variable separately:
@@ -11344,22 +12308,243 @@

Parameters:
0: the matched type
1: the required type
+ documentation: |-
+ #### Description
+
+      The analyzer produces this diagnostic when the type of the value on the
+ right-hand side of a pattern assignment or pattern declaration doesn't
+ match the type required by the pattern being used to match it.
+      The analyzer produces this diagnostic when multiple case clauses in a
+ switch statement share a body, and at least one of them declares a
+ variable that is referenced in the shared statements, but the variable is
+ either not declared in all of the case clauses or it is declared in
+ inconsistent ways.

+
+ If the variable isn't declared in all of the case clauses, then it won't
+      have a value if one of the clauses that doesn't declare the variable is
+ the one that matches and executes the body. This includes the situation
+ where one of the case clauses is the `default` clause.
+          case int b when b < 0:

+ continue someLabel;
+ }
+ }
+ ```
+
+ The following code produces this diagnostic because the variable `a`,
+ while being assigned in all of the case clauses, doesn't have then same
+ type associated with it in every clause:
+
+ ```dart
+ void f(Object? x) {
+ switch (x) {
+ case int a when a < 0:
+ case num a when a > 0:
+ [!a!];
+ }
+ }
+ ```
+
+      The following code produces this diagnostic because the variable `a` is
+      `final` in the first case clause and isn't `final` in the second case
+ clause:
+
+ ```dart
+ void f(Object? x) {
+ switch (x) {
+ case final int a when a < 0:
+ case int a when a > 0:
+ [!a!];
+ }
+ }
+ ```
+
+ #### Common fixes
+
+      If the variable isn't declared in all of the cases, and you need to
+ reference it in the statements, then declare it in the other cases:

+
+ ```dart
+ void f(Object? x) {
+ switch (x) {
+          case int a when a > 0:
+ case int a when a == 0:
+ a;
+ }
+ }
+ ```
+
+ If the variable isn't declared in all of the cases, and you don't need to
+ reference it in the statements, then remove the references to it and
+ remove the declarations from the other cases:
+
+ ```dart
+ void f(int x) {
+ switch (x) {
+ case > 0:
+ case 0:
+ }
+ }
+ ```
+
+      If the type of the variable is different, decide the type the variable
+ should have and make the cases consistent:
@@ -11584,7 +12769,7 @@

#### Example

- Given a file named `a.dart` containing the following code:
+ Given a file `a.dart` containing the following code:

```dart
%uri="lib/a.dart"
@@ -11664,7 +12849,7 @@

#### Example

- Given a file named `a.dart` that contains the following:
+ Given a file `a.dart` that contains the following:

```dart
%uri="lib/a.dart"
@@ -12464,6 +13649,38 @@
   RELATIONAL_PATTERN_OPERAND_TYPE_NOT_ASSIGNABLE:
problemMessage: "The constant expression type '{0}' is not assignable to the parameter type '{1}' of the '{2}' operator."
comment: |-
@@ -12474,12 +13691,141 @@

RELATIONAL_PATTERN_OPERATOR_RETURN_TYPE_NOT_ASSIGNABLE_TO_BOOL:
problemMessage: The return type of operators used in relational patterns must be assignable to 'bool'.
correctionMessage: Try updating the operator declaration to return 'bool'.
+ documentation: |-
+ #### Description
+
+      The analyzer produces this diagnostic when a relational pattern references
+ an operator that doesn't produce a value of type `bool`.

+
+ #### Example
+
+      has a subpattern. In Dart, there is no notion of a subset of a map, so
+ there isn't anything to match against the subpattern.

+
+ #### Example
+
     correctionMessage: Try moving the rest element to be the last element.

+ documentation: |-
+ #### Description
+
+      The analyzer produces this diagnostic when a map pattern contains entries
+ after a rest pattern. The rest pattern will match map entries whose keys
+ aren't matched by any of the entries in the pattern. To make those
+      semantics clear, the language requires that the rest pattern be the last
@@ -12916,6 +14262,32 @@
Parameters:

0: the name of the subtype that is not 'base', 'final', or 'sealed'
       1: the name of the 'base' supertype

+ documentation: |-
+ #### Description
+
+      The analyzer produces this diagnostic when a class or mixin has a direct
+ or indirect supertype that is either `base` or `final`, but the class or
+ mixin itself isn't marked either `base`, `final`, or `sealed`.

+
+ #### Example
+
+      The following code produces this diagnostic because the class `B` is a
+ subtype of `A`, and `A` is a `base` class, but `B` is neither `base`,
+ `final` or `sealed`:
+
+ ```dart
+ base class A {}
+ class [!B!] extends A {}
+ ```
+
+ #### Common fixes
+
+ Add either `base`, `final` or `sealed` to the class or mixin declaration:
+
+ ```dart
+ base class A {}
+ final class B extends A {}
+ ```
   SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED:
sharedName: SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED
problemMessage: "The type '{0}' must be 'base', 'final' or 'sealed' because the supertype '{1}' is 'final'."
@@ -13169,12 +14541,12 @@
classes from deferred libraries aren't compiled until the library is
loaded.

- For more information, see the language tour's coverage of
- [deferred loading](https://dart.dev/guides/language/language-tour#lazily-loading-a-library).
+ For more information, check out
+ [Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).

#### Example

- Given a file (`a.dart`) that defines the class `A`:
+ Given a file `a.dart` that defines the class `A`:

```dart
%uri="lib/a.dart"
@@ -13661,7 +15033,7 @@

#### Common fixes

- Add an explicit null check to the expression:
+ Add an explicit null-check to the expression:

```dart
void f(String? s) {
@@ -13761,8 +15133,8 @@
is a type declared in a library that is imported using a deferred import.
These types are required to be available at compile time, but aren't.

- For more information, see the language tour's coverage of
- [deferred loading](https://dart.dev/guides/language/language-tour#lazily-loading-a-library).
+ For more information, check out
+ [Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).

#### Example

@@ -15541,6 +16913,35 @@

VARIABLE_PATTERN_KEYWORD_IN_DECLARATION_CONTEXT:
problemMessage: Variable patterns in declaration context can't specify 'var' or 'final' keyword.
correctionMessage: Try removing the keyword.
+ comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a variable pattern is used
+ within a declaration context.
+
+ #### Example
+
+ The following code produces this diagnostic because the variable patterns
+ in the record pattern are in a declaration context:
+
+ ```dart
+ void f((int, int) r) {
+        var ([!var!] x, y) = r;

+ print(x + y);
+ }
+ ```
+
+ #### Common fixes
+
+ Remove the `var` or `final` keyword(s) within the variable pattern:
+
+ ```dart
+ void f((int, int) r) {
+ var (x, y) = r;
+ print(x + y);
+ }
+ ```
VARIABLE_TYPE_MISMATCH:
problemMessage: "A value of type '{0}' can't be assigned to a const variable of type '{1}'."
correctionMessage: "Try using a subtype, or removing the 'const' keyword"
@@ -18205,12 +19606,12 @@
function is used to load the contents of the deferred library, and the
implicit function hides the explicit declaration in the deferred library.

- For more information, see the language tour's coverage of
- [deferred loading](https://dart.dev/guides/language/language-tour#lazily-loading-a-library).
+ For more information, check out
+ [Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).

#### Example

- Given a file (`a.dart`) that defines a function named `loadLibrary`:
+ Given a file `a.dart` that defines a function named `loadLibrary`:

```dart
%uri="lib/a.dart"
@@ -18281,7 +19682,7 @@

#### Example

- Given a file named `a.dart` that contains the following:
+ Given a file `a.dart` that contains the following:

```dart
%uri="lib/a.dart"
@@ -18533,14 +19934,14 @@

#### Example

- Given a file named `a.dart` that contains the following:
+ Given a file `a.dart` that contains the following:

```dart
%uri="lib/a.dart"
class A {}
```

- And, given a file named `b.dart` that contains the following:
+ And, given a file `b.dart` that contains the following:

```dart
%uri="lib/b.dart"
@@ -18572,6 +19973,43 @@

correctionMessage: Try removing the set literal around the expression.
hasPublishedDocs: false
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a function that has a return
+ type of `void`, `Future<void>`, or `FutureOr<void>` uses an expression
+      function body (`=>`) and the returned value is a literal set containing a
+ single element.
+
+ Although the language allows it, returning a value from a `void` function
+ isn't useful because it can't be used at the call site. In this particular
+ case the return is often due to a misunderstanding about the syntax. The
+ braces aren't necessary and can be removed.
@@ -18616,7 +20054,45 @@

comment: No parameters.
UNREACHABLE_SWITCH_CASE:
problemMessage: "This case is covered by the previous cases."
+ correctionMessage: Try removing the case clause, or restructuring the preceding patterns.
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a `case` clause in a `switch`
+ statement doesn't match anything because all of the matchable values are
+ matched by an earlier `case` clause.
+
+ #### Example
+
+      The following code produces this diagnostic because the value `1` was
+ matched in the preceeding case:

+
+ ```dart
+ void f(int x) {
+ switch (x) {
+          case 1:
+ print('one');
+ [!case!] 1:
+ print('two');
+ }
+ }
+ ```
+

+ #### Common fixes
+
+      Change one or both of the conflicting cases to match different values:

+
+ ```dart
+ void f(int x) {
+ switch (x) {
+          case 1:
+ print('one');
+ case 2:
+ print('two');

+ }
+ }
+ ```
UNUSED_ELEMENT:
problemMessage: "The declaration '{0}' isn't referenced."
correctionMessage: "Try removing the declaration of '{0}'."
@@ -19684,7 +21160,7 @@

#### Example

- Assuming that the directory `local_package` doesn't contain a file named
+ Assuming that the directory `local_package` doesn't contain a file
`pubspec.yaml`, the following code produces this diagnostic because it's
listed as the path of a package:

@@ -20015,10 +21491,63 @@

problemMessage: The null-assert pattern will have no effect because the matched type isn't nullable.
correctionMessage: Try replacing the null-assert pattern with its nested pattern.
comment: No parameters.
+
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a null-assert pattern is used
+ to match a value that isn't nullable.
+
+ #### Example
+
+ The following code produces this diagnostic because the variable `x` isn't
+ nullable:
+
+ ```dart
+ void f(int x) {
+ if (x case var a[!!!] when a > 0) {}
+ }
+ ```
+
+ #### Common fixes
+
+      Remove the null-assert pattern:
+      Remove the null-check pattern:

+
+ ```dart
+ void f(int x) {
+        if (x case var a when a > 0) {}
+ }
+ ```
WarningCode:
ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER:
problemMessage: "The argument type '{0}' can't be assigned to the parameter type '{1} Function(Object)' or '{1} Function(Object, StackTrace)'."
@@ -20292,6 +21821,44 @@

Parameters:
0: the matched value type
1: the constant value type
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a constant pattern can never
+      match the value it's being tested against because the type of the constant
+ is known to never match the type of the value.

+
+ #### Example
+
@@ -20793,7 +22360,7 @@

#### Example

- Given a file named `a.dart` in the `src` directory that contains:
+ Given a file `a.dart` in the `src` directory that contains:

```dart
%uri="lib/src/a.dart"
@@ -20837,7 +22404,7 @@

#### Example

- Given a file named `a.dart` in the `src` directory that contains the
+ Given a file `a.dart` in the `src` directory that contains the
following:

```dart
@@ -21404,7 +22971,7 @@

#### Example

- Given a file named `a.dart` containing the following declaration:
+ Given a file `a.dart` containing the following declaration:

```dart
%uri="lib/a.dart"
@@ -21461,7 +23028,7 @@

#### Example

- Given a file named `c.dart` that contains the following:
+ Given a file `c.dart` that contains the following:

```dart
%uri="lib/c.dart"
diff --git a/pkg/analyzer/test/verify_diagnostics_test.dart b/pkg/analyzer/test/verify_diagnostics_test.dart
index 0473a48..3be5507 100644
--- a/pkg/analyzer/test/verify_diagnostics_test.dart
+++ b/pkg/analyzer/test/verify_diagnostics_test.dart
@@ -196,15 +196,23 @@
diff --git a/pkg/analyzer/tool/diagnostics/diagnostics.md b/pkg/analyzer/tool/diagnostics/diagnostics.md
index 202daa5..41b2dc2 100644
--- a/pkg/analyzer/tool/diagnostics/diagnostics.md
+++ b/pkg/analyzer/tool/diagnostics/diagnostics.md
@@ -285,6 +285,7 @@

[ffi]: https://dart.dev/guides/libraries/c-interop
[IEEE 754]: https://en.wikipedia.org/wiki/IEEE_754
+[irrefutable pattern]: https://dart.dev/resources/glossary#irrefutable-pattern
[meta-doNotStore]: https://pub.dev/documentation/meta/latest/meta/doNotStore-constant.html
[meta-factory]: https://pub.dev/documentation/meta/latest/meta/factory-constant.html
[meta-immutable]: https://pub.dev/documentation/meta/latest/meta/immutable-constant.html
@@ -297,6 +298,7 @@
[meta-UseResult]: https://pub.dev/documentation/meta/latest/meta/UseResult-class.html
[meta-visibleForOverriding]: https://pub.dev/documentation/meta/latest/meta/visibleForOverriding-constant.html
[meta-visibleForTesting]: https://pub.dev/documentation/meta/latest/meta/visibleForTesting-constant.html
+[refutable pattern]: https://dart.dev/resources/glossary#refutable-pattern

### abi_specific_integer_invalid

@@ -562,6 +564,41 @@
}
{% endprettify %}

+### abstract_sealed_class
+
+_A class can't be declared both 'sealed' and 'abstract'._
+
+#### Description
+
+The analyzer produces this diagnostic when a class is declared using both
+the modifier `abstract` and the modifier `sealed`. Sealed classes are
+implicitly abstract, so explicitly using both modifiers is not allowed.
+
+#### Example
+
+The following code produces this diagnostic because the class `C` is
+declared using both `abstract` and `sealed`:
+
+{% prettify dart tag=pre+code %}
+abstract [!sealed!] class C {}
+{% endprettify %}
+
+#### Common fixes
+
+If the class should be abstract but not sealed, then remove the `sealed`
+modifier:
+
+{% prettify dart tag=pre+code %}
+abstract class C {}
+{% endprettify %}
+
+If the class should be both abstract and sealed, then remove the
+`abstract` modifier:
+
+{% prettify dart tag=pre+code %}
+sealed class C {}
+{% endprettify %}
+
### abstract_super_member_reference

_The {0} '{1}' is always abstract in the supertype._
@@ -602,13 +639,13 @@

#### Example

-Given a file named `a.dart` containing
+Given a file `a.dart` containing

{% prettify dart tag=pre+code %}
class C {}
{% endprettify %}

-And a file named `b.dart` containing
+And a file `b.dart` containing

{% prettify dart tag=pre+code %}
class C {}
@@ -2264,6 +2301,42 @@

int y = x as int;
 {% endprettify %}

+### class_used_as_mixin
+
+_The class '{0}' can't be used as a mixin because it's neither a mixin class nor
+a mixin._
+
+#### Description
+
+The analyzer produces this diagnostic when a class that is neither a
+`mixin class` nor a `mixin` is used in a `with` clause.
+
+#### Example
+
+The following code produces this diagnostic because the class `M` is being
+used as a mixin, but it isn't defined as a `mixin class`:
+
+{% prettify dart tag=pre+code %}
+class M {}
+class C with [!M!] {}
+{% endprettify %}
+
+#### Common fixes
+
+If the class can be a pure mixin, then change `class` to `mixin`:
+
+{% prettify dart tag=pre+code %}
+mixin M {}
+class C with M {}
+{% endprettify %}
+
+If the class needs to be both a class and a mixin, then add `mixin`:
+
+{% prettify dart tag=pre+code %}
+mixin class M {}
+class C with M {}
+{% endprettify %}
+
### collection_element_from_deferred_library

_Constant values from a deferred library can't be used as keys in a 'const' map
@@ -2287,12 +2360,12 @@

deferred import. Constants are evaluated at compile time, and values from
deferred libraries aren't available at compile time.

-For more information, see the language tour's coverage of
-[deferred loading](https://dart.dev/guides/language/language-tour#lazily-loading-a-library).
+For more information, check out
+[Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).

#### Example

-Given a file (`a.dart`) that defines the constant `zero`:
+Given a file `a.dart` that defines the constant `zero`:

{% prettify dart tag=pre+code %}
const zero = 0;
@@ -2621,6 +2694,95 @@
}
{% endprettify %}

+### constant_pattern_never_matches_value_type
+
+_The matched value type '{0}' can never be equal to this constant of type
+'{1}'._
+
+#### Description
+
+The analyzer produces this diagnostic when a constant pattern can never
+match the value it's being tested against because the type of the constant
+is known to never match the type of the value.
+
+#### Example
+
+The following code produces this diagnostic because the type of the
+constant pattern `(true)` is `bool`, and the type of the value being
+matched (`x`) is `int`, and a Boolean can never match an integer:
+
+{% prettify dart tag=pre+code %}
+void f(int x) {

+ if (x case [!true!]) {}
+}
+{% endprettify %}
+
+#### Common fixes
+
+If the type of the value is correct, then rewrite the pattern to be
+compatible:
+
+{% prettify dart tag=pre+code %}
+void f(int x) {

+ if (x case 3) {}
+}
+{% endprettify %}
+
+If the type of the constant is correct, then rewrite the value to be
+compatible:
+
+{% prettify dart tag=pre+code %}
+void f(bool x) {

+ if (x case true) {}
+}
+{% endprettify %}
+
+### constant_pattern_with_non_constant_expression
+
+_The expression of a constant pattern must be a valid constant._
+
+#### Description
+
+The analyzer produces this diagnostic when a constant pattern has an
+expression that isn't a valid constant.
+
+#### Example
+
+The following code produces this diagnostic because the constant pattern

+`i` isn't a constant:
+
+{% prettify dart tag=pre+code %}
+void f(int e, int i) {

+ switch (e) {
+ case [!i!]:
+ break;
+ }
+}
+{% endprettify %}
+
+#### Common fixes
+
+If the value that should be matched is known, then replace the expression
+with a constant:
+
+{% prettify dart tag=pre+code %}
+void f(int e, int i) {

+ switch (e) {
+ case 0:
+ break;
+ }
+}
+{% endprettify %}
+
+If the value that should be matched isn't known, then rewrite the code to
+not use a pattern:
+
+{% prettify dart tag=pre+code %}
+void f(int e, int i) {

+ if (e == i) {}
+}
+{% endprettify %}
+
### const_constructor_param_type_mismatch

_A value of type '{0}' can't be assigned to a parameter of type '{1}' in a const
@@ -2842,8 +3004,8 @@
Constants are evaluated at compile time, and classes from deferred

libraries aren't available at compile time.

-For more information, see the language tour's coverage of
-[deferred loading](https://dart.dev/guides/language/language-tour#lazily-loading-a-library).
+For more information, check out
+[Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).

#### Example

@@ -2926,8 +3088,8 @@

a deferred import. Constants are evaluated at compile time, and values from
deferred libraries aren't available at compile time.

-For more information, see the language tour's coverage of
-[deferred loading](https://dart.dev/guides/language/language-tour#lazily-loading-a-library).
+For more information, check out
+[Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).

#### Example

@@ -3006,12 +3168,13 @@
#### Description

The analyzer produces this diagnostic when the class of object used as a
-key in a constant map literal implements the `==` operator. The
-implementation of constant maps uses the `==` operator, so any
-implementation other than the one inherited from `Object` requires
-executing arbitrary code at compile time, which isn't supported.
+key in a constant map literal implements either the `==` operator, the
+getter `hashCode`, or both. The implementation of constant maps uses both
+the `==` operator and the `hashCode` getter, so any implementation other
+than the ones inherited from `Object` requires executing arbitrary code at
+compile time, which isn't supported.

-#### Example
+#### Examples


The following code produces this diagnostic because the constant map
contains a key whose type is `C`, and the class `C` overrides the
@@ -3027,9 +3190,24 @@

const map = {[!C()!] : 0};
 {% endprettify %}

+The following code produces this diagnostic because the constant map
+contains a key whose type is `C`, and the class `C` overrides the
+implementation of `hashCode`:
+
+{% prettify dart tag=pre+code %}
+class C {

+ const C();
+
+ int get hashCode => 3;
+}
+
+const map = {[!C()!] : 0};
+{% endprettify %}
+
#### Common fixes

-If you can remove the implementation of `==` from the class, then do so:
+If you can remove the implementation of `==` and `hashCode` from the
+class, then do so:

{% prettify dart tag=pre+code %}
class C {
@@ -3039,8 +3217,8 @@

const map = {C() : 0};
 {% endprettify %}

-If you can't remove the implementation of `==` from the class, then make
-the map be non-constant:
+If you can't remove the implementation of `==` and `hashCode` from the
+class, then make the map non-constant:

{% prettify dart tag=pre+code %}
class C {
@@ -3085,10 +3263,11 @@

#### Description

The analyzer produces this diagnostic when the class of object used as an
-element in a constant set literal implements the `==` operator. The
-implementation of constant sets uses the `==` operator, so any
-implementation other than the one inherited from `Object` requires
-executing arbitrary code at compile time, which isn't supported.
+element in a constant set literal implements either the `==` operator, the
+getter `hashCode`, or both. The implementation of constant sets uses both
+the `==` operator and the `hashCode` getter, so any implementation other
+than the ones inherited from `Object` requires executing arbitrary code at
+compile time, which isn't supported.

#### Example

@@ -3106,9 +3285,24 @@
const set = {[!C()!]};
{% endprettify %}

+The following code produces this diagnostic because the constant set
+contains an element whose type is `C`, and the class `C` overrides the
+implementation of `hashCode`:
+
+{% prettify dart tag=pre+code %}
+class C {

+ const C();
+
+ int get hashCode => 3;
+}
+
+const map = {[!C()!]};
+{% endprettify %}
+
#### Common fixes

-If you can remove the implementation of `==` from the class, then do so:
+If you can remove the implementation of `==` and `hashCode` from the
+class, then do so:

{% prettify dart tag=pre+code %}
class C {
@@ -3118,8 +3312,8 @@
const set = {C()};
{% endprettify %}

-If you can't remove the implementation of `==` from the class, then make
-the set be non-constant:
+If you can't remove the implementation of `==` and `hashCode` from the
+class, then make the set non-constant:

{% prettify dart tag=pre+code %}
class C {
@@ -3851,12 +4045,12 @@
library. Extension methods are resolved at compile time, and extensions

from deferred libraries aren't available at compile time.

-For more information, see the language tour's coverage of
-[deferred loading](https://dart.dev/guides/language/language-tour#lazily-loading-a-library).
+For more information, check out
+[Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).

#### Example

-Given a file (`a.dart`) that defines a named extension:
+Given a file `a.dart` that defines a named extension:

{% prettify dart tag=pre+code %}
class C {}
@@ -4468,6 +4662,41 @@
}
{% endprettify %}

+### duplicate_field_name
+
+_The field name '{0}' is already used in this record._
+
+#### Description
+
+The analyzer produces this diagnostic when either a record literal or a
+record type annotation contains a field whose name is the same as a
+previously declared field in the same literal or type.
+
+#### Examples
+
+The following code produces this diagnostic because the record literal has
+two fields named `a`:
+
+{% prettify dart tag=pre+code %}
+var r = (a: 1, [!a!]: 2);
+{% endprettify %}
+
+The following code produces this diagnostic because the record type
+annotation has two fields named `a`, one a positional field and the other
+a named field:
+
+{% prettify dart tag=pre+code %}
+void f((int a, {int [!a!]}) r) {}
+{% endprettify %}
+
+#### Common fixes
+
+Rename one or both of the fields:
+
+{% prettify dart tag=pre+code %}
+var r = (a: 1, b: 2);
+{% endprettify %}
+
### duplicate_hidden_name

_Duplicate hidden name._
@@ -4648,7 +4877,7 @@

#### Example

-Given a file named `part.dart` containing
+Given a file `part.dart` containing

{% prettify dart tag=pre+code %}
part of lib;
@@ -4674,6 +4903,149 @@
part 'part.dart';
{% endprettify %}

+### duplicate_pattern_assignment_variable
+
+_The variable '{0}' is already assigned in this pattern._
+
+#### Description
+
+The analyzer produces this diagnostic when a single pattern variable is
+assigned a value more than once in the same pattern assignment.
+
+#### Example
+
+The following code produces this diagnostic because the variable `a` is
+assigned twice in the pattern `(a, a)`:
+
+{% prettify dart tag=pre+code %}
+int f((int, int) r) {

+ int a;
+ (a, [!a!]) = r;
+ return a;
+}
+{% endprettify %}
+
+#### Common fixes
+
+If you need to capture all of the values, then use a unique variable for
+each of the subpatterns being matched:
+
+{% prettify dart tag=pre+code %}
+int f((int, int) r) {

+ int a, b;
+ (a, b) = r;
+ return a + b;
+}
+{% endprettify %}
+
+If some of the values don't need to be captured, then use a wildcard
+pattern `_` to avoid having to bind the value to a variable:
+
+{% prettify dart tag=pre+code %}
+int f((int, int) r) {

+ int a;
+ (_, a) = r;
+ return a;
+}
+{% endprettify %}
+
+### duplicate_pattern_field
+
+_The field '{0}' is already matched in this pattern._
+
+#### Description
+
+The analyzer produces this diagnostic when a record pattern matches the
+same field more than once, or when an object pattern matches the same

+getter more than once.
+
+#### Examples
+
+The following code produces this diagnostic because the record field `a`
+is matched twice in the same record pattern:
+
+{% prettify dart tag=pre+code %}
+void f(({int a, int b}) r) {

+ switch (r) {
+ case (a: 1, [!a!]: 2):
+ return;
+ }
+}
+{% endprettify %}
+
+The following code produces this diagnostic because the getter `f` is
+matched twice in the same object pattern:
+
+{% prettify dart tag=pre+code %}
+void f(Object o) {

+ switch (0) {
+ case C(f: 1, [!f!]: 2):
+ return;
+ }
+}
+class C {
+ int? f;
+}
+{% endprettify %}
+
+#### Common fixes
+
+If the pattern should match for more than one value of the duplicated
+field, then use a logical-or pattern:
+
+{% prettify dart tag=pre+code %}
+void f(({int a, int b}) r) {
+ switch (r) {
+ case (a: 1, b: _) || (a: 2, b: _):
+ break;
+ }
+}
+{% endprettify %}
+
+If the pattern should match against multiple fields, then change the name
+of one of the fields:
+
+{% prettify dart tag=pre+code %}
+void f(({int a, int b}) r) {

+ switch (r) {
+ case (a: 1, b: 2):
+ return;
+ }
+}
+{% endprettify %}
+
+### duplicate_rest_element_in_pattern
+
+_At most one rest element is allowed in a list or map pattern._
+
+#### Description
+
+The analyzer produces this diagnostic when there's more than one rest
+pattern in either a list or map pattern. A rest pattern will capture any
+values unmatched by other subpatterns, making subsequent rest patterns
+unnecessary because there's nothing left to capture.
+
+#### Example
+
+The following code produces this diagnostic because there are two rest
+patterns in the list pattern:
+
+{% prettify dart tag=pre+code %}
+void f(List<int> x) {

+ if (x case [0, ..., [!...!]]) {}
+}
+{% endprettify %}
+
+#### Common fixes
+
+Remove all but one of the rest patterns:
+
+{% prettify dart tag=pre+code %}
+void f(List<int> x) {

+ if (x case [0, ...]) {}
+}
+{% endprettify %}
+
### duplicate_shown_name

_Duplicate shown name._
@@ -4714,6 +5086,153 @@
var x = min(2, min(0, 1));
{% endprettify %}

+### duplicate_variable_pattern
+
+_The variable '{0}' is already defined in this pattern._
+
+#### Description
+
+The analyzer produces this diagnostic when a branch of a logical-and
+pattern declares a variable that is already declared in an earlier branch

+of the same pattern.
+
+#### Example
+
+The following code produces this diagnostic because the variable `a` is
+declared in both branches of the logical-and pattern:
+
+{% prettify dart tag=pre+code %}
+void f((int, int) r) {

+ if (r case (var a, 0) && (0, var [!a!])) {
+ print(a);
+ }
+}
+{% endprettify %}
+
+#### Common fixes
+
+If you need to capture the matched value in multiple branches, then change
+the names of the variables so that they are unique:
+
+{% prettify dart tag=pre+code %}
+void f((int, int) r) {

+ if (r case (var a, 0) && (0, var b)) {
+ print(a + b);
+ }
+}
+{% endprettify %}
+
+If you only need to capture the matched value on one branch, then remove
+the variable pattern from all but one branch:
+
+{% prettify dart tag=pre+code %}
+void f((int, int) r) {
+ if (r case (var a, 0) && (0, _)) {
+ print(a);
+ }
+}
+{% endprettify %}
+
+### empty_record_literal_with_comma
+
+_A record literal without fields can't have a trailing comma._
+
+#### Description
+
+The analyzer produces this diagnostic when a record literal that has no
+fields has a trailing comma. Empty record literals can't contain a comma.
+
+#### Example
+
+The following code produces this diagnostic because the empty record
+literal has a trailing comma:
+
+{% prettify dart tag=pre+code %}
+var r = ([!,!]);
+{% endprettify %}
+
+#### Common fixes
+
+If the record is intended to be empty, then remove the comma:
+
+{% prettify dart tag=pre+code %}
+var r = ();
+{% endprettify %}
+
+If the record is intended to have one or more fields, then add the
+expressions used to compute the values of those fields:
+
+{% prettify dart tag=pre+code %}
+var r = (3, 4);
+{% endprettify %}
+
+### empty_record_type_named_fields_list
+
+_The list of named fields in a record type can't be empty._
+
+#### Description
+
+The analyzer produces this diagnostic when a record type has an empty list

+of named fields.
+
+#### Example
+
+The following code produces this diagnostic because the record type has an
+empty list of named fields:
+
+{% prettify dart tag=pre+code %}
+void f((int, int, {[!}!]) r) {}
+{% endprettify %}
+
+#### Common fixes
+
+If the record is intended to have named fields, then add the types and
+names of the fields:
+
+{% prettify dart tag=pre+code %}
+void f((int, int, {int z}) r) {}
+{% endprettify %}
+
+If the record isn't intended to have named fields, then remove the curly
+braces:
+
+{% prettify dart tag=pre+code %}
+void f((int, int) r) {}
+{% endprettify %}
+
+### empty_record_type_with_comma
+
+_A record type without fields can't have a trailing comma._
+
+#### Description
+
+The analyzer produces this diagnostic when a record type that has no
+fields has a trailing comma. Empty record types can't contain a comma.
+
+#### Example
+
+The following code produces this diagnostic because the empty record type
+has a trailing comma:
+
+{% prettify dart tag=pre+code %}
+void f(([!,!]) r) {}
+{% endprettify %}
+
+#### Common fixes
+
+If the record type is intended to be empty, then remove the comma:
+
+{% prettify dart tag=pre+code %}
+void f(() r) {}
+{% endprettify %}
+
+If the record type is intended to have one or more fields, then add the
+types of those fields:
+
+{% prettify dart tag=pre+code %}
+void f((int, int) r) {}
+{% endprettify %}
+
### empty_struct

_The class '{0}' can't be empty because it's a subclass of '{1}'._
@@ -5110,6 +5629,77 @@
of which entry to remove might affect the order in which the keys and
values are returned by an iterator.

+### equal_keys_in_map_pattern
+
+_Two keys in a map pattern can't be equal._
+
+#### Description
+
+The analyzer produces this diagnostic when a map pattern contains more
+than one key with the same name. The same key can't be matched twice.
+
+#### Example
+
+The following code produces this diagnostic because the key `'a'` appears
+twice:
+
+{% prettify dart tag=pre+code %}
+void f(Map<String, int> x) {

+ if (x case {'a': 1, [!'a'!]: 2}) {}
+}
+{% endprettify %}
+
+#### Common fixes
+
+If you are trying to match two different keys, then change one of the keys
+in the pattern:
+
+{% prettify dart tag=pre+code %}
+void f(Map<String, int> x) {

+ if (x case {'a': 1, 'b': 2}) {}
+}
+{% endprettify %}
+
+If you are trying to match the same key, but allow any one of multiple
+patterns to match, the use a logical-or pattern:
+
+{% prettify dart tag=pre+code %}
+void f(Map<String, int> x) {
+ if (x case {'a': 1 || 2}) {}
+}
+{% endprettify %}
+
+### expected_one_list_pattern_type_arguments
+
+_List patterns require one type argument or none, but {0} found._
+
+#### Description
+
+The analyzer produces this diagnostic when a list pattern has more than
+one type argument. List patterns can have either zero type arguments or
+one type argument, but can't have more than one.
+
+#### Example
+
+The following code produces this diagnostic because the list pattern
+(`[0]`) has two type arguments:
+
+{% prettify dart tag=pre+code %}
+void f(Object x) {

+ if (x case [!<int, int>!][0]) {}
+}
+{% endprettify %}
+
+#### Common fixes
+
+Remove all but one of the type arguments:
+
+{% prettify dart tag=pre+code %}
+void f(Object x) {

+ if (x case <int>[0]) {}
+}
+{% endprettify %}
+
### expected_one_list_type_arguments

_List literals require one type argument or none, but {0} found._
@@ -5162,6 +5752,38 @@
var s = <int>{0, 1};
{% endprettify %}

+### expected_two_map_pattern_type_arguments
+
+_Map patterns require two type arguments or none, but {0} found._
+
+#### Description
+
+The analyzer produces this diagnostic when a map pattern has either one
+type argument or more than two type arguments. Map patterns can have
+either two type arguments or zero type arguments, but can't have any other
+number.
+
+#### Example
+
+The following code produces this diagnostic because the map pattern
+(`<int>{}`) has one type argument:
+
+{% prettify dart tag=pre+code %}
+void f(Object x) {

+ if (x case [!<int>!]{}) {}
+}
+{% endprettify %}
+
+#### Common fixes
+
+Add or remove type arguments until there are two, or none:
+
+{% prettify dart tag=pre+code %}
+void f(Object x) {

+ if (x case <int, int>{}) {}
+}
+{% endprettify %}
+
### expected_two_map_type_arguments

_Map literals require two type arguments or none, but {0} found._
@@ -5271,7 +5893,7 @@

#### Example

-Given a file named `part.dart` containing
+Given a file `part.dart` containing

{% prettify dart tag=pre+code %}
part of lib;
@@ -7409,12 +8031,12 @@
function is used to load the contents of the deferred library, and the
implicit function hides the explicit declaration in the deferred library.

-For more information, see the language tour's coverage of
-[deferred loading](https://dart.dev/guides/language/language-tour#lazily-loading-a-library).
+For more information, check out
+[Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).

#### Example

-Given a file (`a.dart`) that defines a function named `loadLibrary`:
+Given a file `a.dart` that defines a function named `loadLibrary`:

{% prettify dart tag=pre+code %}
void loadLibrary(Library library) {}
@@ -7502,7 +8124,7 @@

#### Example

-Given a file named `a.dart` that contains the following:
+Given a file `a.dart` that contains the following:

{% prettify dart tag=pre+code %}
// @dart = 2.9
@@ -7648,6 +8270,84 @@
the code in the [part file][] to be consistent with the new language
version.

+### inconsistent_pattern_variable_logical_or
+
+_The variable '{0}' has a different type and/or finality in this branch of the
+logical-or pattern._
+
+#### Description
+
+The analyzer produces this diagnostic when a pattern variable that is
+declared on all branches of a logical-or pattern doesn't have the same
+type on every branch. It is also produced when the variable has a
+different finality on different branches. A pattern variable declared on
+multiple branches of a logical-or pattern is required to have the same
+type and finality in each branch, so that the type and finality of the
+variable can be known in code that's guarded by the logical-or pattern.
+
+#### Examples
+
+The following code produces this diagnostic because the variable `a` is
+defined to be an `int` on one branch and a `double` on the other:
+
+{% prettify dart tag=pre+code %}
+void f(Object? x) {

+ if (x case (int a) || (double [!a!])) {
+ print(a);
+ }
+}
+{% endprettify %}
+
+The following code produces this diagnostic because the variable `a` is

+`final` in the first branch and isn't `final` in the second branch:
+
+{% prettify dart tag=pre+code %}
+void f(Object? x) {

+ if (x case (final int a) || (int [!a!])) {
+ print(a);
+ }
+}
+{% endprettify %}
+
+#### Common fixes
+
+If the finality of the variable is different, decide whether it should be

+`final` or not `final` and make the cases consistent:
+
+{% prettify dart tag=pre+code %}
+void f(Object? x) {

+ if (x case (int a) || (int a)) {
+ print(a);
+ }
+}
+{% endprettify %}
+
+If the type of the variable is different and the type isn't critical to
+the condition being matched, then ensure that the variable has the same
+type on both branches:
+
+{% prettify dart tag=pre+code %}
+void f(Object? x) {

+ if (x case (num a) || (num a)) {
+ print(a);
+ }
+}
+{% endprettify %}
+
+If the type of the variable is different and the type is critical to the
+condition being matched, then consider breaking the condition into
+multiple `if` statements or `case` clauses:
+
+{% prettify dart tag=pre+code %}
+void f(Object? x) {

+ if (x case int a) {
+ print(a);
+ } else if (x case double a) {
+ print(a);
+ }
+}
+{% endprettify %}
+
### initializer_for_non_existent_field

_'{0}' isn't a field in the enclosing class._
@@ -8209,8 +8909,8 @@
of an annotation. Annotations are evaluated at compile time, and values

from deferred libraries aren't available at compile time.

-For more information, see the language tour's coverage of
-[deferred loading](https://dart.dev/guides/language/language-tour#lazily-loading-a-library).
+For more information, check out
+[Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).

#### Example

@@ -8260,8 +8960,8 @@
are evaluated at compile time, and constants from deferred libraries aren't
available at compile time.

-For more information, see the language tour's coverage of
-[deferred loading](https://dart.dev/guides/language/language-tour#lazily-loading-a-library).
+For more information, check out
+[Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).

#### Example

@@ -8470,7 +9170,7 @@

#### Example

-Given a file named `a.dart` in the `src` directory that contains:
+Given a file `a.dart` in the `src` directory that contains:

{% prettify dart tag=pre+code %}
import 'package:meta/meta.dart';
@@ -8510,7 +9210,7 @@

#### Example

-Given a file named `a.dart` in the `src` directory that contains the
+Given a file `a.dart` in the `src` directory that contains the
following:

{% prettify dart tag=pre+code %}
@@ -8747,6 +9447,80 @@
}
{% endprettify %}

+### invalid_field_name
+
+_Record field names can't be a dollar sign followed by an integer when the
+integer is the index of a positional field._
+
+_Record field names can't be private._
+
+_Record field names can't be the same as a member from 'Object'._
+
+#### Description
+
+The analyzer produces this diagnostic when either a record literal or a
+record type annotation has a field whose name is invalid. The name is
+invalid if it is:
+- private (starts with `_`)
+- the same as one of the members defined on `Object`
+- the same as the name of a positional field (an exception is made if the
+ field is a positional field with the specified name)
+
+#### Examples
+
+The following code produces this diagnostic because the record literal has
+a field named `toString`, which is a method defined on `Object`:
+
+{% prettify dart tag=pre+code %}
+var r = (a: 1, [!toString!]: 4);
+{% endprettify %}
+
+The following code produces this diagnostic because the record type
+annotation has a field named `hashCode`, which is a getter defined on
+`Object`:
+
+{% prettify dart tag=pre+code %}
+void f(({int a, int [!hashCode!]}) r) {}
+{% endprettify %}
+
+The following code produces this diagnostic because the record literal has
+a private field named `_a`:
+
+{% prettify dart tag=pre+code %}
+var r = ([!_a!]: 1, b: 2);
+{% endprettify %}
+
+The following code produces this diagnostic because the record type
+annotation has a private field named `_a`:
+
+{% prettify dart tag=pre+code %}
+void f(({int [!_a!], int b}) r) {}
+{% endprettify %}
+
+The following code produces this diagnostic because the record literal has
+a field named `$1`, which is also the name of a different positional
+parameter:
+
+{% prettify dart tag=pre+code %}
+var r = (2, [!$1!]: 1);
+{% endprettify %}
+
+The following code produces this diagnostic because the record type
+annotation has a field named `$1`, which is also the name of a different
+positional parameter:
+
+{% prettify dart tag=pre+code %}
+void f((int, String, {int [!$1!]}) r) {}
+{% endprettify %}
+
+#### Common fixes
+
+Rename the field:
+
+{% prettify dart tag=pre+code %}
+var r = (a: 1, d: 4);
+{% endprettify %}
+
### invalid_field_type_in_struct

_Fields in struct classes can't have the type '{0}'. They can only be declared
@@ -9436,6 +10210,163 @@
}
{% endprettify %}

+### invalid_pattern_variable_in_shared_case_scope
+
+_The variable '{0}' doesn't have the same type and/or finality in all cases that
+share this body._
+
+_The variable '{0}' is available in some, but not all cases that share this
+body._
+
+_The variable '{0}' is not available because there is a label or 'default'
+case._
+
+#### Description
+
+The analyzer produces this diagnostic when multiple case clauses in a
+switch statement share a body, and at least one of them declares a
+variable that is referenced in the shared statements, but the variable is
+either not declared in all of the case clauses or it is declared in
+inconsistent ways.
+
+If the variable isn't declared in all of the case clauses, then it won't
+have a value if one of the clauses that doesn't declare the variable is
+the one that matches and executes the body. This includes the situation
+where one of the case clauses is the `default` clause.
+
+If the variable is declared in inconsistent ways, either being `final` in
+some cases and not `final` in others or having a different type in
+different cases, then the semantics of what the type or finality of the
+variable should be are not defined.
+
+#### Examples
+
+The following code produces this diagnostic because the variable `a` is
+only declared in one of the case clauses, and won't have a value if the
+second clause is the one that matched `x`:
+
+{% prettify dart tag=pre+code %}
+void f(Object? x) {

+ switch (x) {
+ case int a when a > 0:
+ case 0:
+ [!a!];
+ }
+}
+{% endprettify %}
+
+The following code produces this diagnostic because the variable `a` isn't
+declared in the `default` clause, and won't have a value if the body is
+executed because none of the other clauses matched `x`:
+
+{% prettify dart tag=pre+code %}
+void f(Object? x) {
+ switch (x) {

+ case int a when a > 0:
+ default:
+ [!a!];
+ }
+}
+{% endprettify %}
+
+The following code produces this diagnostic because the variable `a` won't
+have a value if the body is executed because a different group of cases
+caused control to continue at the label:
+
+{% prettify dart tag=pre+code %}
+void f(Object? x) {

+ switch (x) {
+ someLabel:
+ case int a when a > 0:
+ [!a!];
+    case int b when b < 0:

+ continue someLabel;
+ }
+}
+{% endprettify %}
+
+The following code produces this diagnostic because the variable `a`,
+while being assigned in all of the case clauses, doesn't have then same
+type associated with it in every clause:
+
+{% prettify dart tag=pre+code %}
+void f(Object? x) {
+ switch (x) {

+ case int a when a < 0:
+ case num a when a > 0:
+ [!a!];
+ }
+}
+{% endprettify %}
+
+The following code produces this diagnostic because the variable `a` is
+`final` in the first case clause and isn't `final` in the second case
+clause:
+
+{% prettify dart tag=pre+code %}
+void f(Object? x) {
+ switch (x) {
+ case final int a when a < 0:
+ case int a when a > 0:
+ [!a!];
+ }
+}
+{% endprettify %}
+
+#### Common fixes
+
+If the variable isn't declared in all of the cases, and you need to
+reference it in the statements, then declare it in the other cases:
+
+{% prettify dart tag=pre+code %}
+void f(Object? x) {
+ switch (x) {

+ case int a when a > 0:
+ case int a when a == 0:
+ a;
+ }
+}
+{% endprettify %}
+
+If the variable isn't declared in all of the cases, and you don't need to
+reference it in the statements, then remove the references to it and
+remove the declarations from the other cases:
+
+{% prettify dart tag=pre+code %}
+void f(int x) {

+ switch (x) {
+ case > 0:
+ case 0:
+ }
+}
+{% endprettify %}
+
+If the type of the variable is different, decide the type the variable
+should have and make the cases consistent:
+
+{% prettify dart tag=pre+code %}
+void f(Object? x) {

+ switch (x) {
+ case num a when a < 0:
+ case num a when a > 0:
+ a;
+ }
+}
+{% endprettify %}
+
+If the finality of the variable is different, decide whether it should be

+`final` or not `final` and make the cases consistent:
+
+{% prettify dart tag=pre+code %}
+void f(Object? x) {
+ switch (x) {
+ case final int a when a < 0:
+ case final int a when a > 0:
+ a;
+ }
+}
+{% endprettify %}
+
### invalid_reference_to_generative_enum_constructor

_Generative enum constructors can only be used as targets of redirection._
@@ -9877,6 +10808,83 @@
}
{% endprettify %}

+### invalid_use_of_type_outside_library
+
+_The class '{0}' can't be extended outside of its library because it's a final
+class._
+
+_The class '{0}' can't be extended outside of its library because it's an
+interface class._
+
+_The class '{0}' can't be extended, implemented, or mixed in outside of its
+library because it's a sealed class._
+
+_The class '{0}' can't be implemented outside of its library because it's a base
+class._
+
+_The class '{0}' can't be implemented outside of its library because it's a
+final class._
+
+_The mixin '{0}' can't be implemented outside of its library because it's a base
+mixin._
+
+_The mixin '{0}' can't be implemented outside of its library because it's a
+final mixin._
+
+_The mixin '{0}' can't be mixed in outside of its library because it's a sealed
+mixin._
+
+_The mixin '{0}' can't be mixed-in outside of its library because it's a final
+mixin._
+
+_The mixin '{0}' can't be mixed-in outside of its library because it's an
+interface mixin._
+
+#### Description
+
+The analyzer produces this diagnostic when an `extends`, `implements`,
+`with`, or `on` clause uses a class or mixin in a way that isn't allowed
+given the modifiers on that class or mixin's declaration.
+
+The message specifies how the declaration is being used and why it isn't
+allowed.
+
+#### Example
+
+Given a file `a.dart` that defines a base class `A`:
+
+{% prettify dart tag=pre+code %}
+base class A {}
+{% endprettify %}
+
+The following code produces this diagnostic because the class `B`
+implements the class `A`, but the `base` modifier prevents `A` from being
+implemented outside of the library where it's defined:
+
+{% prettify dart tag=pre+code %}
+import 'a.dart';
+
+final class B implements [!A!] {}
+{% endprettify %}
+
+#### Common fixes
+
+Use of this type is restricted outside of its declaring library. If a
+different, unrestricted type is available that can provide similar
+functionality, then replace the type:
+
+{% prettify dart tag=pre+code %}
+class B implements C {}
+class C {}
+{% endprettify %}
+
+If there isn't a different type that would be appropriate, then remove the
+type, and possibly the whole clause:
+
+{% prettify dart tag=pre+code %}
+class B {}
+{% endprettify %}
+
### invalid_use_of_visible_for_overriding_member

_The member '{0}' can only be used for overriding._
@@ -9890,7 +10898,7 @@

#### Example

-Given a file named `a.dart` containing the following declaration:
+Given a file `a.dart` containing the following declaration:

{% prettify dart tag=pre+code %}
import 'package:meta/meta.dart';
@@ -9931,7 +10939,7 @@

#### Example

-Given a file named `c.dart` that contains the following:
+Given a file `c.dart` that contains the following:

{% prettify dart tag=pre+code %}
import 'package:meta/meta.dart';
@@ -11114,6 +12122,74 @@
meta: ^1.0.2
```

+### missing_object_pattern_getter_name
+
+_The getter name is not specified explicitly, and the pattern is not a
+variable._
+
+#### Description
+
+The analyzer produces this diagnostic when, within an object pattern, the
+specification of a property and the pattern used to match the property's
+value doesn't have either:
+- a getter name before the colon
+- a variable pattern from which the getter name can be inferred
+
+#### Example
+
+The following code produces this diagnostic because there is no getter
+name before the colon and no variable pattern after the colon in the
+object pattern (`C(:0)`):
+
+{% prettify dart tag=pre+code %}
+abstract class C {

+ int get f;
+}
+
+void f(C c) {

+ switch (c) {
+ case C([!:0!]):
+ break;
+ }
+}
+{% endprettify %}
+
+#### Common fixes
+
+If you need to use the actual value of the property within the pattern's
+scope, then add a variable pattern where the name of the variable is the
+same as the name of the property being matched:
+
+{% prettify dart tag=pre+code %}
+abstract class C {

+ int get f;
+}
+
+void f(C c) {
+ switch (c) {
+ case C(:var f) when f == 0:
+ print(f);
+ }
+}
+{% endprettify %}
+
+If you don't need to use the actual value of the property within the
+pattern's scope, then add the name of the property being matched before
+the colon:
+
+{% prettify dart tag=pre+code %}
+abstract class C {

+ int get f;
+}
+
+void f(C c) {

+ switch (c) {
+ case C(f: 0):
+ break;
+ }
+}
+{% endprettify %}
+
### missing_override_of_must_be_overridden

_Missing concrete implementation of '{0}'._
@@ -11314,6 +12390,70 @@
}
{% endprettify %}

+### missing_variable_pattern
+
+_Variable pattern '{0}' is missing in this branch of the logical-or pattern._
+
+#### Description
+
+The analyzer produces this diagnostic when one branch of a logical-or
+pattern doesn't declare a variable that is declared on the other branch of

+the same pattern.
+
+#### Example
+
+The following code produces this diagnostic because the right-hand side of
+the logical-or pattern doesn't declare the variable `a`:
+
+{% prettify dart tag=pre+code %}
+void f((int, int) r) {

+ if (r case (var a, 0) || [!(0, _)!]) {
+ print(a);
+ }
+}
+{% endprettify %}
+
+#### Common fixes
+
+If the variable needs to be referenced in the controlled statements, then
+add a declaration of the variable to every branch of the logical-or
+pattern:
+
+{% prettify dart tag=pre+code %}
+void f((int, int) r) {

+ if (r case (var a, 0) || (0, var a)) {
+ print(a);
+ }
+}
+{% endprettify %}
+
+If the variable doesn't need to be referenced in the controlled
+statements, then remove the declaration of the variable from every branch
+of the logical-or pattern:
+
+{% prettify dart tag=pre+code %}
+void f((int, int) r) {

+ if (r case (_, 0) || (0, _)) {
+    print('found a zero');
+ }
+}
+{% endprettify %}
+
+If the variable needs to be referenced if one branch of the pattern
+matches but not when the other matches, then break the pattern into two
+pieces:
+
+{% prettify dart tag=pre+code %}
+void f((int, int) r) {
+ switch (r) {
+ case (var a, 0):
+ print(a);
+ case (0, _):
+ print('found a zero');
+ }
+}
+{% endprettify %}
+
### mixin_application_concrete_super_invoked_member_type

_The super-invoked member '{0}' has the type '{1}', and the concrete member in
@@ -12496,12 +13636,12 @@
constants referenced in case clauses need to be available at compile time,
and constants from deferred libraries aren't available at compile time.

-For more information, see the language tour's coverage of
-[deferred loading](https://dart.dev/guides/language/language-tour#lazily-loading-a-library).
+For more information, check out
+[Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).

#### Example

-Given a file (`a.dart`) that defines the constant `zero`:
+Given a file `a.dart` that defines the constant `zero`:

{% prettify dart tag=pre+code %}
const zero = 0;
@@ -12620,12 +13760,12 @@
Default values need to be available at compile time, and constants from

deferred libraries aren't available at compile time.

-For more information, see the language tour's coverage of
-[deferred loading](https://dart.dev/guides/language/language-tour#lazily-loading-a-library).
+For more information, check out
+[Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).

#### Example

-Given a file (`a.dart`) that defines the constant `zero`:
+Given a file `a.dart` that defines the constant `zero`:

{% prettify dart tag=pre+code %}
const zero = 0;
@@ -12781,6 +13921,44 @@
var m = {a: 0};
{% endprettify %}

+### non_constant_map_pattern_key
+
+_Key expressions in map patterns must be constants._
+
+#### Description
+
+The analyzer produces this diagnostic when a key in a map pattern isn't a
+constant expression.
+
+#### Example
+
+The following code produces this diagnostic because the key `A()` isn't a
+constant:
+
+{% prettify dart tag=pre+code %}
+void f(Object x) {
+ if (x case {[!A()!]: 0}) {}
+}
+
+class A {
+ const A();
+}
+{% endprettify %}
+
+#### Common fixes
+
+Use a constant for the key:
+
+{% prettify dart tag=pre+code %}
+void f(Object x) {
+ if (x case {const A(): 0}) {}
+}
+
+class A {
+ const A();
+}
+{% endprettify %}
+
### non_constant_map_value

_The values in a const map literal must be constant._
@@ -12816,6 +13994,40 @@
var m = {0: a};
{% endprettify %}

+### non_constant_relational_pattern_expression
+
+_The relational pattern expression must be a constant._
+
+#### Description
+
+The analyzer produces this diagnostic when the value in a relational
+pattern expression isn't a constant expression.
+
+#### Example
+
+The following code produces this diagnostic because the operand of the `>`
+operator, `a`, isn't a constant:
+
+{% prettify dart tag=pre+code %}
+final a = 0;
+
+void f(int x) {

+ if (x case > [!a!]) {}
+}
+{% endprettify %}
+
+#### Common fixes
+
+Replace the value with a constant expression:
+
+{% prettify dart tag=pre+code %}
+const a = 0;
+
+void f(int x) {

+ if (x case > a) {}
+}
+{% endprettify %}
+
### non_constant_set_element

_The values in a const set literal must be constants._
@@ -12976,6 +14188,71 @@
}
{% endprettify %}

+### non_exhaustive_switch
+
+_The type '{0}' is not exhaustively matched by the switch cases._
+
+#### Description
+
+The analyzer produces this diagnostic when a `switch` statement switching
+over an exhaustive type is missing a case for one or more of the possible
+values that could flow through it.
+
+#### Example
+
+The following code produces this diagnostic because the switch statement
+doesn't have a case for the value `E.three`, and `E` is an exhaustive
+type:
+
+{% prettify dart tag=pre+code %}
+enum E { one, two, three }
+
+void f(E e) {

+ [!switch!] (e) {
+ case E.one:
+ case E.two:
+ }
+}
+{% endprettify %}
+
+#### Common fixes
+
+Add a case for each of the constants that aren't currently being matched:
+
+{% prettify dart tag=pre+code %}
+enum E { one, two, three }
+
+void f(E e) {

+ switch (e) {
+ case E.one:
+ case E.two:
+ break;
+ case E.three:
+ }
+}
+{% endprettify %}
+
+If the missing values don't need to be matched, then add a `default`
+clause (or a wildcard pattern in a `switch` expression):
+
+{% prettify dart tag=pre+code %}
+enum E { one, two, three }
+
+void f(E e) {

+ switch (e) {
+ case E.one:
+ case E.two:
+ break;
+    default:
+ }
+}
+{% endprettify %}
+
+But be aware that adding a `default` clause or wildcard pattern will cause
+any future values of the exhaustive type to also be handled, so you will
+have lost the ability for the compiler to warn you if the `switch` needs
+to be updated.
+
### non_final_field_in_enum

_Enums can only declare final fields._
@@ -14482,7 +15759,7 @@

#### Example

-Given a file named `part.dart` containing
+Given a file `part.dart` containing

{% prettify dart tag=pre+code %}
part of 'library.dart';
@@ -14516,7 +15793,7 @@

#### Example

-Given a file (`a.dart`) containing:
+Given a file `a.dart` containing:

{% prettify dart tag=pre+code %}
class A {}
@@ -14649,7 +15926,7 @@

#### Example

-Assuming that the directory `local_package` doesn't contain a file named
+Assuming that the directory `local_package` doesn't contain a file
`pubspec.yaml`, the following code produces this diagnostic because it's
listed as the path of a package:

@@ -14671,6 +15948,224 @@

If the path is wrong, then replace it with the correct path.

+### pattern_assignment_not_local_variable
+
+_Only local variables can be assigned in pattern assignments._
+
+#### Description
+
+The analyzer produces this diagnostic when a pattern assignment assigns a
+value to anything other than a local variable. Patterns can't assign to

+fields or top-level variables.
+
+#### Example
+
+If the code is cleaner when destructuring with a pattern, then rewrite the
+code to assign the value to a local variable in a pattern declaration,
+assigning the non-local variable separately:
+
+{% prettify dart tag=pre+code %}
+class C {

+ var x = 0;
+
+ void f((int, int) r) {
+ ([!x!], _) = r;
+ }
+}
+{% endprettify %}
+
+#### Common fixes
+
+If the code is cleaner when using a pattern assignment, then rewrite the
+code to assign the value to a local variable, assigning the non-local
+variable separately:
+
+{% prettify dart tag=pre+code %}
+class C {

+ var x = 0;
+
+ void f((int, int) r) {
+    var (a, _) = r;
+ x = a;
+ }
+}
+{% endprettify %}
+
+If the code is cleaner without using a pattern assignment, then rewrite
+the code to not use a pattern assignment:
+
+{% prettify dart tag=pre+code %}
+class C {

+ var x = 0;
+
+ void f((int, int) r) {
+ x = r.$1;
+ }
+}
+{% endprettify %}
+
+### pattern_constant_from_deferred_library
+
+_Constant values from a deferred library can't be used in patterns._
+
+#### Description
+
+The analyzer produces this diagnostic when a pattern contains a value
+declared in a different library, and that library is imported using a
+deferred import. Constants are evaluated at compile time, but values from
+deferred libraries aren't available at compile time.
+
+For more information, check out
+[Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).
+
+#### Example
+
+Given a file `a.dart` that defines the constant `zero`:
+
+{% prettify dart tag=pre+code %}
+const zero = 0;
+{% endprettify %}
+
+The following code produces this diagnostic because the constant pattern
+`a.zero` is imported using a deferred import:
+
+{% prettify dart tag=pre+code %}
+import 'a.dart' deferred as a;
+
+void f(int x) {

+ switch (x) {
+ case a.[!zero!]:
+ // ...
+ break;
+ }
+}
+{% endprettify %}
+
+#### Common fixes
+
+If you need to reference the constant from the imported library, then
+remove the `deferred` keyword:
+
+{% prettify dart tag=pre+code %}
+import 'a.dart' as a;
+
+void f(int x) {

+ switch (x) {
+ case a.zero:
+ // ...
+ break;
+ }
+}
+{% endprettify %}
+
+If you need to reference the constant from the imported library and also
+need the imported library to be deferred, then rewrite the switch
+statement as a sequence of `if` statements:
+
+{% prettify dart tag=pre+code %}
+import 'a.dart' deferred as a;
+
+void f(int x) {

+ if (x == a.zero) {
+ // ...
+ }
+}
+{% endprettify %}
+
+If you don't need to reference the constant, then replace the case
+expression:
+
+{% prettify dart tag=pre+code %}
+void f(int x) {

+ switch (x) {
+ case 0:
+ // ...
+ break;
+ }
+}
+{% endprettify %}
+
+### pattern_type_mismatch_in_irrefutable_context
+
+_The matched value of type '{0}' isn't assignable to the required type '{1}'._
+
+#### Description
+
+The analyzer produces this diagnostic when the type of the value on the
+right-hand side of a pattern assignment or pattern declaration doesn't
+match the type required by the pattern being used to match it.
+
+#### Example
+
+The following code produces this diagnostic because `x` might not be a

+`String` and hence might not match the object pattern:
+
+{% prettify dart tag=pre+code %}
+void f(Object x) {

+ var [!String(length: a)!] = x;
+ print(a);
+}
+{% endprettify %}
+
+#### Common fixes
+
+Change the code so that the type of the expression on the right-hand side
+matches the type required by the pattern:
+
+{% prettify dart tag=pre+code %}
+void f(String x) {

+ var String(length: a) = x;
+ print(a);
+}
+{% endprettify %}
+
+### pattern_variable_assignment_inside_guard
+
+_Pattern variables can't be assigned inside the guard of the enclosing guarded
+pattern._
+
+#### Description
+
+The analyzer produces this diagnostic when a pattern variable is assigned
+a value inside a guard (`when`) clause.
+
+#### Example
+
+The following code produces this diagnostic because the variable `a` is
+assigned a value inside the guard clause:
+
+{% prettify dart tag=pre+code %}
+void f(int x) {

+ if (x case var a when ([!a!] = 1) > 0) {
+ print(a);
+ }
+}
+{% endprettify %}
+
+#### Common fixes
+
+If there's a value you need to capture, then assign it to a different
+variable:
+
+{% prettify dart tag=pre+code %}
+void f(int x) {
+ var b;
+ if (x case var a when (b = 1) > 0) {

+ print(a + b);
+ }
+}
+{% endprettify %}
+
+If there isn't a value you need to capture, then remove the assignment:
+
+{% prettify dart tag=pre+code %}
+void f(int x) {

+ if (x case var a when 1 > 0) {
+ print(a);
+ }
+}
+{% endprettify %}
+
### positional_super_formal_parameter_with_positional_argument

_Positional super parameters can't be used when the super constructor invocation
@@ -14878,7 +16373,7 @@

#### Example

-Given a file named `a.dart` containing the following code:
+Given a file `a.dart` containing the following code:

{% prettify dart tag=pre+code %}
mixin A {
@@ -14955,7 +16450,7 @@

#### Example

-Given a file named `a.dart` that contains the following:
+Given a file `a.dart` that contains the following:

{% prettify dart tag=pre+code %}
class A {
@@ -15028,6 +16523,66 @@
}
{% endprettify %}

+### record_literal_one_positional_no_trailing_comma
+
+_A record literal with exactly one positional field requires a trailing comma._
+
+#### Description
+
+The analyzer produces this diagnostic when a record literal with a single
+positional field doesn't have a trailing comma after the field.
+
+In some locations a record literal with a single positional field could
+also be a parenthesized expression. A trailing comma is required to
+disambiguate these two valid interpretations.
+
+#### Example
+
+The following code produces this diagnostic because the record literal has
+one positional field but doesn't have a trailing comma:
+
+{% prettify dart tag=pre+code %}
+var r = const (1[!)!];
+{% endprettify %}
+
+#### Common fixes
+
+Add a trailing comma:
+
+{% prettify dart tag=pre+code %}
+var r = const (1,);
+{% endprettify %}
+
+### record_type_one_positional_no_trailing_comma
+
+_A record type with exactly one positional field requires a trailing comma._
+
+#### Description
+
+The analyzer produces this diagnostic when a record type annotation with a
+single positional field doesn't have a trailing comma after the field.
+
+In some locations a record type with a single positional field could also
+be a parenthesized expression. A trailing comma is required to
+disambiguate these two valid interpretations.
+
+#### Example
+
+The following code produces this diagnostic because the record type has
+one positional field, but doesn't have a trailing comma:
+
+{% prettify dart tag=pre+code %}
+void f((int[!)!] r) {}
+{% endprettify %}
+
+#### Common fixes
+
+Add a trailing comma:
+
+{% prettify dart tag=pre+code %}
+void f((int,) r) {}
+{% endprettify %}
+
### recursive_compile_time_constant

_The compile-time constant expression depends on itself._
@@ -15656,6 +17211,184 @@
}
{% endprettify %}

+### refutable_pattern_in_irrefutable_context
+
+_Refutable patterns can't be used in an irrefutable context._
+
+#### Description
+
+The analyzer produces this diagnostic when a [refutable pattern][] is used
+in a context where only an [irrefutable pattern][] is allowed.
+
+The refutable patterns that are disallowed are:
+- logical-or
+- relational
+- null-check
+- constant
+
+The contexts that are checked are:
+- pattern-based variable declarations
+- pattern-based for loops
+- assignments with a pattern on the left-hand side
+
+#### Example
+
+The following code produces this diagnostic because the null-check
+pattern, which is a refutable pattern, is in a pattern-based variable
+declaration, which doesn't allow refutable patterns:
+
+{% prettify dart tag=pre+code %}
+void f(int? x) {

+ var ([!_?!]) = x;
+}
+{% endprettify %}
+
+#### Common fixes
+
+Rewrite the code to not use a refutable pattern in an irrefutable context.
+
+### relational_pattern_operator_return_type_not_assignable_to_bool
+
+_The return type of operators used in relational patterns must be assignable to
+'bool'._
+
+#### Description
+
+The analyzer produces this diagnostic when a relational pattern references
+an operator that doesn't produce a value of type `bool`.
+
+#### Example
+
+The following code produces this diagnostic because the operator `>`, used
+in the relational pattern `> c2`, returns a value of type `int` rather
+than a `bool`:
+
+{% prettify dart tag=pre+code %}
+class C {
+ const C();
+
+ int operator >(C c) => 3;
+
+ bool operator <(C c) => false;
+}
+
+const C c2 = C();
+
+void f(C c1) {
+ if (c1 case [!>!] c2) {}
+}
+{% endprettify %}
+
+#### Common fixes
+
+If there's a different operator that should be used, then change the
+operator:
+
+{% prettify dart tag=pre+code %}
+class C {
+ const C();
+
+ int operator >(C c) => 3;
+
+ bool operator <(C c) => false;
+}
+
+const C c2 = C();
+
+void f(C c1) {

+ if (c1 case < c2) {}
+}
+{% endprettify %}
+
+If the operator is expected to return `bool`, then update the declaration
+of the operator:
+
+{% prettify dart tag=pre+code %}
+class C {
+ const C();
+
+ bool operator >(C c) => true;
+
+ bool operator <(C c) => false;
+}
+
+const C c2 = C();
+
+void f(C c1) {

+ if (c1 case > c2) {}
+}
+{% endprettify %}
+
+### rest_element_not_last_in_map_pattern
+
+_A rest element in a map pattern must be the last element._
+
+#### Description
+
+The analyzer produces this diagnostic when a map pattern contains entries
+after a rest pattern. The rest pattern will match map entries whose keys
+aren't matched by any of the entries in the pattern. To make those
+semantics clear, the language requires that the rest pattern be the last

+entry in the list.
+
+#### Example
+
+The following code produces this diagnostic because the rest pattern is
+followed by another map pattern entry (`0: _`):
+
+{% prettify dart tag=pre+code %}
+void f(Map<int, String> x) {

+ if (x case {[!...!], 0: _}) {}
+}
+{% endprettify %}
+
+#### Common fixes
+
+Move the rest pattern to the end of the map pattern:
+
+{% prettify dart tag=pre+code %}
+void f(Map<int, String> x) {

+ if (x case {0: _, ...}) {}
+}
+{% endprettify %}
+
+### rest_element_with_subpattern_in_map_pattern
+
+_A rest element in a map pattern can't have a subpattern._
+
+#### Description
+
+The analyzer produces this diagnostic when a rest pattern in a map pattern
+has a subpattern. In Dart, there is no notion of a subset of a map, so
+there isn't anything to match against the subpattern.
+
+#### Example
+
+The following code produces this diagnostic because the rest pattern has a
+subpattern:
+
+{% prettify dart tag=pre+code %}
+void f(Map<String, int> m) {

+ switch (m) {
+ case {'a': var a, ... [!> 0!]}:
+ print(a);
+ }
+}
+{% endprettify %}
+
+#### Common fixes
+
+Remove the subpattern:
+
+{% prettify dart tag=pre+code %}
+void f(Map<String, int> m) {

+ switch (m) {
+ case {'a': var a, ...}:
+ print(a);
+ }
+}
+{% endprettify %}
+
### rethrow_outside_catch

_A rethrow must be inside of a catch clause._
@@ -16760,6 +18493,40 @@
int f(C c) => c.b;
{% endprettify %}

+### subtype_of_base_or_final_is_not_base_final_or_sealed
+
+_The type '{0}' must be 'base', 'final' or 'sealed' because the supertype '{1}'
+is 'base'._
+
+_The type '{0}' must be 'base', 'final' or 'sealed' because the supertype '{1}'
+is 'final'._
+
+#### Description
+
+The analyzer produces this diagnostic when a class or mixin has a direct
+or indirect supertype that is either `base` or `final`, but the class or
+mixin itself isn't marked either `base`, `final`, or `sealed`.
+
+#### Example
+
+The following code produces this diagnostic because the class `B` is a
+subtype of `A`, and `A` is a `base` class, but `B` is neither `base`,

+`final` or `sealed`:
+
+{% prettify dart tag=pre+code %}
+base class A {}
+class [!B!] extends A {}
+{% endprettify %}
+
+#### Common fixes
+
+Add either `base`, `final` or `sealed` to the class or mixin declaration:
+
+{% prettify dart tag=pre+code %}
+base class A {}
+final class B extends A {}
+{% endprettify %}
+
### subtype_of_deferred_class

_Classes and mixins can't implement deferred classes._
@@ -16776,12 +18543,12 @@
classes from deferred libraries aren't compiled until the library is
loaded.

-For more information, see the language tour's coverage of
-[deferred loading](https://dart.dev/guides/language/language-tour#lazily-loading-a-library).
+For more information, check out
+[Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).

#### Example

-Given a file (`a.dart`) that defines the class `A`:
+Given a file `a.dart` that defines the class `A`:

{% prettify dart tag=pre+code %}
class A {}
@@ -17662,7 +19429,7 @@

#### Common fixes

-Add an explicit null check to the expression:
+Add an explicit null-check to the expression:

{% prettify dart tag=pre+code %}
void f(String? s) {
@@ -17756,8 +19523,8 @@
is a type declared in a library that is imported using a deferred import.
These types are required to be available at compile time, but aren't.

-For more information, see the language tour's coverage of
-[deferred loading](https://dart.dev/guides/language/language-tour#lazily-loading-a-library).
+For more information, check out
+[Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).

#### Example

@@ -19332,13 +21099,13 @@

#### Example

-Given a file named `a.dart` that contains the following:
+Given a file `a.dart` that contains the following:

{% prettify dart tag=pre+code %}
class A {}
{% endprettify %}

-And, given a file named `b.dart` that contains the following:
+And, given a file `b.dart` that contains the following:

{% prettify dart tag=pre+code %}
export 'a.dart';
@@ -19479,6 +21246,68 @@
class B extends A {}
{% endprettify %}

+### unnecessary_null_assert_pattern
+
+_The null-assert pattern will have no effect because the matched type isn't
+nullable._
+
+#### Description
+
+The analyzer produces this diagnostic when a null-assert pattern is used
+to match a value that isn't nullable.
+
+#### Example
+
+The following code produces this diagnostic because the variable `x` isn't
+nullable:
+
+{% prettify dart tag=pre+code %}
+void f(int x) {

+ if (x case var a[!!!] when a > 0) {}
+}
+{% endprettify %}
+
+#### Common fixes
+
+Remove the null-assert pattern:
+
+{% prettify dart tag=pre+code %}
+void f(int x) {
+ if (x case var a when a > 0) {}
+}
+{% endprettify %}
+
+### unnecessary_null_check_pattern
+
+_The null-check pattern will have no effect because the matched type isn't
+nullable._
+
+#### Description
+
+The analyzer produces this diagnostic when a null-check pattern is used to
+match a value that isn't nullable.
+
+#### Example
+
+The following code produces this diagnostic because the value `x` isn't
+nullable:
+
+{% prettify dart tag=pre+code %}
+void f(int x) {

+ if (x case var a[!?!] when a > 0) {}
+}
+{% endprettify %}
+
+#### Common fixes
+
+Remove the null-check pattern:
+
+{% prettify dart tag=pre+code %}
+void f(int x) {
+ if (x case var a when a > 0) {}
+}
+{% endprettify %}
+
### unnecessary_null_comparison

_The operand can't be null, so the condition is always 'false'._
@@ -19564,6 +21393,47 @@
dynamic x;
{% endprettify %}

+### unnecessary_set_literal
+
+_Braces unnecessarily wrap this expression in a set literal._
+
+#### Description
+
+The analyzer produces this diagnostic when a function that has a return
+type of `void`, `Future<void>`, or `FutureOr<void>` uses an expression
+function body (`=>`) and the returned value is a literal set containing a
+single element.
+
+Although the language allows it, returning a value from a `void` function
+isn't useful because it can't be used at the call site. In this particular
+case the return is often due to a misunderstanding about the syntax. The
+braces aren't necessary and can be removed.
+
+#### Example
+
+The following code produces this diagnostic because the closure being
+passed to `g` has a return type of `void`, but is returning a set:
+
+{% prettify dart tag=pre+code %}
+void f() {

+ g(() => [!{1}!]);
+}
+
+void g(void Function() p) {}
+{% endprettify %}
+
+#### Common fixes
+
+Remove the braces from around the value:
+
+{% prettify dart tag=pre+code %}
+void f() {

+ g(() => 1);
+}
+
+void g(void Function() p) {}
+{% endprettify %}
+
### unnecessary_type_check

_Unnecessary type check; the result is always 'false'._
@@ -19704,6 +21574,47 @@
}
{% endprettify %}

+### unreachable_switch_case
+
+_This case is covered by the previous cases._
+
+#### Description
+
+The analyzer produces this diagnostic when a `case` clause in a `switch`
+statement doesn't match anything because all of the matchable values are
+matched by an earlier `case` clause.
+
+#### Example
+
+The following code produces this diagnostic because the value `1` was
+matched in the preceeding case:
+
+{% prettify dart tag=pre+code %}
+void f(int x) {
+ switch (x) {
+ case 1:
+ print('one');
+ [!case!] 1:
+ print('two');
+ }
+}
+{% endprettify %}
+
+#### Common fixes
+
+Change one or both of the conflicting cases to match different values:
+
+{% prettify dart tag=pre+code %}
+void f(int x) {
+ switch (x) {
+ case 1:
+ print('one');
+ case 2:
+ print('two');
+ }
+}
+{% endprettify %}
+
### unused_catch_clause

_The exception variable '{0}' isn't used, so the 'catch' clause can be removed._
@@ -20260,6 +22171,39 @@
}
{% endprettify %}

+### variable_pattern_keyword_in_declaration_context
+
+_Variable patterns in declaration context can't specify 'var' or 'final'
+keyword._
+
+#### Description
+
+The analyzer produces this diagnostic when a variable pattern is used
+within a declaration context.
+
+#### Example
+
+The following code produces this diagnostic because the variable patterns
+in the record pattern are in a declaration context:
+
+{% prettify dart tag=pre+code %}
+void f((int, int) r) {
+ var ([!var!] x, y) = r;

+ print(x + y);
+}
+{% endprettify %}
+
+#### Common fixes
+
+Remove the `var` or `final` keyword(s) within the variable pattern:
+
+{% prettify dart tag=pre+code %}
+void f((int, int) r) {

+ var (x, y) = r;
+ print(x + y);
+}
+{% endprettify %}
+
### variable_type_mismatch

_A value of type '{0}' can't be assigned to a const variable of type '{1}'._
diff --git a/pkg/analyzer/tool/diagnostics/generate.dart b/pkg/analyzer/tool/diagnostics/generate.dart
index e8c353a..8988d02 100644
--- a/pkg/analyzer/tool/diagnostics/generate.dart
+++ b/pkg/analyzer/tool/diagnostics/generate.dart
@@ -196,6 +196,7 @@

[ffi]: https://dart.dev/guides/libraries/c-interop
[IEEE 754]: https://en.wikipedia.org/wiki/IEEE_754
+[irrefutable pattern]: https://dart.dev/resources/glossary#irrefutable-pattern
[meta-doNotStore]: https://pub.dev/documentation/meta/latest/meta/doNotStore-constant.html
[meta-factory]: https://pub.dev/documentation/meta/latest/meta/factory-constant.html
[meta-immutable]: https://pub.dev/documentation/meta/latest/meta/immutable-constant.html
@@ -208,6 +209,7 @@
[meta-UseResult]: https://pub.dev/documentation/meta/latest/meta/UseResult-class.html
[meta-visibleForOverriding]: https://pub.dev/documentation/meta/latest/meta/visibleForOverriding-constant.html
[meta-visibleForTesting]: https://pub.dev/documentation/meta/latest/meta/visibleForTesting-constant.html
+[refutable pattern]: https://dart.dev/resources/glossary#refutable-pattern
''');
var errorCodes = infoByName.keys.toList();
errorCodes.sort();
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 550babe..65c265b 100644

To view, visit change 286524. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: sdk
Gerrit-Branch: main
Gerrit-Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
Gerrit-Change-Number: 286524
Gerrit-PatchSet: 6
Gerrit-Owner: Brian Wilkerson <brianwi...@google.com>
Gerrit-Reviewer: Brian Wilkerson <brianwi...@google.com>
Gerrit-Reviewer: Johnni Winther <johnni...@google.com>
Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
Gerrit-Reviewer: Marya Belanger <mbel...@google.com>
Gerrit-Attention: Johnni Winther <johnni...@google.com>
Gerrit-MessageType: newchange

CBuild (Gerrit)

unread,
Mar 17, 2023, 7:08:53 PM3/17/23
to Brian Wilkerson, dart-analys...@google.com, dart-fe-te...@google.com, dart-uxr...@google.com, rev...@dartlang.org, Johnni Winther, Commit Queue, Marya Belanger, Konstantin Shcheglov

Attention is currently required from: Johnni Winther.

go/dart-cbuild result: SUCCESS

Details: https://goto.google.com/dart-cbuild/find/f7b35e871268ed8fecccbaf6d47a141eb20dd3b9

View Change

    To view, visit change 286524. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: sdk
    Gerrit-Branch: main
    Gerrit-Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
    Gerrit-Change-Number: 286524
    Gerrit-PatchSet: 6
    Gerrit-Owner: Brian Wilkerson <brianwi...@google.com>
    Gerrit-Reviewer: Brian Wilkerson <brianwi...@google.com>
    Gerrit-Reviewer: Johnni Winther <johnni...@google.com>
    Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
    Gerrit-Reviewer: Marya Belanger <mbel...@google.com>
    Gerrit-Attention: Johnni Winther <johnni...@google.com>
    Gerrit-Comment-Date: Fri, 17 Mar 2023 23:08:50 +0000
    Gerrit-HasComments: No
    Gerrit-Has-Labels: No
    Gerrit-MessageType: comment

    Johnni Winther (Gerrit)

    unread,
    Mar 17, 2023, 7:10:34 PM3/17/23
    to Brian Wilkerson, dart-analys...@google.com, dart-fe-te...@google.com, dart-uxr...@google.com, rev...@dartlang.org, CBuild, Commit Queue, Marya Belanger, Konstantin Shcheglov

    Attention is currently required from: Brian Wilkerson.

    Patch set 6:Code-Review +1

    View Change

      To view, visit change 286524. To unsubscribe, or for help writing mail filters, visit settings.

      Gerrit-Project: sdk
      Gerrit-Branch: main
      Gerrit-Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
      Gerrit-Change-Number: 286524
      Gerrit-PatchSet: 6
      Gerrit-Owner: Brian Wilkerson <brianwi...@google.com>
      Gerrit-Reviewer: Brian Wilkerson <brianwi...@google.com>
      Gerrit-Reviewer: Johnni Winther <johnni...@google.com>
      Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
      Gerrit-Reviewer: Marya Belanger <mbel...@google.com>
      Gerrit-Attention: Brian Wilkerson <brianwi...@google.com>
      Gerrit-Comment-Date: Fri, 17 Mar 2023 23:10:29 +0000
      Gerrit-HasComments: No
      Gerrit-Has-Labels: Yes
      Gerrit-MessageType: comment

      Johnni Winther (Gerrit)

      unread,
      Mar 17, 2023, 7:10:41 PM3/17/23
      to Brian Wilkerson, dart-analys...@google.com, dart-fe-te...@google.com, dart-uxr...@google.com, rev...@dartlang.org, CBuild, Commit Queue, Marya Belanger, Konstantin Shcheglov

      Attention is currently required from: Brian Wilkerson, Konstantin Shcheglov.

      View Change

      1 comment:

      • File pkg/analyzer/messages.yaml:

        • Patch Set #1, Line 20152: Example

          I tried this with full implementation, and it does not work there. […]

          The exhaustiveness check for unreachable switch cases is not concerned with cases that cannot be reached from the scrutinee type. It creates a model of each case based on the assumption that it is within values of the scrutinee type. We could (should?) extend the creation of this model to detect when model for a single case is unreachable wrt. the scrutinee type.

          What it does instead is to check that a case is reachable after the previous cases have been matched. For instance

              void f(int x) {
          switch (x) {
          case int y:
          print(y);
          case double z:
          print(z);
          case 5:
          print(5);
          }
          }

          Here it will report that `case 5` is unreachable.

      To view, visit change 286524. To unsubscribe, or for help writing mail filters, visit settings.

      Gerrit-Project: sdk
      Gerrit-Branch: main
      Gerrit-Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
      Gerrit-Change-Number: 286524
      Gerrit-PatchSet: 6
      Gerrit-Owner: Brian Wilkerson <brianwi...@google.com>
      Gerrit-Reviewer: Brian Wilkerson <brianwi...@google.com>
      Gerrit-Reviewer: Johnni Winther <johnni...@google.com>
      Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
      Gerrit-Reviewer: Marya Belanger <mbel...@google.com>
      Gerrit-Attention: Konstantin Shcheglov <sche...@google.com>
      Gerrit-Attention: Brian Wilkerson <brianwi...@google.com>
      Gerrit-Comment-Date: Fri, 17 Mar 2023 23:10:36 +0000
      Gerrit-HasComments: Yes
      Gerrit-Has-Labels: No
      Comment-In-Reply-To: Konstantin Shcheglov <sche...@google.com>

      Brian Wilkerson (Gerrit)

      unread,
      Mar 20, 2023, 4:19:32 PM3/20/23
      to Brian Wilkerson, dart-analys...@google.com, dart-fe-te...@google.com, dart-uxr...@google.com, rev...@dartlang.org, Johnni Winther, CBuild, Commit Queue, Marya Belanger, Konstantin Shcheglov

      Attention is currently required from: Brian Wilkerson, Konstantin Shcheglov.

      Patch set 7:Commit-Queue +2

      View Change

        To view, visit change 286524. To unsubscribe, or for help writing mail filters, visit settings.

        Gerrit-Project: sdk
        Gerrit-Branch: main
        Gerrit-Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
        Gerrit-Change-Number: 286524
        Gerrit-PatchSet: 7
        Gerrit-Owner: Brian Wilkerson <brianwi...@google.com>
        Gerrit-Reviewer: Brian Wilkerson <brianwi...@google.com>
        Gerrit-Reviewer: Johnni Winther <johnni...@google.com>
        Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
        Gerrit-Reviewer: Marya Belanger <mbel...@google.com>
        Gerrit-Attention: Konstantin Shcheglov <sche...@google.com>
        Gerrit-Attention: Brian Wilkerson <brianwi...@google.com>
        Gerrit-Comment-Date: Mon, 20 Mar 2023 20:19:28 +0000

        Brian Wilkerson (Gerrit)

        unread,
        Mar 20, 2023, 6:37:27 PM3/20/23
        to Brian Wilkerson, dart-analys...@google.com, dart-fe-te...@google.com, dart-uxr...@google.com, rev...@dartlang.org, Johnni Winther, CBuild, Commit Queue, Marya Belanger, Konstantin Shcheglov

        Attention is currently required from: Brian Wilkerson, Konstantin Shcheglov.

        Patch set 8:Commit-Queue +2

        View Change

          To view, visit change 286524. To unsubscribe, or for help writing mail filters, visit settings.

          Gerrit-Project: sdk
          Gerrit-Branch: main
          Gerrit-Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
          Gerrit-Change-Number: 286524
          Gerrit-PatchSet: 8
          Gerrit-Owner: Brian Wilkerson <brianwi...@google.com>
          Gerrit-Reviewer: Brian Wilkerson <brianwi...@google.com>
          Gerrit-Reviewer: Johnni Winther <johnni...@google.com>
          Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
          Gerrit-Reviewer: Marya Belanger <mbel...@google.com>
          Gerrit-Attention: Konstantin Shcheglov <sche...@google.com>
          Gerrit-Attention: Brian Wilkerson <brianwi...@google.com>
          Gerrit-Comment-Date: Mon, 20 Mar 2023 22:37:22 +0000

          Commit Queue (Gerrit)

          unread,
          Mar 20, 2023, 8:36:32 PM3/20/23
          to Brian Wilkerson, dart-analys...@google.com, dart-fe-te...@google.com, dart-uxr...@google.com, rev...@dartlang.org, Johnni Winther, CBuild, Marya Belanger, Konstantin Shcheglov

          Commit Queue submitted this change.

          View Change



          6 is the latest approved patch-set.
          The change was submitted with unreviewed changes in the following files:

          ```
          The name of the file: pkg/front_end/parser_testcases/record/record_type_02.dart.expect
          Insertions: 2, Deletions: 2.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: pkg/front_end/testcases/patterns/issue50897.dart.weak.transformed.expect
          Insertions: 53, Deletions: 0.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: pkg/front_end/parser_testcases/general/call_on_after_try_block.dart.expect
          Insertions: 1, Deletions: 1.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: pkg/front_end/parser_testcases/record/on.dart.expect
          Insertions: 1, Deletions: 1.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: pkg/front_end/parser_testcases/general/call_on_after_try_block2.dart.expect
          Insertions: 2, Deletions: 2.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: pkg/front_end/parser_testcases/record/record_and_commas.dart.expect
          Insertions: 4, Deletions: 4.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: pkg/front_end/testcases/records/record_type_errors.dart.weak.outline.expect
          Insertions: 4, Deletions: 4.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: pkg/front_end/testcases/records/record_type_errors.dart.weak.transformed.expect
          Insertions: 8, Deletions: 8.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: pkg/front_end/parser_testcases/error_recovery/issue_26073.dart.expect
          Insertions: 1, Deletions: 1.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: pkg/front_end/testcases/records/record_type_errors.dart.strong.transformed.expect
          Insertions: 8, Deletions: 8.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: pkg/front_end/testcases/general/issue_47541.dart.weak.expect
          Insertions: 1, Deletions: 1.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: pkg/front_end/testcases/general/issue_47541.dart.weak.modular.expect
          Insertions: 1, Deletions: 1.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: pkg/front_end/testcases/general/issue_47541.dart.weak.transformed.expect
          Insertions: 1, Deletions: 1.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: pkg/front_end/parser_testcases/error_recovery/keyword_named_top_level_methods.dart.expect
          Insertions: 2, Deletions: 2.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: pkg/front_end/testcases/patterns/issue50897.dart.weak.modular.expect
          Insertions: 51, Deletions: 0.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: tests/language/record_literal_problems_test.dart
          Insertions: 1, Deletions: 1.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: pkg/front_end/testcases/general/issue_47541.dart.strong.expect
          Insertions: 1, Deletions: 1.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: pkg/front_end/parser_testcases/error_recovery/keyword_named_class_methods.dart.expect
          Insertions: 2, Deletions: 2.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: tests/language/record_type_problems_test.dart
          Insertions: 2, Deletions: 2.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: pkg/front_end/testcases/records/record_type_errors.dart.weak.modular.expect
          Insertions: 8, Deletions: 8.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: tests/language/record_type_empty_problems_test.dart
          Insertions: 2, Deletions: 2.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: pkg/front_end/testcases/records/record_type_errors.dart.strong.expect
          Insertions: 8, Deletions: 8.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: pkg/front_end/testcases/patterns/issue50897.dart.strong.transformed.expect
          Insertions: 53, Deletions: 0.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: tests/language_2/record_literal_problems_test.dart
          Insertions: 1, Deletions: 1.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: pkg/front_end/parser_testcases/record/record_literal_04.dart.expect
          Insertions: 1, Deletions: 1.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: pkg/front_end/testcases/patterns/issue50897.dart.weak.expect
          Insertions: 51, Deletions: 0.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: pkg/front_end/testcases/patterns/issue50897.dart.strong.expect
          Insertions: 51, Deletions: 0.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: pkg/front_end/testcases/general/issue_47541.dart.strong.transformed.expect
          Insertions: 1, Deletions: 1.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: tests/language_2/record_type_problems_test.dart
          Insertions: 2, Deletions: 2.

          The diff is too large to show. Please review the diff.
          ```
          ```
          The name of the file: pkg/front_end/testcases/records/record_type_errors.dart.weak.expect
          Insertions: 8, Deletions: 8.

          The diff is too large to show. Please review the diff.
          ```

          Approvals: Marya Belanger: Looks good to me, approved Konstantin Shcheglov: Looks good to me, approved Johnni Winther: Looks good to me, approved Brian Wilkerson: Commit
          Add documentation for new diagnostics

          I have not yet run the analyzer's generators just to keep the generated
          version of the changes out of the review.

          There are 10 parser diagnostics that are not being documented:
          - ParserErrorCode.INVALID_CONSTANT_CONST_PREFIX
          - ParserErrorCode.INVALID_CONSTANT_PATTERN_BINARY
          - ParserErrorCode.INVALID_CONSTANT_PATTERN_DUPLICATE_CONST
          - ParserErrorCode.INVALID_CONSTANT_PATTERN_EMPTY_RECORD_LITERAL
          - ParserErrorCode.INVALID_CONSTANT_PATTERN_GENERIC
          - ParserErrorCode.INVALID_CONSTANT_PATTERN_NEGATION
          - ParserErrorCode.INVALID_CONSTANT_PATTERN_UNARY
          - ParserErrorCode.FINAL_MIXIN_CLASS
          - ParserErrorCode.INTERFACE_MIXIN_CLASS
          - ParserErrorCode.SEALED_MIXIN_CLASS

          Let me know if you think any of those need documentation.

          Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
          Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/286524
          Reviewed-by: Johnni Winther <johnni...@google.com>
          Commit-Queue: Brian Wilkerson <brianwi...@google.com>
          Reviewed-by: Marya Belanger <mbel...@google.com>
          Reviewed-by: Konstantin Shcheglov <sche...@google.com>

          ---
          M pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
          M pkg/analyzer/lib/src/dart/error/hint_codes.g.dart
          M pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
          M pkg/analyzer/lib/src/error/codes.g.dart
          M pkg/analyzer/messages.yaml
          M pkg/analyzer/test/verify_diagnostics_test.dart
          M pkg/analyzer/tool/diagnostics/diagnostics.md
          M pkg/analyzer/tool/diagnostics/generate.dart
          M pkg/front_end/messages.yaml
          M pkg/front_end/parser_testcases/error_recovery/issue_26073.dart.expect
          M pkg/front_end/parser_testcases/error_recovery/keyword_named_class_methods.dart.expect
          M pkg/front_end/parser_testcases/error_recovery/keyword_named_top_level_methods.dart.expect
          M pkg/front_end/parser_testcases/general/call_on_after_try_block.dart.expect
          M pkg/front_end/parser_testcases/general/call_on_after_try_block2.dart.expect
          M pkg/front_end/parser_testcases/record/on.dart.expect
          M pkg/front_end/parser_testcases/record/record_and_commas.dart.expect
          M pkg/front_end/parser_testcases/record/record_literal_04.dart.expect
          M pkg/front_end/parser_testcases/record/record_type_02.dart.expect
          M pkg/front_end/testcases/general/issue_47541.dart.strong.expect
          M pkg/front_end/testcases/general/issue_47541.dart.strong.transformed.expect
          M pkg/front_end/testcases/general/issue_47541.dart.weak.expect
          M pkg/front_end/testcases/general/issue_47541.dart.weak.modular.expect
          M pkg/front_end/testcases/general/issue_47541.dart.weak.transformed.expect
          M pkg/front_end/testcases/records/record_type_errors.dart.strong.expect
          M pkg/front_end/testcases/records/record_type_errors.dart.strong.transformed.expect
          M pkg/front_end/testcases/records/record_type_errors.dart.weak.expect
          M pkg/front_end/testcases/records/record_type_errors.dart.weak.modular.expect
          M pkg/front_end/testcases/records/record_type_errors.dart.weak.outline.expect
          M pkg/front_end/testcases/records/record_type_errors.dart.weak.transformed.expect
          M tests/language/record_literal_problems_test.dart
          M tests/language/record_type_empty_problems_test.dart
          M tests/language/record_type_problems_test.dart
          M tests/language_2/record_literal_problems_test.dart
          M tests/language_2/record_type_problems_test.dart
          34 files changed, 3,931 insertions(+), 230 deletions(-)

          index 8f194b4..8ef5e47 100644
          --- a/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart
          +++ b/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart
          @@ -244,6 +244,9 @@
          index 8e72acf..22a5021 100644

          --- a/pkg/analyzer/lib/src/error/codes.g.dart
          +++ b/pkg/analyzer/lib/src/error/codes.g.dart
          @@ -415,8 +415,8 @@
          /// 0: the name of the class being used as a mixin
          static const CompileTimeErrorCode CLASS_USED_AS_MIXIN = CompileTimeErrorCode(
          'CLASS_USED_AS_MIXIN',
          - "The class '{0}' can't be used as a mixin because it isn't a mixin class "
          - "nor a mixin.",
          + "The class '{0}' can't be used as a mixin because it's neither a mixin "
          + "class nor a mixin.",
          );

          static const CompileTimeErrorCode CONCRETE_CLASS_HAS_ENUM_SUPERINTERFACE =
          @@ -3873,11 +3873,11 @@

          hasPublishedDocs: true,
          );

          + /// No parameters.
          static const CompileTimeErrorCode PATTERN_ASSIGNMENT_NOT_LOCAL_VARIABLE =
          CompileTimeErrorCode(
          'PATTERN_ASSIGNMENT_NOT_LOCAL_VARIABLE',
          - "Only local variables or formal parameters can be used in pattern "
          - "assignments.",
          + "Only local variables can be assigned in pattern assignments.",
          correctionMessage: "Try assigning to a local variable.",
          );

          @@ -3915,36 +3915,39 @@
          @@ -5248,6 +5251,7 @@

          hasPublishedDocs: true,
          );

          + /// No parameters.
          static const CompileTimeErrorCode
          VARIABLE_PATTERN_KEYWORD_IN_DECLARATION_CONTEXT = CompileTimeErrorCode(
          'VARIABLE_PATTERN_KEYWORD_IN_DECLARATION_CONTEXT',
          diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml
          index abd9b9d..932b5b6 100644
          @@ -9583,12 +10369,12 @@

          constants referenced in case clauses need to be available at compile time,
          and constants from deferred libraries aren't available at compile time.

          - For more information, see the language tour's coverage of
          - [deferred loading](https://dart.dev/guides/language/language-tour#lazily-loading-a-library).
          + For more information, check out
          + [Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).

          #### Example

          - Given a file (`a.dart`) that defines the constant `zero`:
          + Given a file `a.dart` that defines the constant `zero`:

          ```dart
          %uri="lib/a.dart"
          @@ -9712,12 +10498,12 @@

          Default values need to be available at compile time, and constants from
          deferred libraries aren't available at compile time.

          - For more information, see the language tour's coverage of
          - [deferred loading](https://dart.dev/guides/language/language-tour#lazily-loading-a-library).
          + For more information, check out
          + [Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).

          #### Example

          - Given a file (`a.dart`) that defines the constant `zero`:
          + Given a file `a.dart` that defines the constant `zero`:

          ```dart
          %uri="lib/a.dart"
          @@ -9880,6 +10666,40 @@
          @@ -9920,6 +10740,36 @@
          @@ -9971,6 +10821,67 @@
          @@ -11228,7 +12139,7 @@


          #### Example

          - Given a file named `part.dart` containing
          + Given a file `part.dart` containing

          ```dart
          %uri="package:a/part.dart"
          @@ -11266,7 +12177,7 @@


          #### Example

          - Given a file (`a.dart`) containing:
          + Given a file `a.dart` containing:

          ```dart
          %uri="lib/a.dart"
          @@ -11340,8 +12251,61 @@
          @@ -11349,22 +12313,243 @@
          @@ -11589,7 +12774,7 @@


          #### Example

          - Given a file named `a.dart` containing the following code:
          + Given a file `a.dart` containing the following code:

          ```dart
          %uri="lib/a.dart"
          @@ -11669,7 +12854,7 @@


          #### Example

          - Given a file named `a.dart` that contains the following:
          + Given a file `a.dart` that contains the following:

          ```dart
          %uri="lib/a.dart"
          @@ -12469,6 +13654,38 @@
          @@ -12479,12 +13696,141 @@
          @@ -12921,6 +14267,32 @@
          @@ -13174,12 +14546,12 @@

          classes from deferred libraries aren't compiled until the library is
          loaded.

          - For more information, see the language tour's coverage of
          - [deferred loading](https://dart.dev/guides/language/language-tour#lazily-loading-a-library).
          + For more information, check out
          + [Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).

          #### Example

          - Given a file (`a.dart`) that defines the class `A`:
          + Given a file `a.dart` that defines the class `A`:

          ```dart
          %uri="lib/a.dart"
          @@ -13666,7 +15038,7 @@


          #### Common fixes

          - Add an explicit null check to the expression:
          + Add an explicit null-check to the expression:

          ```dart
          void f(String? s) {
          @@ -13766,8 +15138,8 @@

          is a type declared in a library that is imported using a deferred import.
          These types are required to be available at compile time, but aren't.

          - For more information, see the language tour's coverage of
          - [deferred loading](https://dart.dev/guides/language/language-tour#lazily-loading-a-library).
          + For more information, check out
          + [Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).

          #### Example

          @@ -15546,6 +16918,35 @@
          @@ -18210,12 +19611,12 @@

          function is used to load the contents of the deferred library, and the
          implicit function hides the explicit declaration in the deferred library.

          - For more information, see the language tour's coverage of
          - [deferred loading](https://dart.dev/guides/language/language-tour#lazily-loading-a-library).
          + For more information, check out
          + [Lazily loading a library](https://dart.dev/language/libraries#lazily-loading-a-library).

          #### Example

          - Given a file (`a.dart`) that defines a function named `loadLibrary`:
          + Given a file `a.dart` that defines a function named `loadLibrary`:

          ```dart
          %uri="lib/a.dart"
          @@ -18286,7 +19687,7 @@


          #### Example

          - Given a file named `a.dart` that contains the following:
          + Given a file `a.dart` that contains the following:

          ```dart
          %uri="lib/a.dart"
          @@ -18428,14 +19829,14 @@


          #### Example

          - Given a file named `a.dart` that contains the following:
          + Given a file `a.dart` that contains the following:

          ```dart
          %uri="lib/a.dart"
          class A {}
          ```

          - And, given a file named `b.dart` that contains the following:
          + And, given a file `b.dart` that contains the following:

          ```dart
          %uri="lib/b.dart"
          @@ -18467,6 +19868,43 @@
          @@ -18511,7 +19949,45 @@
          @@ -19579,7 +21055,7 @@


          #### Example

          - Assuming that the directory `local_package` doesn't contain a file named
          + Assuming that the directory `local_package` doesn't contain a file
          `pubspec.yaml`, the following code produces this diagnostic because it's
          listed as the path of a package:

          @@ -19910,10 +21386,63 @@
          @@ -20187,6 +21716,44 @@
          @@ -20688,7 +22255,7 @@


          #### Example

          - Given a file named `a.dart` in the `src` directory that contains:
          + Given a file `a.dart` in the `src` directory that contains:

          ```dart
          %uri="lib/src/a.dart"
          @@ -20732,7 +22299,7 @@


          #### Example

          - Given a file named `a.dart` in the `src` directory that contains the
          + Given a file `a.dart` in the `src` directory that contains the
          following:

          ```dart
          @@ -21299,7 +22866,7 @@


          #### Example

          - Given a file named `a.dart` containing the following declaration:
          + Given a file `a.dart` containing the following declaration:

          ```dart
          %uri="lib/a.dart"
          @@ -21356,7 +22923,7 @@


          #### Example

          - Given a file named `c.dart` that contains the following:
          + Given a file `c.dart` that contains the following:

          ```dart
          %uri="lib/c.dart"
          diff --git a/pkg/analyzer/test/verify_diagnostics_test.dart b/pkg/analyzer/test/verify_diagnostics_test.dart
          index b4cce87..da380e4 100644
          --- a/pkg/analyzer/test/verify_diagnostics_test.dart
          +++ b/pkg/analyzer/test/verify_diagnostics_test.dart
          @@ -193,15 +193,23 @@
          index ef3e637..99ac1fc 100644
          diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_26073.dart.expect b/pkg/front_end/parser_testcases/error_recovery/issue_26073.dart.expect
          index 3ede2bc..d49cc7c 100644
          --- a/pkg/front_end/parser_testcases/error_recovery/issue_26073.dart.expect
          +++ b/pkg/front_end/parser_testcases/error_recovery/issue_26073.dart.expect
          @@ -4,7 +4,7 @@
          typedef c = foo(int x); // error.
          ^

          -parser/error_recovery/issue_26073:4:19: Record type with one entry requires a trailing comma.
          +parser/error_recovery/issue_26073:4:19: A record type with exactly one positional field requires a trailing comma.
          typedef d = (int x); // error.
          ^

          diff --git a/pkg/front_end/parser_testcases/error_recovery/keyword_named_class_methods.dart.expect b/pkg/front_end/parser_testcases/error_recovery/keyword_named_class_methods.dart.expect
          index ed96aed..041ef99 100644
          --- a/pkg/front_end/parser_testcases/error_recovery/keyword_named_class_methods.dart.expect
          +++ b/pkg/front_end/parser_testcases/error_recovery/keyword_named_class_methods.dart.expect
          @@ -56,7 +56,7 @@
          int const(int x) {
          ^^^^^

          -parser/error_recovery/keyword_named_class_methods:49:21: Record literal with one field requires a trailing comma.
          +parser/error_recovery/keyword_named_class_methods:49:21: A record literal with exactly one positional field requires a trailing comma.
          return const(x-1) + 1;
          ^

          @@ -272,7 +272,7 @@
          return is(x-1) + 1;
          ^

          -parser/error_recovery/keyword_named_class_methods:184:18: Record type with one entry requires a trailing comma.
          +parser/error_recovery/keyword_named_class_methods:184:18: A record type with exactly one positional field requires a trailing comma.
          return is(x-1) + 1;
          ^

          diff --git a/pkg/front_end/parser_testcases/error_recovery/keyword_named_top_level_methods.dart.expect b/pkg/front_end/parser_testcases/error_recovery/keyword_named_top_level_methods.dart.expect
          index 0a21b0f..8222444 100644
          --- a/pkg/front_end/parser_testcases/error_recovery/keyword_named_top_level_methods.dart.expect
          +++ b/pkg/front_end/parser_testcases/error_recovery/keyword_named_top_level_methods.dart.expect
          @@ -56,7 +56,7 @@
          int const(int x) {
          ^^^^^

          -parser/error_recovery/keyword_named_top_level_methods:48:19: Record literal with one field requires a trailing comma.
          +parser/error_recovery/keyword_named_top_level_methods:48:19: A record literal with exactly one positional field requires a trailing comma.
          return const(x-1) + 1;
          ^

          @@ -272,7 +272,7 @@
          return is(x-1) + 1;
          ^

          -parser/error_recovery/keyword_named_top_level_methods:183:16: Record type with one entry requires a trailing comma.
          +parser/error_recovery/keyword_named_top_level_methods:183:16: A record type with exactly one positional field requires a trailing comma.
          return is(x-1) + 1;
          ^

          diff --git a/pkg/front_end/parser_testcases/general/call_on_after_try_block.dart.expect b/pkg/front_end/parser_testcases/general/call_on_after_try_block.dart.expect
          index e269a92..ed37907 100644
          --- a/pkg/front_end/parser_testcases/general/call_on_after_try_block.dart.expect
          +++ b/pkg/front_end/parser_testcases/general/call_on_after_try_block.dart.expect
          @@ -8,7 +8,7 @@
          on(42);
          ^^

          -parser/general/call_on_after_try_block:12:8: Record type with one entry requires a trailing comma.
          +parser/general/call_on_after_try_block:12:8: A record type with exactly one positional field requires a trailing comma.
          on(42);
          ^

          diff --git a/pkg/front_end/parser_testcases/general/call_on_after_try_block2.dart.expect b/pkg/front_end/parser_testcases/general/call_on_after_try_block2.dart.expect
          index 82109c7..a12d98b 100644
          --- a/pkg/front_end/parser_testcases/general/call_on_after_try_block2.dart.expect
          +++ b/pkg/front_end/parser_testcases/general/call_on_after_try_block2.dart.expect
          @@ -1,6 +1,6 @@
          Problems reported:

          -parser/general/call_on_after_try_block2:12:7: Record type with one entry requires a trailing comma.
          +parser/general/call_on_after_try_block2:12:7: A record type with exactly one positional field requires a trailing comma.
          on(e) {
          ^

          @@ -12,7 +12,7 @@
          on("");
          ^^

          -parser/general/call_on_after_try_block2:15:8: Record type with one entry requires a trailing comma.
          +parser/general/call_on_after_try_block2:15:8: A record type with exactly one positional field requires a trailing comma.
          on("");
          ^

          diff --git a/pkg/front_end/parser_testcases/record/on.dart.expect b/pkg/front_end/parser_testcases/record/on.dart.expect
          index 4da117d4c3..2ba0e93 100644
          --- a/pkg/front_end/parser_testcases/record/on.dart.expect
          +++ b/pkg/front_end/parser_testcases/record/on.dart.expect
          @@ -8,7 +8,7 @@
          } on ([int? i, String? n]) {
          ^

          -parser/record/on:5:28: Record type with one entry requires a trailing comma.
          +parser/record/on:5:28: A record type with exactly one positional field requires a trailing comma.
          } on ([int? i, String? n]) {
          ^

          diff --git a/pkg/front_end/parser_testcases/record/record_and_commas.dart.expect b/pkg/front_end/parser_testcases/record/record_and_commas.dart.expect
          index d11df8d..56bbce2 100644
          --- a/pkg/front_end/parser_testcases/record/record_and_commas.dart.expect
          +++ b/pkg/front_end/parser_testcases/record/record_and_commas.dart.expect
          @@ -1,18 +1,18 @@
          Problems reported:

          -parser/record/record_and_commas:6:4: Record type without fields can't have a trailing comma.
          +parser/record/record_and_commas:6:4: A record type without fields can't have a trailing comma.
          (,) emptyRecord2 = ();
          ^

          -parser/record/record_and_commas:7:22: Record literal without fields can't have a trailing comma.
          +parser/record/record_and_commas:7:22: A record literal without fields can't have a trailing comma.
          () emptyRecord3 = (,);
          ^

          -parser/record/record_and_commas:8:4: Record type without fields can't have a trailing comma.
          +parser/record/record_and_commas:8:4: A record type without fields can't have a trailing comma.
          (,) emptyRecord4 = (,);
          ^

          -parser/record/record_and_commas:8:23: Record literal without fields can't have a trailing comma.
          +parser/record/record_and_commas:8:23: A record literal without fields can't have a trailing comma.
          (,) emptyRecord4 = (,);
          ^

          diff --git a/pkg/front_end/parser_testcases/record/record_literal_04.dart.expect b/pkg/front_end/parser_testcases/record/record_literal_04.dart.expect
          index 005f1bd..96efaba 100644
          --- a/pkg/front_end/parser_testcases/record/record_literal_04.dart.expect
          +++ b/pkg/front_end/parser_testcases/record/record_literal_04.dart.expect
          @@ -1,6 +1,6 @@
          Problems reported:

          -parser/record/record_literal_04:9:21: Record literal with one field requires a trailing comma.
          +parser/record/record_literal_04:9:21: A record literal with exactly one positional field requires a trailing comma.
          var r5 = const (42);
          ^

          diff --git a/pkg/front_end/parser_testcases/record/record_type_02.dart.expect b/pkg/front_end/parser_testcases/record/record_type_02.dart.expect
          index d485df1..55e71e6 100644
          --- a/pkg/front_end/parser_testcases/record/record_type_02.dart.expect
          +++ b/pkg/front_end/parser_testcases/record/record_type_02.dart.expect
          @@ -1,10 +1,10 @@
          Problems reported:

          -parser/record/record_type_02:2:26: Record type named fields list can't be empty.
          +parser/record/record_type_02:2:26: The list of named fields in a record type can't be empty.
          (int, int, {/*missing*/}) record1 = (1, 2);
          ^

          -parser/record/record_type_02:3:37: Record type with one entry requires a trailing comma.
          +parser/record/record_type_02:3:37: A record type with exactly one positional field requires a trailing comma.
          (int /* missing trailing comma */ ) record2 = (1, );
          ^

          diff --git a/pkg/front_end/testcases/general/issue_47541.dart.strong.expect b/pkg/front_end/testcases/general/issue_47541.dart.strong.expect
          index 5815575..9a971f2 100644
          --- a/pkg/front_end/testcases/general/issue_47541.dart.strong.expect
          +++ b/pkg/front_end/testcases/general/issue_47541.dart.strong.expect
          @@ -14,7 +14,7 @@
          // on(42);
          // ^^
          //
          -// pkg/front_end/testcases/general/issue_47541.dart:24:8: Error: Record type with one entry requires a trailing comma.
          +// pkg/front_end/testcases/general/issue_47541.dart:24:8: Error: A record type with exactly one positional field requires a trailing comma.
          // Try adding a trailing comma.
          // on(42);
          // ^
          diff --git a/pkg/front_end/testcases/general/issue_47541.dart.strong.transformed.expect b/pkg/front_end/testcases/general/issue_47541.dart.strong.transformed.expect
          index 5815575..9a971f2 100644
          --- a/pkg/front_end/testcases/general/issue_47541.dart.strong.transformed.expect
          +++ b/pkg/front_end/testcases/general/issue_47541.dart.strong.transformed.expect
          @@ -14,7 +14,7 @@
          // on(42);
          // ^^
          //
          -// pkg/front_end/testcases/general/issue_47541.dart:24:8: Error: Record type with one entry requires a trailing comma.
          +// pkg/front_end/testcases/general/issue_47541.dart:24:8: Error: A record type with exactly one positional field requires a trailing comma.
          // Try adding a trailing comma.
          // on(42);
          // ^
          diff --git a/pkg/front_end/testcases/general/issue_47541.dart.weak.expect b/pkg/front_end/testcases/general/issue_47541.dart.weak.expect
          index 5815575..9a971f2 100644
          --- a/pkg/front_end/testcases/general/issue_47541.dart.weak.expect
          +++ b/pkg/front_end/testcases/general/issue_47541.dart.weak.expect
          @@ -14,7 +14,7 @@
          // on(42);
          // ^^
          //
          -// pkg/front_end/testcases/general/issue_47541.dart:24:8: Error: Record type with one entry requires a trailing comma.
          +// pkg/front_end/testcases/general/issue_47541.dart:24:8: Error: A record type with exactly one positional field requires a trailing comma.
          // Try adding a trailing comma.
          // on(42);
          // ^
          diff --git a/pkg/front_end/testcases/general/issue_47541.dart.weak.modular.expect b/pkg/front_end/testcases/general/issue_47541.dart.weak.modular.expect
          index 5815575..9a971f2 100644
          --- a/pkg/front_end/testcases/general/issue_47541.dart.weak.modular.expect
          +++ b/pkg/front_end/testcases/general/issue_47541.dart.weak.modular.expect
          @@ -14,7 +14,7 @@
          // on(42);
          // ^^
          //
          -// pkg/front_end/testcases/general/issue_47541.dart:24:8: Error: Record type with one entry requires a trailing comma.
          +// pkg/front_end/testcases/general/issue_47541.dart:24:8: Error: A record type with exactly one positional field requires a trailing comma.
          // Try adding a trailing comma.
          // on(42);
          // ^
          diff --git a/pkg/front_end/testcases/general/issue_47541.dart.weak.transformed.expect b/pkg/front_end/testcases/general/issue_47541.dart.weak.transformed.expect
          index 5815575..9a971f2 100644
          --- a/pkg/front_end/testcases/general/issue_47541.dart.weak.transformed.expect
          +++ b/pkg/front_end/testcases/general/issue_47541.dart.weak.transformed.expect
          @@ -14,7 +14,7 @@
          // on(42);
          // ^^
          //
          -// pkg/front_end/testcases/general/issue_47541.dart:24:8: Error: Record type with one entry requires a trailing comma.
          +// pkg/front_end/testcases/general/issue_47541.dart:24:8: Error: A record type with exactly one positional field requires a trailing comma.
          // Try adding a trailing comma.
          // on(42);
          // ^
          diff --git a/pkg/front_end/testcases/records/record_type_errors.dart.strong.expect b/pkg/front_end/testcases/records/record_type_errors.dart.strong.expect
          index 67dfe7f..04f4cb2 100644
          --- a/pkg/front_end/testcases/records/record_type_errors.dart.strong.expect
          +++ b/pkg/front_end/testcases/records/record_type_errors.dart.strong.expect
          @@ -2,7 +2,7 @@
          //
          // Problems in library:
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:6:5: Error: Record type with one entry requires a trailing comma.
          +// pkg/front_end/testcases/records/record_type_errors.dart:6:5: Error: A record type with exactly one positional field requires a trailing comma.
          // Try adding a trailing comma.
          // (int) singleType = throw '';
          // ^
          @@ -20,13 +20,13 @@
          // (var a, {var b}) missingType = throw '';
          // ^^^
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:8:16: Error: Record type with one entry requires a trailing comma.
          +// pkg/front_end/testcases/records/record_type_errors.dart:8:16: Error: A record type with exactly one positional field requires a trailing comma.
          // Try adding a trailing comma.
          // (var a, {var b}) missingType = throw '';
          // ^
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:9:8: Error: Record type named fields list can't be empty.
          -// Try adding a record type named field to the list.
          +// pkg/front_end/testcases/records/record_type_errors.dart:9:8: Error: The list of named fields in a record type can't be empty.
          +// Try adding a named field to the list.
          // (int, {}) emptyNamedFields = throw '';
          // ^
          //
          @@ -66,7 +66,7 @@
          // (var a, {var b}) missingType = throw '';
          // ^
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:15:7: Error: Record type with one entry requires a trailing comma.
          +// pkg/front_end/testcases/records/record_type_errors.dart:15:7: Error: A record type with exactly one positional field requires a trailing comma.
          // Try adding a trailing comma.
          // (int) singleType = throw '';
          // ^
          @@ -88,13 +88,13 @@
          // (var a, {var b}) missingType = throw '';
          // ^^^
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:17:18: Error: Record type with one entry requires a trailing comma.
          +// pkg/front_end/testcases/records/record_type_errors.dart:17:18: Error: A record type with exactly one positional field requires a trailing comma.
          // Try adding a trailing comma.
          // (var a, {var b}) missingType = throw '';
          // ^
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:18:10: Error: Record type named fields list can't be empty.
          -// Try adding a record type named field to the list.
          +// pkg/front_end/testcases/records/record_type_errors.dart:18:10: Error: The list of named fields in a record type can't be empty.
          +// Try adding a named field to the list.
          // (int, {}) emptyNamedFields = throw '';
          // ^
          //
          diff --git a/pkg/front_end/testcases/records/record_type_errors.dart.strong.transformed.expect b/pkg/front_end/testcases/records/record_type_errors.dart.strong.transformed.expect
          index 67dfe7f..04f4cb2 100644
          --- a/pkg/front_end/testcases/records/record_type_errors.dart.strong.transformed.expect
          +++ b/pkg/front_end/testcases/records/record_type_errors.dart.strong.transformed.expect
          @@ -2,7 +2,7 @@
          //
          // Problems in library:
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:6:5: Error: Record type with one entry requires a trailing comma.
          +// pkg/front_end/testcases/records/record_type_errors.dart:6:5: Error: A record type with exactly one positional field requires a trailing comma.
          // Try adding a trailing comma.
          // (int) singleType = throw '';
          // ^
          @@ -20,13 +20,13 @@
          // (var a, {var b}) missingType = throw '';
          // ^^^
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:8:16: Error: Record type with one entry requires a trailing comma.
          +// pkg/front_end/testcases/records/record_type_errors.dart:8:16: Error: A record type with exactly one positional field requires a trailing comma.
          // Try adding a trailing comma.
          // (var a, {var b}) missingType = throw '';
          // ^
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:9:8: Error: Record type named fields list can't be empty.
          -// Try adding a record type named field to the list.
          +// pkg/front_end/testcases/records/record_type_errors.dart:9:8: Error: The list of named fields in a record type can't be empty.
          +// Try adding a named field to the list.
          // (int, {}) emptyNamedFields = throw '';
          // ^
          //
          @@ -66,7 +66,7 @@
          // (var a, {var b}) missingType = throw '';
          // ^
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:15:7: Error: Record type with one entry requires a trailing comma.
          +// pkg/front_end/testcases/records/record_type_errors.dart:15:7: Error: A record type with exactly one positional field requires a trailing comma.
          // Try adding a trailing comma.
          // (int) singleType = throw '';
          // ^
          @@ -88,13 +88,13 @@
          // (var a, {var b}) missingType = throw '';
          // ^^^
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:17:18: Error: Record type with one entry requires a trailing comma.
          +// pkg/front_end/testcases/records/record_type_errors.dart:17:18: Error: A record type with exactly one positional field requires a trailing comma.
          // Try adding a trailing comma.
          // (var a, {var b}) missingType = throw '';
          // ^
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:18:10: Error: Record type named fields list can't be empty.
          -// Try adding a record type named field to the list.
          +// pkg/front_end/testcases/records/record_type_errors.dart:18:10: Error: The list of named fields in a record type can't be empty.
          +// Try adding a named field to the list.
          // (int, {}) emptyNamedFields = throw '';
          // ^
          //
          diff --git a/pkg/front_end/testcases/records/record_type_errors.dart.weak.expect b/pkg/front_end/testcases/records/record_type_errors.dart.weak.expect
          index 67dfe7f..04f4cb2 100644
          --- a/pkg/front_end/testcases/records/record_type_errors.dart.weak.expect
          +++ b/pkg/front_end/testcases/records/record_type_errors.dart.weak.expect
          @@ -2,7 +2,7 @@
          //
          // Problems in library:
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:6:5: Error: Record type with one entry requires a trailing comma.
          +// pkg/front_end/testcases/records/record_type_errors.dart:6:5: Error: A record type with exactly one positional field requires a trailing comma.
          // Try adding a trailing comma.
          // (int) singleType = throw '';
          // ^
          @@ -20,13 +20,13 @@
          // (var a, {var b}) missingType = throw '';
          // ^^^
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:8:16: Error: Record type with one entry requires a trailing comma.
          +// pkg/front_end/testcases/records/record_type_errors.dart:8:16: Error: A record type with exactly one positional field requires a trailing comma.
          // Try adding a trailing comma.
          // (var a, {var b}) missingType = throw '';
          // ^
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:9:8: Error: Record type named fields list can't be empty.
          -// Try adding a record type named field to the list.
          +// pkg/front_end/testcases/records/record_type_errors.dart:9:8: Error: The list of named fields in a record type can't be empty.
          +// Try adding a named field to the list.
          // (int, {}) emptyNamedFields = throw '';
          // ^
          //
          @@ -66,7 +66,7 @@
          // (var a, {var b}) missingType = throw '';
          // ^
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:15:7: Error: Record type with one entry requires a trailing comma.
          +// pkg/front_end/testcases/records/record_type_errors.dart:15:7: Error: A record type with exactly one positional field requires a trailing comma.
          // Try adding a trailing comma.
          // (int) singleType = throw '';
          // ^
          @@ -88,13 +88,13 @@
          // (var a, {var b}) missingType = throw '';
          // ^^^
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:17:18: Error: Record type with one entry requires a trailing comma.
          +// pkg/front_end/testcases/records/record_type_errors.dart:17:18: Error: A record type with exactly one positional field requires a trailing comma.
          // Try adding a trailing comma.
          // (var a, {var b}) missingType = throw '';
          // ^
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:18:10: Error: Record type named fields list can't be empty.
          -// Try adding a record type named field to the list.
          +// pkg/front_end/testcases/records/record_type_errors.dart:18:10: Error: The list of named fields in a record type can't be empty.
          +// Try adding a named field to the list.
          // (int, {}) emptyNamedFields = throw '';
          // ^
          //
          diff --git a/pkg/front_end/testcases/records/record_type_errors.dart.weak.modular.expect b/pkg/front_end/testcases/records/record_type_errors.dart.weak.modular.expect
          index 67dfe7f..04f4cb2 100644
          --- a/pkg/front_end/testcases/records/record_type_errors.dart.weak.modular.expect
          +++ b/pkg/front_end/testcases/records/record_type_errors.dart.weak.modular.expect
          @@ -2,7 +2,7 @@
          //
          // Problems in library:
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:6:5: Error: Record type with one entry requires a trailing comma.
          +// pkg/front_end/testcases/records/record_type_errors.dart:6:5: Error: A record type with exactly one positional field requires a trailing comma.
          // Try adding a trailing comma.
          // (int) singleType = throw '';
          // ^
          @@ -20,13 +20,13 @@
          // (var a, {var b}) missingType = throw '';
          // ^^^
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:8:16: Error: Record type with one entry requires a trailing comma.
          +// pkg/front_end/testcases/records/record_type_errors.dart:8:16: Error: A record type with exactly one positional field requires a trailing comma.
          // Try adding a trailing comma.
          // (var a, {var b}) missingType = throw '';
          // ^
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:9:8: Error: Record type named fields list can't be empty.
          -// Try adding a record type named field to the list.
          +// pkg/front_end/testcases/records/record_type_errors.dart:9:8: Error: The list of named fields in a record type can't be empty.
          +// Try adding a named field to the list.
          // (int, {}) emptyNamedFields = throw '';
          // ^
          //
          @@ -66,7 +66,7 @@
          // (var a, {var b}) missingType = throw '';
          // ^
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:15:7: Error: Record type with one entry requires a trailing comma.
          +// pkg/front_end/testcases/records/record_type_errors.dart:15:7: Error: A record type with exactly one positional field requires a trailing comma.
          // Try adding a trailing comma.
          // (int) singleType = throw '';
          // ^
          @@ -88,13 +88,13 @@
          // (var a, {var b}) missingType = throw '';
          // ^^^
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:17:18: Error: Record type with one entry requires a trailing comma.
          +// pkg/front_end/testcases/records/record_type_errors.dart:17:18: Error: A record type with exactly one positional field requires a trailing comma.
          // Try adding a trailing comma.
          // (var a, {var b}) missingType = throw '';
          // ^
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:18:10: Error: Record type named fields list can't be empty.
          -// Try adding a record type named field to the list.
          +// pkg/front_end/testcases/records/record_type_errors.dart:18:10: Error: The list of named fields in a record type can't be empty.
          +// Try adding a named field to the list.
          // (int, {}) emptyNamedFields = throw '';
          // ^
          //
          diff --git a/pkg/front_end/testcases/records/record_type_errors.dart.weak.outline.expect b/pkg/front_end/testcases/records/record_type_errors.dart.weak.outline.expect
          index 7f4a4e9..df428d3 100644
          --- a/pkg/front_end/testcases/records/record_type_errors.dart.weak.outline.expect
          +++ b/pkg/front_end/testcases/records/record_type_errors.dart.weak.outline.expect
          @@ -2,7 +2,7 @@
          //
          // Problems in library:
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:6:5: Error: Record type with one entry requires a trailing comma.
          +// pkg/front_end/testcases/records/record_type_errors.dart:6:5: Error: A record type with exactly one positional field requires a trailing comma.
          // Try adding a trailing comma.
          // (int) singleType = throw '';
          // ^
          @@ -20,13 +20,13 @@
          // (var a, {var b}) missingType = throw '';
          // ^^^
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:8:16: Error: Record type with one entry requires a trailing comma.
          +// pkg/front_end/testcases/records/record_type_errors.dart:8:16: Error: A record type with exactly one positional field requires a trailing comma.
          // Try adding a trailing comma.
          // (var a, {var b}) missingType = throw '';
          // ^
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:9:8: Error: Record type named fields list can't be empty.
          -// Try adding a record type named field to the list.
          +// pkg/front_end/testcases/records/record_type_errors.dart:9:8: Error: The list of named fields in a record type can't be empty.
          +// Try adding a named field to the list.
          // (int, {}) emptyNamedFields = throw '';
          // ^
          //
          diff --git a/pkg/front_end/testcases/records/record_type_errors.dart.weak.transformed.expect b/pkg/front_end/testcases/records/record_type_errors.dart.weak.transformed.expect
          index 67dfe7f..04f4cb2 100644
          --- a/pkg/front_end/testcases/records/record_type_errors.dart.weak.transformed.expect
          +++ b/pkg/front_end/testcases/records/record_type_errors.dart.weak.transformed.expect
          @@ -2,7 +2,7 @@
          //
          // Problems in library:
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:6:5: Error: Record type with one entry requires a trailing comma.
          +// pkg/front_end/testcases/records/record_type_errors.dart:6:5: Error: A record type with exactly one positional field requires a trailing comma.
          // Try adding a trailing comma.
          // (int) singleType = throw '';
          // ^
          @@ -20,13 +20,13 @@
          // (var a, {var b}) missingType = throw '';
          // ^^^
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:8:16: Error: Record type with one entry requires a trailing comma.
          +// pkg/front_end/testcases/records/record_type_errors.dart:8:16: Error: A record type with exactly one positional field requires a trailing comma.
          // Try adding a trailing comma.
          // (var a, {var b}) missingType = throw '';
          // ^
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:9:8: Error: Record type named fields list can't be empty.
          -// Try adding a record type named field to the list.
          +// pkg/front_end/testcases/records/record_type_errors.dart:9:8: Error: The list of named fields in a record type can't be empty.
          +// Try adding a named field to the list.
          // (int, {}) emptyNamedFields = throw '';
          // ^
          //
          @@ -66,7 +66,7 @@
          // (var a, {var b}) missingType = throw '';
          // ^
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:15:7: Error: Record type with one entry requires a trailing comma.
          +// pkg/front_end/testcases/records/record_type_errors.dart:15:7: Error: A record type with exactly one positional field requires a trailing comma.
          // Try adding a trailing comma.
          // (int) singleType = throw '';
          // ^
          @@ -88,13 +88,13 @@
          // (var a, {var b}) missingType = throw '';
          // ^^^
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:17:18: Error: Record type with one entry requires a trailing comma.
          +// pkg/front_end/testcases/records/record_type_errors.dart:17:18: Error: A record type with exactly one positional field requires a trailing comma.
          // Try adding a trailing comma.
          // (var a, {var b}) missingType = throw '';
          // ^
          //
          -// pkg/front_end/testcases/records/record_type_errors.dart:18:10: Error: Record type named fields list can't be empty.
          -// Try adding a record type named field to the list.
          +// pkg/front_end/testcases/records/record_type_errors.dart:18:10: Error: The list of named fields in a record type can't be empty.
          +// Try adding a named field to the list.
          // (int, {}) emptyNamedFields = throw '';
          // ^
          //
          diff --git a/tests/language/record_literal_problems_test.dart b/tests/language/record_literal_problems_test.dart
          index aafbefd..117a61c 100644
          --- a/tests/language/record_literal_problems_test.dart
          +++ b/tests/language/record_literal_problems_test.dart
          @@ -8,7 +8,7 @@
          var r1 = const (42);
          // ^
          // [analyzer] SYNTACTIC_ERROR.RECORD_LITERAL_ONE_POSITIONAL_NO_TRAILING_COMMA
          - // [cfe] Record literal with one field requires a trailing comma.
          + // [cfe] A record literal with exactly one positional field requires a trailing comma.

          var r2 = const ();
          }
          diff --git a/tests/language/record_type_empty_problems_test.dart b/tests/language/record_type_empty_problems_test.dart
          index a847433..e70e9cb 100644
          --- a/tests/language/record_type_empty_problems_test.dart
          +++ b/tests/language/record_type_empty_problems_test.dart
          @@ -8,10 +8,10 @@
          (int, int, {/*missing*/}) r1 = (1, 2);
          // ^
          // [analyzer] SYNTACTIC_ERROR.EMPTY_RECORD_TYPE_NAMED_FIELDS_LIST
          - // [cfe] Record type named fields list can't be empty.
          + // [cfe] The list of named fields in a record type can't be empty.

          (int /* missing trailing comma */ ) r2 = (1, );
          // ^
          // [analyzer] SYNTACTIC_ERROR.RECORD_TYPE_ONE_POSITIONAL_NO_TRAILING_COMMA
          - // [cfe] Record type with one entry requires a trailing comma.
          + // [cfe] A record type with exactly one positional field requires a trailing comma.
          }
          diff --git a/tests/language/record_type_problems_test.dart b/tests/language/record_type_problems_test.dart
          index a847433..e70e9cb 100644
          --- a/tests/language/record_type_problems_test.dart
          +++ b/tests/language/record_type_problems_test.dart
          @@ -8,10 +8,10 @@
          (int, int, {/*missing*/}) r1 = (1, 2);
          // ^
          // [analyzer] SYNTACTIC_ERROR.EMPTY_RECORD_TYPE_NAMED_FIELDS_LIST
          - // [cfe] Record type named fields list can't be empty.
          + // [cfe] The list of named fields in a record type can't be empty.

          (int /* missing trailing comma */ ) r2 = (1, );
          // ^
          // [analyzer] SYNTACTIC_ERROR.RECORD_TYPE_ONE_POSITIONAL_NO_TRAILING_COMMA
          - // [cfe] Record type with one entry requires a trailing comma.
          + // [cfe] A record type with exactly one positional field requires a trailing comma.
          }
          diff --git a/tests/language_2/record_literal_problems_test.dart b/tests/language_2/record_literal_problems_test.dart
          index 292cfeb..0768617 100644
          --- a/tests/language_2/record_literal_problems_test.dart
          +++ b/tests/language_2/record_literal_problems_test.dart
          @@ -13,7 +13,7 @@
          // [cfe] The 'records' language feature is disabled for this library.
          // ^
          // [analyzer] SYNTACTIC_ERROR.RECORD_LITERAL_ONE_POSITIONAL_NO_TRAILING_COMMA
          - // [cfe] Record literal with one field requires a trailing comma.
          + // [cfe] A record literal with exactly one positional field requires a trailing comma.

          var r2 = const ();
          // ^
          diff --git a/tests/language_2/record_type_problems_test.dart b/tests/language_2/record_type_problems_test.dart
          index eb45432..98718eb 100644
          --- a/tests/language_2/record_type_problems_test.dart
          +++ b/tests/language_2/record_type_problems_test.dart
          @@ -13,7 +13,7 @@
          // [cfe] This requires the experimental 'records' language feature to be enabled.
          // ^
          // [analyzer] SYNTACTIC_ERROR.EMPTY_RECORD_TYPE_NAMED_FIELDS_LIST
          -// [cfe] Record type named fields list can't be empty.
          +// [cfe] The list of named fields in a record type can't be empty.
          // ^
          // [analyzer] SYNTACTIC_ERROR.EXPERIMENT_NOT_ENABLED
          // [cfe] The 'records' language feature is disabled for this library.
          @@ -24,7 +24,7 @@
          // [cfe] This requires the experimental 'records' language feature to be enabled.
          // ^
          // [analyzer] SYNTACTIC_ERROR.RECORD_TYPE_ONE_POSITIONAL_NO_TRAILING_COMMA
          -// [cfe] Record type with one entry requires a trailing comma.
          +// [cfe] A record type with exactly one positional field requires a trailing comma.
          // ^
          // [analyzer] SYNTACTIC_ERROR.EXPERIMENT_NOT_ENABLED
          // [cfe] The 'records' language feature is disabled for this library.

          To view, visit change 286524. To unsubscribe, or for help writing mail filters, visit settings.

          Gerrit-Project: sdk
          Gerrit-Branch: main
          Gerrit-Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
          Gerrit-Change-Number: 286524
          Gerrit-PatchSet: 9
          Gerrit-Owner: Brian Wilkerson <brianwi...@google.com>
          Gerrit-Reviewer: Brian Wilkerson <brianwi...@google.com>
          Gerrit-Reviewer: Johnni Winther <johnni...@google.com>
          Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
          Gerrit-Reviewer: Marya Belanger <mbel...@google.com>
          Gerrit-MessageType: merged

          CBuild (Gerrit)

          unread,
          Mar 20, 2023, 9:18:45 PM3/20/23
          to Commit Queue, Brian Wilkerson, dart-analys...@google.com, dart-fe-te...@google.com, dart-uxr...@google.com, rev...@dartlang.org, Johnni Winther, Marya Belanger, Konstantin Shcheglov

          go/dart-cbuild result: FAILURE (NO REGRESSIONS DETECTED)

          Details: https://goto.google.com/dart-cbuild/find/101a2b428756e6c577d9f189d63d3faac1ac6edb

          View Change

            To view, visit change 286524. To unsubscribe, or for help writing mail filters, visit settings.

            Gerrit-Project: sdk
            Gerrit-Branch: main
            Gerrit-Change-Id: I904ecaeb07383fedcdc5c7c286f36d635ed8684e
            Gerrit-Change-Number: 286524
            Gerrit-PatchSet: 9
            Gerrit-Owner: Brian Wilkerson <brianwi...@google.com>
            Gerrit-Reviewer: Brian Wilkerson <brianwi...@google.com>
            Gerrit-Reviewer: Johnni Winther <johnni...@google.com>
            Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
            Gerrit-Reviewer: Marya Belanger <mbel...@google.com>
            Gerrit-Comment-Date: Tue, 21 Mar 2023 01:18:42 +0000
            Reply all
            Reply to author
            Forward
            0 new messages