Version 2.15.0-153.0.dev
Merge commit '7176311597509d456557c10e26066c4386c9eb8f' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b76d62e..036e134 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -268,6 +268,11 @@
### Core libraries
+#### `dart:async`
+
+- Make the `unawaited` function's argument nullable, to allow calls like
+ `unawaited(foo?.bar())` too.
+
#### `dart:cli`
- The experimental `waitFor` functionality, and the library containing only that
diff --git a/pkg/analyzer/lib/src/dart/constant/evaluation.dart b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
index 9a4f218..26fdf2b 100644
--- a/pkg/analyzer/lib/src/dart/constant/evaluation.dart
+++ b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
@@ -1507,6 +1507,11 @@
);
}
+ @override
+ DartObjectImpl? visitTypeLiteral(TypeLiteral node) {
+ return node.type.accept(this);
+ }
+
/// Add the entries produced by evaluating the given collection [element] to
/// the given [list]. Return `true` if the evaluation of one or more of the
/// elements failed.
@@ -1716,7 +1721,7 @@
} else if (variableElement is TypeAliasElement) {
var type = variableElement.instantiate(
typeArguments: variableElement.typeParameters
- .map((t) => _typeProvider.dynamicType)
+ .map((t) => t.bound ?? _typeProvider.dynamicType)
.toList(),
nullabilitySuffix: NullabilitySuffix.star,
);
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
index 43707ea..af7d2b2 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
@@ -2486,7 +2486,7 @@
/**
* No parameters.
*/
- /* // #### Description
+ // #### Description
//
// The analyzer produces this diagnostic when the operator `>>>` is used in
// code that has an SDK constraint whose lower bound is less than 2.X.0. This
@@ -2534,7 +2534,7 @@
// }
// return leftOperand ~/ divisor;
// }
- // ``` */
+ // ```
static const HintCode SDK_VERSION_GT_GT_GT_OPERATOR = HintCode(
'SDK_VERSION_GT_GT_GT_OPERATOR',
"The operator '>>>' wasn't supported until version 2.3.2, but this code "
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 d498abb..ed43512 100644
--- a/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
+++ b/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
@@ -130,555 +130,553 @@
const ParserErrorCode _ABSTRACT_CLASS_MEMBER = ParserErrorCode(
'ABSTRACT_CLASS_MEMBER',
- r"Members of classes can't be declared to be 'abstract'.",
+ "Members of classes can't be declared to be 'abstract'.",
correction:
"Try removing the 'abstract' keyword. You can add the 'abstract' keyword before the class declaration.");
const ParserErrorCode _ABSTRACT_EXTERNAL_FIELD = ParserErrorCode(
'ABSTRACT_EXTERNAL_FIELD',
- r"Fields can't be declared both 'abstract' and 'external'.",
+ "Fields can't be declared both 'abstract' and 'external'.",
correction: "Try removing the 'abstract' or 'external' keyword.");
const ParserErrorCode _ABSTRACT_LATE_FIELD = ParserErrorCode(
- 'ABSTRACT_LATE_FIELD', r"Abstract fields cannot be late.",
+ 'ABSTRACT_LATE_FIELD', "Abstract fields cannot be late.",
correction: "Try removing the 'abstract' or 'late' keyword.");
const ParserErrorCode _ABSTRACT_STATIC_FIELD = ParserErrorCode(
- 'ABSTRACT_STATIC_FIELD', r"Static fields can't be declared 'abstract'.",
+ 'ABSTRACT_STATIC_FIELD', "Static fields can't be declared 'abstract'.",
correction: "Try removing the 'abstract' or 'static' keyword.");
const ParserErrorCode _ANNOTATION_ON_TYPE_ARGUMENT = ParserErrorCode(
'ANNOTATION_ON_TYPE_ARGUMENT',
- r"Type arguments can't have annotations because they aren't declarations.");
+ "Type arguments can't have annotations because they aren't declarations.");
const ParserErrorCode _ANNOTATION_WITH_TYPE_ARGUMENTS = ParserErrorCode(
'ANNOTATION_WITH_TYPE_ARGUMENTS',
- r"An annotation can't use type arguments.");
+ "An annotation can't use type arguments.");
const ParserErrorCode _ANNOTATION_WITH_TYPE_ARGUMENTS_UNINSTANTIATED =
ParserErrorCode('ANNOTATION_WITH_TYPE_ARGUMENTS_UNINSTANTIATED',
- r"An annotation with type arguments must be followed by an argument list.");
+ "An annotation with type arguments must be followed by an argument list.");
const ParserErrorCode _BINARY_OPERATOR_WRITTEN_OUT = ParserErrorCode(
'BINARY_OPERATOR_WRITTEN_OUT',
- r"Binary operator '{0}' is written as '{1}' instead of the written out word.",
+ "Binary operator '{0}' is written as '{1}' instead of the written out word.",
correction: "Try replacing '{0}' with '{1}'.");
const ParserErrorCode _BREAK_OUTSIDE_OF_LOOP = ParserErrorCode(
'BREAK_OUTSIDE_OF_LOOP',
- r"A break statement can't be used outside of a loop or switch statement.",
+ "A break statement can't be used outside of a loop or switch statement.",
correction: "Try removing the break statement.");
const ParserErrorCode _CATCH_SYNTAX = ParserErrorCode('CATCH_SYNTAX',
- r"'catch' must be followed by '(identifier)' or '(identifier, identifier)'.",
+ "'catch' must be followed by '(identifier)' or '(identifier, identifier)'.",
correction:
"No types are needed, the first is given by 'on', the second is always 'StackTrace'.");
const ParserErrorCode _CATCH_SYNTAX_EXTRA_PARAMETERS = ParserErrorCode(
'CATCH_SYNTAX_EXTRA_PARAMETERS',
- r"'catch' must be followed by '(identifier)' or '(identifier, identifier)'.",
+ "'catch' must be followed by '(identifier)' or '(identifier, identifier)'.",
correction:
"No types are needed, the first is given by 'on', the second is always 'StackTrace'.");
const ParserErrorCode _CLASS_IN_CLASS = ParserErrorCode(
- 'CLASS_IN_CLASS', r"Classes can't be declared inside other classes.",
+ 'CLASS_IN_CLASS', "Classes can't be declared inside other classes.",
correction: "Try moving the class to the top-level.");
const ParserErrorCode _COLON_IN_PLACE_OF_IN = ParserErrorCode(
- 'COLON_IN_PLACE_OF_IN', r"For-in loops use 'in' rather than a colon.",
+ 'COLON_IN_PLACE_OF_IN', "For-in loops use 'in' rather than a colon.",
correction: "Try replacing the colon with the keyword 'in'.");
const ParserErrorCode _CONFLICTING_MODIFIERS = ParserErrorCode(
'CONFLICTING_MODIFIERS',
- r"Members can't be declared to be both '{0}' and '{1}'.",
+ "Members can't be declared to be both '{0}' and '{1}'.",
correction: "Try removing one of the keywords.");
const ParserErrorCode _CONSTRUCTOR_WITH_RETURN_TYPE = ParserErrorCode(
- 'CONSTRUCTOR_WITH_RETURN_TYPE', r"Constructors can't have a return type.",
+ 'CONSTRUCTOR_WITH_RETURN_TYPE', "Constructors can't have a return type.",
correction: "Try removing the return type.");
const ParserErrorCode _CONSTRUCTOR_WITH_TYPE_ARGUMENTS = ParserErrorCode(
'CONSTRUCTOR_WITH_TYPE_ARGUMENTS',
- r"A constructor invocation can't have type arguments after the constructor name.",
+ "A constructor invocation can't have type arguments after the constructor name.",
correction:
"Try removing the type arguments or placing them after the class name.");
const ParserErrorCode _CONST_AND_FINAL = ParserErrorCode('CONST_AND_FINAL',
- r"Members can't be declared to be both 'const' and 'final'.",
+ "Members can't be declared to be both 'const' and 'final'.",
correction: "Try removing either the 'const' or 'final' keyword.");
const ParserErrorCode _CONST_CLASS = ParserErrorCode(
- 'CONST_CLASS', r"Classes can't be declared to be 'const'.",
+ 'CONST_CLASS', "Classes can't be declared to be 'const'.",
correction:
"Try removing the 'const' keyword. If you're trying to indicate that instances of the class can be constants, place the 'const' keyword on the class' constructor(s).");
const ParserErrorCode _CONST_FACTORY = ParserErrorCode('CONST_FACTORY',
- r"Only redirecting factory constructors can be declared to be 'const'.",
+ "Only redirecting factory constructors can be declared to be 'const'.",
correction:
"Try removing the 'const' keyword, or replacing the body with '=' followed by a valid target.");
const ParserErrorCode _CONST_METHOD = ParserErrorCode('CONST_METHOD',
- r"Getters, setters and methods can't be declared to be 'const'.",
+ "Getters, setters and methods can't be declared to be 'const'.",
correction: "Try removing the 'const' keyword.");
const ParserErrorCode _CONTINUE_OUTSIDE_OF_LOOP = ParserErrorCode(
'CONTINUE_OUTSIDE_OF_LOOP',
- r"A continue statement can't be used outside of a loop or switch statement.",
+ "A continue statement can't be used outside of a loop or switch statement.",
correction: "Try removing the continue statement.");
const ParserErrorCode _CONTINUE_WITHOUT_LABEL_IN_CASE = ParserErrorCode(
'CONTINUE_WITHOUT_LABEL_IN_CASE',
- r"A continue statement in a switch statement must have a label as a target.",
+ "A continue statement in a switch statement must have a label as a target.",
correction:
"Try adding a label associated with one of the case clauses to the continue statement.");
const ParserErrorCode _COVARIANT_AND_STATIC = ParserErrorCode(
'COVARIANT_AND_STATIC',
- r"Members can't be declared to be both 'covariant' and 'static'.",
+ "Members can't be declared to be both 'covariant' and 'static'.",
correction: "Try removing either the 'covariant' or 'static' keyword.");
const ParserErrorCode _COVARIANT_MEMBER = ParserErrorCode('COVARIANT_MEMBER',
- r"Getters, setters and methods can't be declared to be 'covariant'.",
+ "Getters, setters and methods can't be declared to be 'covariant'.",
correction: "Try removing the 'covariant' keyword.");
const ParserErrorCode _DEFERRED_AFTER_PREFIX = ParserErrorCode(
'DEFERRED_AFTER_PREFIX',
- r"The deferred keyword should come immediately before the prefix ('as' clause).",
+ "The deferred keyword should come immediately before the prefix ('as' clause).",
correction: "Try moving the deferred keyword before the prefix.");
const ParserErrorCode _DIRECTIVE_AFTER_DECLARATION = ParserErrorCode(
'DIRECTIVE_AFTER_DECLARATION',
- r"Directives must appear before any declarations.",
+ "Directives must appear before any declarations.",
correction: "Try moving the directive before any declarations.");
const ParserErrorCode _DUPLICATED_MODIFIER = ParserErrorCode(
- 'DUPLICATED_MODIFIER', r"The modifier '{0}' was already specified.",
+ 'DUPLICATED_MODIFIER', "The modifier '{0}' was already specified.",
correction: "Try removing all but one occurrence of the modifier.");
const ParserErrorCode _DUPLICATE_DEFERRED = ParserErrorCode(
'DUPLICATE_DEFERRED',
- r"An import directive can only have one 'deferred' keyword.",
+ "An import directive can only have one 'deferred' keyword.",
correction: "Try removing all but one 'deferred' keyword.");
const ParserErrorCode _DUPLICATE_LABEL_IN_SWITCH_STATEMENT = ParserErrorCode(
'DUPLICATE_LABEL_IN_SWITCH_STATEMENT',
- r"The label '{0}' was already used in this switch statement.",
+ "The label '{0}' was already used in this switch statement.",
correction: "Try choosing a different name for this label.");
const ParserErrorCode _DUPLICATE_PREFIX = ParserErrorCode('DUPLICATE_PREFIX',
- r"An import directive can only have one prefix ('as' clause).",
+ "An import directive can only have one prefix ('as' clause).",
correction: "Try removing all but one prefix.");
const ParserErrorCode _ENUM_IN_CLASS = ParserErrorCode(
- 'ENUM_IN_CLASS', r"Enums can't be declared inside classes.",
+ 'ENUM_IN_CLASS', "Enums can't be declared inside classes.",
correction: "Try moving the enum to the top-level.");
const ParserErrorCode _EQUALITY_CANNOT_BE_EQUALITY_OPERAND = ParserErrorCode(
'EQUALITY_CANNOT_BE_EQUALITY_OPERAND',
- r"A comparison expression can't be an operand of another comparison expression.",
+ "A comparison expression can't be an operand of another comparison expression.",
correction: "Try putting parentheses around one of the comparisons.");
const ParserErrorCode _EXPECTED_BODY = ParserErrorCode(
- 'EXPECTED_BODY', r"A {0} must have a body, even if it is empty.",
+ 'EXPECTED_BODY', "A {0} must have a body, even if it is empty.",
correction: "Try adding an empty body.");
const ParserErrorCode _EXPECTED_ELSE_OR_COMMA =
- ParserErrorCode('EXPECTED_ELSE_OR_COMMA', r"Expected 'else' or comma.");
+ ParserErrorCode('EXPECTED_ELSE_OR_COMMA', "Expected 'else' or comma.");
const ParserErrorCode _EXPECTED_IDENTIFIER_BUT_GOT_KEYWORD = ParserErrorCode(
'EXPECTED_IDENTIFIER_BUT_GOT_KEYWORD',
- r"'{0}' can't be used as an identifier because it's a keyword.",
+ "'{0}' can't be used as an identifier because it's a keyword.",
correction: "Try renaming this to be an identifier that isn't a keyword.");
const ParserErrorCode _EXPECTED_INSTEAD =
- ParserErrorCode('EXPECTED_INSTEAD', r"Expected '{0}' instead of this.");
+ ParserErrorCode('EXPECTED_INSTEAD', "Expected '{0}' instead of this.");
const ParserErrorCode _EXPERIMENT_NOT_ENABLED = ParserErrorCode(
'EXPERIMENT_NOT_ENABLED',
- r"This requires the '{0}' language feature to be enabled.",
+ "This requires the '{0}' language feature to be enabled.",
correction:
"Try updating your pubspec.yaml to set the minimum SDK constraint to {1} or higher, and running 'pub get'.");
const ParserErrorCode _EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE = ParserErrorCode(
'EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE',
- r"Export directives must precede part directives.",
+ "Export directives must precede part directives.",
correction: "Try moving the export directives before the part directives.");
const ParserErrorCode _EXTENSION_DECLARES_ABSTRACT_MEMBER = ParserErrorCode(
'EXTENSION_DECLARES_ABSTRACT_MEMBER',
- r"Extensions can't declare abstract members.",
+ "Extensions can't declare abstract members.",
correction: "Try providing an implementation for the member.",
hasPublishedDocs: true);
const ParserErrorCode _EXTENSION_DECLARES_CONSTRUCTOR = ParserErrorCode(
- 'EXTENSION_DECLARES_CONSTRUCTOR', r"Extensions can't declare constructors.",
+ 'EXTENSION_DECLARES_CONSTRUCTOR', "Extensions can't declare constructors.",
correction: "Try removing the constructor declaration.",
hasPublishedDocs: true);
const ParserErrorCode _EXTENSION_DECLARES_INSTANCE_FIELD = ParserErrorCode(
'EXTENSION_DECLARES_INSTANCE_FIELD',
- r"Extensions can't declare instance fields",
+ "Extensions can't declare instance fields",
correction:
"Try removing the field declaration or making it a static field",
hasPublishedDocs: true);
const ParserErrorCode _EXTERNAL_CLASS = ParserErrorCode(
- 'EXTERNAL_CLASS', r"Classes can't be declared to be 'external'.",
+ 'EXTERNAL_CLASS', "Classes can't be declared to be 'external'.",
correction: "Try removing the keyword 'external'.");
const ParserErrorCode _EXTERNAL_CONSTRUCTOR_WITH_BODY = ParserErrorCode(
'EXTERNAL_CONSTRUCTOR_WITH_BODY',
- r"External constructors can't have a body.",
+ "External constructors can't have a body.",
correction:
"Try removing the body of the constructor, or removing the keyword 'external'.");
const ParserErrorCode _EXTERNAL_CONSTRUCTOR_WITH_INITIALIZER = ParserErrorCode(
'EXTERNAL_CONSTRUCTOR_WITH_INITIALIZER',
- r"An external constructor can't have any initializers.");
+ "An external constructor can't have any initializers.");
const ParserErrorCode _EXTERNAL_ENUM = ParserErrorCode(
- 'EXTERNAL_ENUM', r"Enums can't be declared to be 'external'.",
+ 'EXTERNAL_ENUM', "Enums can't be declared to be 'external'.",
correction: "Try removing the keyword 'external'.");
const ParserErrorCode _EXTERNAL_FACTORY_REDIRECTION = ParserErrorCode(
- 'EXTERNAL_FACTORY_REDIRECTION', r"A redirecting factory can't be external.",
+ 'EXTERNAL_FACTORY_REDIRECTION', "A redirecting factory can't be external.",
correction: "Try removing the 'external' modifier.");
const ParserErrorCode _EXTERNAL_FACTORY_WITH_BODY = ParserErrorCode(
- 'EXTERNAL_FACTORY_WITH_BODY', r"External factories can't have a body.",
+ 'EXTERNAL_FACTORY_WITH_BODY', "External factories can't have a body.",
correction:
"Try removing the body of the factory, or removing the keyword 'external'.");
const ParserErrorCode _EXTERNAL_FIELD = ParserErrorCode(
- 'EXTERNAL_FIELD', r"Fields can't be declared to be 'external'.",
+ 'EXTERNAL_FIELD', "Fields can't be declared to be 'external'.",
correction:
"Try removing the keyword 'external', or replacing the field by an external getter and/or setter.");
const ParserErrorCode _EXTERNAL_LATE_FIELD = ParserErrorCode(
- 'EXTERNAL_LATE_FIELD', r"External fields cannot be late.",
+ 'EXTERNAL_LATE_FIELD', "External fields cannot be late.",
correction: "Try removing the 'external' or 'late' keyword.");
const ParserErrorCode _EXTERNAL_METHOD_WITH_BODY = ParserErrorCode(
'EXTERNAL_METHOD_WITH_BODY',
- r"An external or native method can't have a body.");
+ "An external or native method can't have a body.");
const ParserErrorCode _EXTERNAL_TYPEDEF = ParserErrorCode(
- 'EXTERNAL_TYPEDEF', r"Typedefs can't be declared to be 'external'.",
+ 'EXTERNAL_TYPEDEF', "Typedefs can't be declared to be 'external'.",
correction: "Try removing the keyword 'external'.");
const ParserErrorCode _EXTRANEOUS_MODIFIER = ParserErrorCode(
- 'EXTRANEOUS_MODIFIER', r"Can't have modifier '{0}' here.",
+ 'EXTRANEOUS_MODIFIER', "Can't have modifier '{0}' here.",
correction: "Try removing '{0}'.");
const ParserErrorCode _FACTORY_TOP_LEVEL_DECLARATION = ParserErrorCode(
'FACTORY_TOP_LEVEL_DECLARATION',
- r"Top-level declarations can't be declared to be 'factory'.",
+ "Top-level declarations can't be declared to be 'factory'.",
correction: "Try removing the keyword 'factory'.");
const ParserErrorCode _FIELD_INITIALIZED_OUTSIDE_DECLARING_CLASS = ParserErrorCode(
'FIELD_INITIALIZED_OUTSIDE_DECLARING_CLASS',
- r"A field can only be initialized in its declaring class",
+ "A field can only be initialized in its declaring class",
correction:
"Try passing a value into the superclass constructor, or moving the initialization into the constructor body.");
const ParserErrorCode _FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR = ParserErrorCode(
'FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR',
- r"Field formal parameters can only be used in a constructor.",
+ "Field formal parameters can only be used in a constructor.",
correction: "Try removing 'this.'.");
const ParserErrorCode _FINAL_AND_COVARIANT = ParserErrorCode(
'FINAL_AND_COVARIANT',
- r"Members can't be declared to be both 'final' and 'covariant'.",
+ "Members can't be declared to be both 'final' and 'covariant'.",
correction: "Try removing either the 'final' or 'covariant' keyword.");
const ParserErrorCode _FINAL_AND_COVARIANT_LATE_WITH_INITIALIZER = ParserErrorCode(
'FINAL_AND_COVARIANT_LATE_WITH_INITIALIZER',
- r"Members marked 'late' with an initializer can't be declared to be both 'final' and 'covariant'.",
+ "Members marked 'late' with an initializer can't be declared to be both 'final' and 'covariant'.",
correction:
"Try removing either the 'final' or 'covariant' keyword, or removing the initializer.");
const ParserErrorCode _FINAL_AND_VAR = ParserErrorCode(
- 'FINAL_AND_VAR', r"Members can't be declared to be both 'final' and 'var'.",
+ 'FINAL_AND_VAR', "Members can't be declared to be both 'final' and 'var'.",
correction: "Try removing the keyword 'var'.");
const ParserErrorCode _GETTER_CONSTRUCTOR = ParserErrorCode(
- 'GETTER_CONSTRUCTOR', r"Constructors can't be a getter.",
+ 'GETTER_CONSTRUCTOR', "Constructors can't be a getter.",
correction: "Try removing 'get'.");
const ParserErrorCode _ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE = ParserErrorCode(
'ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE',
- r"Illegal assignment to non-assignable expression.");
+ "Illegal assignment to non-assignable expression.");
const ParserErrorCode _IMPLEMENTS_BEFORE_EXTENDS = ParserErrorCode(
'IMPLEMENTS_BEFORE_EXTENDS',
- r"The extends clause must be before the implements clause.",
+ "The extends clause must be before the implements clause.",
correction: "Try moving the extends clause before the implements clause.");
const ParserErrorCode _IMPLEMENTS_BEFORE_ON = ParserErrorCode(
'IMPLEMENTS_BEFORE_ON',
- r"The on clause must be before the implements clause.",
+ "The on clause must be before the implements clause.",
correction: "Try moving the on clause before the implements clause.");
const ParserErrorCode _IMPLEMENTS_BEFORE_WITH = ParserErrorCode(
'IMPLEMENTS_BEFORE_WITH',
- r"The with clause must be before the implements clause.",
+ "The with clause must be before the implements clause.",
correction: "Try moving the with clause before the implements clause.");
const ParserErrorCode _IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE = ParserErrorCode(
'IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE',
- r"Import directives must precede part directives.",
+ "Import directives must precede part directives.",
correction: "Try moving the import directives before the part directives.");
const ParserErrorCode _INITIALIZED_VARIABLE_IN_FOR_EACH = ParserErrorCode(
'INITIALIZED_VARIABLE_IN_FOR_EACH',
- r"The loop variable in a for-each loop can't be initialized.",
+ "The loop variable in a for-each loop can't be initialized.",
correction:
"Try removing the initializer, or using a different kind of loop.");
const ParserErrorCode _INVALID_AWAIT_IN_FOR = ParserErrorCode(
'INVALID_AWAIT_IN_FOR',
- r"The keyword 'await' isn't allowed for a normal 'for' statement.",
+ "The keyword 'await' isn't allowed for a normal 'for' statement.",
correction: "Try removing the keyword, or use a for-each statement.");
const ParserErrorCode _INVALID_CONSTRUCTOR_NAME = ParserErrorCode(
'INVALID_CONSTRUCTOR_NAME',
- r"The name of a constructor must match the name of the enclosing class.");
+ "The name of a constructor must match the name of the enclosing class.");
const ParserErrorCode _INVALID_HEX_ESCAPE = ParserErrorCode(
'INVALID_HEX_ESCAPE',
- r"An escape sequence starting with '\x' must be followed by 2 hexadecimal digits.");
+ "An escape sequence starting with '\\x' must be followed by 2 hexadecimal digits.");
const ParserErrorCode _INVALID_INITIALIZER = ParserErrorCode(
- 'INVALID_INITIALIZER', r"Not a valid initializer.",
+ 'INVALID_INITIALIZER', "Not a valid initializer.",
correction: "To initialize a field, use the syntax 'name = value'.");
const ParserErrorCode _INVALID_OPERATOR = ParserErrorCode(
- 'INVALID_OPERATOR', r"The string '{0}' isn't a user-definable operator.");
+ 'INVALID_OPERATOR', "The string '{0}' isn't a user-definable operator.");
const ParserErrorCode _INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER =
ParserErrorCode('INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER',
- r"The operator '?.' cannot be used with 'super' because 'super' cannot be null.",
+ "The operator '?.' cannot be used with 'super' because 'super' cannot be null.",
correction: "Try replacing '?.' with '.'");
const ParserErrorCode _INVALID_SUPER_IN_INITIALIZER = ParserErrorCode(
'INVALID_SUPER_IN_INITIALIZER',
- r"Can only use 'super' in an initializer for calling the superclass constructor (e.g. 'super()' or 'super.namedConstructor()')");
+ "Can only use 'super' in an initializer for calling the superclass constructor (e.g. 'super()' or 'super.namedConstructor()')");
const ParserErrorCode _INVALID_THIS_IN_INITIALIZER = ParserErrorCode(
'INVALID_THIS_IN_INITIALIZER',
- r"Can only use 'this' in an initializer for field initialization (e.g. 'this.x = something') and constructor redirection (e.g. 'this()' or 'this.namedConstructor())");
+ "Can only use 'this' in an initializer for field initialization (e.g. 'this.x = something') and constructor redirection (e.g. 'this()' or 'this.namedConstructor())");
const ParserErrorCode _INVALID_UNICODE_ESCAPE = ParserErrorCode(
'INVALID_UNICODE_ESCAPE',
- r"An escape sequence starting with '\u' must be followed by 4 hexadecimal digits or from 1 to 6 digits between '{' and '}'.");
+ "An escape sequence starting with '\\u' must be followed by 4 hexadecimal digits or from 1 to 6 digits between '{' and '}'.");
const ParserErrorCode _INVALID_USE_OF_COVARIANT_IN_EXTENSION = ParserErrorCode(
'INVALID_USE_OF_COVARIANT_IN_EXTENSION',
- r"Can't have modifier '{0}' in an extension.",
+ "Can't have modifier '{0}' in an extension.",
correction: "Try removing '{0}'.",
hasPublishedDocs: true);
const ParserErrorCode _LIBRARY_DIRECTIVE_NOT_FIRST = ParserErrorCode(
'LIBRARY_DIRECTIVE_NOT_FIRST',
- r"The library directive must appear before all other directives.",
+ "The library directive must appear before all other directives.",
correction:
"Try moving the library directive before any other directives.");
const ParserErrorCode _LITERAL_WITH_CLASS = ParserErrorCode(
- 'LITERAL_WITH_CLASS', r"A {0} literal can't be prefixed by '{1}'.",
+ 'LITERAL_WITH_CLASS', "A {0} literal can't be prefixed by '{1}'.",
correction: "Try removing '{1}'");
const ParserErrorCode _LITERAL_WITH_CLASS_AND_NEW = ParserErrorCode(
'LITERAL_WITH_CLASS_AND_NEW',
- r"A {0} literal can't be prefixed by 'new {1}'.",
+ "A {0} literal can't be prefixed by 'new {1}'.",
correction: "Try removing 'new' and '{1}'");
const ParserErrorCode _LITERAL_WITH_NEW = ParserErrorCode(
- 'LITERAL_WITH_NEW', r"A literal can't be prefixed by 'new'.",
+ 'LITERAL_WITH_NEW', "A literal can't be prefixed by 'new'.",
correction: "Try removing 'new'");
const ParserErrorCode _MEMBER_WITH_CLASS_NAME = ParserErrorCode(
'MEMBER_WITH_CLASS_NAME',
- r"A class member can't have the same name as the enclosing class.",
+ "A class member can't have the same name as the enclosing class.",
correction: "Try renaming the member.");
const ParserErrorCode _MISSING_ASSIGNABLE_SELECTOR = ParserErrorCode(
'MISSING_ASSIGNABLE_SELECTOR',
- r"Missing selector such as '.identifier' or '[0]'.",
+ "Missing selector such as '.identifier' or '[0]'.",
correction: "Try adding a selector.");
const ParserErrorCode _MISSING_ASSIGNMENT_IN_INITIALIZER = ParserErrorCode(
'MISSING_ASSIGNMENT_IN_INITIALIZER',
- r"Expected an assignment after the field name.",
+ "Expected an assignment after the field name.",
correction: "To initialize a field, use the syntax 'name = value'.");
const ParserErrorCode _MISSING_CATCH_OR_FINALLY = ParserErrorCode(
'MISSING_CATCH_OR_FINALLY',
- r"A try block must be followed by an 'on', 'catch', or 'finally' clause.",
+ "A try block must be followed by an 'on', 'catch', or 'finally' clause.",
correction:
"Try adding either a catch or finally clause, or remove the try statement.");
const ParserErrorCode _MISSING_CONST_FINAL_VAR_OR_TYPE = ParserErrorCode(
'MISSING_CONST_FINAL_VAR_OR_TYPE',
- r"Variables must be declared using the keywords 'const', 'final', 'var' or a type name.",
+ "Variables must be declared using the keywords 'const', 'final', 'var' or a type name.",
correction:
"Try adding the name of the type of the variable or the keyword 'var'.");
const ParserErrorCode _MISSING_EXPRESSION_IN_THROW = ParserErrorCode(
- 'MISSING_EXPRESSION_IN_THROW', r"Missing expression after 'throw'.",
+ 'MISSING_EXPRESSION_IN_THROW', "Missing expression after 'throw'.",
correction:
"Add an expression after 'throw' or use 'rethrow' to throw a caught exception");
const ParserErrorCode _MISSING_INITIALIZER =
- ParserErrorCode('MISSING_INITIALIZER', r"Expected an initializer.");
+ ParserErrorCode('MISSING_INITIALIZER', "Expected an initializer.");
const ParserErrorCode _MISSING_KEYWORD_OPERATOR = ParserErrorCode(
'MISSING_KEYWORD_OPERATOR',
- r"Operator declarations must be preceded by the keyword 'operator'.",
+ "Operator declarations must be preceded by the keyword 'operator'.",
correction: "Try adding the keyword 'operator'.");
const ParserErrorCode _MISSING_PREFIX_IN_DEFERRED_IMPORT = ParserErrorCode(
'MISSING_PREFIX_IN_DEFERRED_IMPORT',
- r"Deferred imports should have a prefix.",
+ "Deferred imports should have a prefix.",
correction: "Try adding a prefix to the import by adding an 'as' clause.");
const ParserErrorCode _MISSING_STATEMENT =
- ParserErrorCode('MISSING_STATEMENT', r"Expected a statement.");
+ ParserErrorCode('MISSING_STATEMENT', "Expected a statement.");
const ParserErrorCode _MIXIN_DECLARES_CONSTRUCTOR = ParserErrorCode(
- 'MIXIN_DECLARES_CONSTRUCTOR', r"Mixins can't declare constructors.");
+ 'MIXIN_DECLARES_CONSTRUCTOR', "Mixins can't declare constructors.");
const ParserErrorCode _MODIFIER_OUT_OF_ORDER = ParserErrorCode(
'MODIFIER_OUT_OF_ORDER',
- r"The modifier '{0}' should be before the modifier '{1}'.",
+ "The modifier '{0}' should be before the modifier '{1}'.",
correction: "Try re-ordering the modifiers.");
const ParserErrorCode _MULTIPLE_EXTENDS_CLAUSES = ParserErrorCode(
'MULTIPLE_EXTENDS_CLAUSES',
- r"Each class definition can have at most one extends clause.",
+ "Each class definition can have at most one extends clause.",
correction:
"Try choosing one superclass and define your class to implement (or mix in) the others.");
const ParserErrorCode _MULTIPLE_LIBRARY_DIRECTIVES = ParserErrorCode(
'MULTIPLE_LIBRARY_DIRECTIVES',
- r"Only one library directive may be declared in a file.",
+ "Only one library directive may be declared in a file.",
correction: "Try removing all but one of the library directives.");
const ParserErrorCode _MULTIPLE_ON_CLAUSES = ParserErrorCode(
'MULTIPLE_ON_CLAUSES',
- r"Each mixin definition can have at most one on clause.",
+ "Each mixin definition can have at most one on clause.",
correction: "Try combining all of the on clauses into a single clause.");
const ParserErrorCode _MULTIPLE_PART_OF_DIRECTIVES = ParserErrorCode(
'MULTIPLE_PART_OF_DIRECTIVES',
- r"Only one part-of directive may be declared in a file.",
+ "Only one part-of directive may be declared in a file.",
correction: "Try removing all but one of the part-of directives.");
const ParserErrorCode _MULTIPLE_VARIANCE_MODIFIERS = ParserErrorCode(
'MULTIPLE_VARIANCE_MODIFIERS',
- r"Each type parameter can have at most one variance modifier.",
+ "Each type parameter can have at most one variance modifier.",
correction: "Use at most one of the 'in', 'out', or 'inout' modifiers.");
const ParserErrorCode _MULTIPLE_WITH_CLAUSES = ParserErrorCode(
'MULTIPLE_WITH_CLAUSES',
- r"Each class definition can have at most one with clause.",
+ "Each class definition can have at most one with clause.",
correction: "Try combining all of the with clauses into a single clause.");
const ParserErrorCode _NATIVE_CLAUSE_SHOULD_BE_ANNOTATION = ParserErrorCode(
'NATIVE_CLAUSE_SHOULD_BE_ANNOTATION',
- r"Native clause in this form is deprecated.",
+ "Native clause in this form is deprecated.",
correction:
"Try removing this native clause and adding @native() or @native('native-name') before the declaration.");
const ParserErrorCode _NULL_AWARE_CASCADE_OUT_OF_ORDER = ParserErrorCode(
'NULL_AWARE_CASCADE_OUT_OF_ORDER',
- r"The '?..' cascade operator must be first in the cascade sequence.",
+ "The '?..' cascade operator must be first in the cascade sequence.",
correction:
"Try moving the '?..' operator to be the first cascade operator in the sequence.");
const ParserErrorCode _PREFIX_AFTER_COMBINATOR = ParserErrorCode(
'PREFIX_AFTER_COMBINATOR',
- r"The prefix ('as' clause) should come before any show/hide combinators.",
+ "The prefix ('as' clause) should come before any show/hide combinators.",
correction: "Try moving the prefix before the combinators.");
const ParserErrorCode _REDIRECTING_CONSTRUCTOR_WITH_BODY = ParserErrorCode(
'REDIRECTING_CONSTRUCTOR_WITH_BODY',
- r"Redirecting constructors can't have a body.",
+ "Redirecting constructors can't have a body.",
correction:
"Try removing the body, or not making this a redirecting constructor.");
const ParserErrorCode _REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR = ParserErrorCode(
'REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR',
- r"Only factory constructor can specify '=' redirection.",
+ "Only factory constructor can specify '=' redirection.",
correction:
"Try making this a factory constructor, or remove the redirection.");
const ParserErrorCode _SETTER_CONSTRUCTOR = ParserErrorCode(
- 'SETTER_CONSTRUCTOR', r"Constructors can't be a setter.",
+ 'SETTER_CONSTRUCTOR', "Constructors can't be a setter.",
correction: "Try removing 'set'.");
-const ParserErrorCode _STACK_OVERFLOW = ParserErrorCode('STACK_OVERFLOW',
- r"The file has too many nested expressions or statements.",
+const ParserErrorCode _STACK_OVERFLOW = ParserErrorCode(
+ 'STACK_OVERFLOW', "The file has too many nested expressions or statements.",
correction: "Try simplifying the code.");
const ParserErrorCode _STATIC_CONSTRUCTOR = ParserErrorCode(
- 'STATIC_CONSTRUCTOR', r"Constructors can't be static.",
+ 'STATIC_CONSTRUCTOR', "Constructors can't be static.",
correction: "Try removing the keyword 'static'.");
const ParserErrorCode _STATIC_OPERATOR = ParserErrorCode(
- 'STATIC_OPERATOR', r"Operators can't be static.",
+ 'STATIC_OPERATOR', "Operators can't be static.",
correction: "Try removing the keyword 'static'.");
const ParserErrorCode _SWITCH_HAS_CASE_AFTER_DEFAULT_CASE = ParserErrorCode(
'SWITCH_HAS_CASE_AFTER_DEFAULT_CASE',
- r"The default case should be the last case in a switch statement.",
+ "The default case should be the last case in a switch statement.",
correction: "Try moving the default case after the other case clauses.");
const ParserErrorCode _SWITCH_HAS_MULTIPLE_DEFAULT_CASES = ParserErrorCode(
'SWITCH_HAS_MULTIPLE_DEFAULT_CASES',
- r"The 'default' case can only be declared once.",
+ "The 'default' case can only be declared once.",
correction: "Try removing all but one default case.");
const ParserErrorCode _TOP_LEVEL_OPERATOR = ParserErrorCode(
- 'TOP_LEVEL_OPERATOR', r"Operators must be declared within a class.",
+ 'TOP_LEVEL_OPERATOR', "Operators must be declared within a class.",
correction:
"Try removing the operator, moving it to a class, or converting it to be a function.");
const ParserErrorCode _TYPEDEF_IN_CLASS = ParserErrorCode(
- 'TYPEDEF_IN_CLASS', r"Typedefs can't be declared inside classes.",
+ 'TYPEDEF_IN_CLASS', "Typedefs can't be declared inside classes.",
correction: "Try moving the typedef to the top-level.");
const ParserErrorCode _TYPE_ARGUMENTS_ON_TYPE_VARIABLE = ParserErrorCode(
'TYPE_ARGUMENTS_ON_TYPE_VARIABLE',
- r"Can't use type arguments with type variable '{0}'.",
+ "Can't use type arguments with type variable '{0}'.",
correction: "Try removing the type arguments.");
const ParserErrorCode _TYPE_BEFORE_FACTORY = ParserErrorCode(
- 'TYPE_BEFORE_FACTORY', r"Factory constructors cannot have a return type.",
+ 'TYPE_BEFORE_FACTORY', "Factory constructors cannot have a return type.",
correction: "Try removing the type appearing before 'factory'.");
const ParserErrorCode _TYPE_PARAMETER_ON_CONSTRUCTOR = ParserErrorCode(
- 'TYPE_PARAMETER_ON_CONSTRUCTOR',
- r"Constructors can't have type parameters.",
+ 'TYPE_PARAMETER_ON_CONSTRUCTOR', "Constructors can't have type parameters.",
correction: "Try removing the type parameters.");
const ParserErrorCode _VAR_AND_TYPE = ParserErrorCode('VAR_AND_TYPE',
- r"Variables can't be declared using both 'var' and a type name.",
+ "Variables can't be declared using both 'var' and a type name.",
correction: "Try removing 'var.'");
const ParserErrorCode _VAR_AS_TYPE_NAME = ParserErrorCode(
- 'VAR_AS_TYPE_NAME', r"The keyword 'var' can't be used as a type name.");
+ 'VAR_AS_TYPE_NAME', "The keyword 'var' can't be used as a type name.");
const ParserErrorCode _VAR_RETURN_TYPE = ParserErrorCode(
- 'VAR_RETURN_TYPE', r"The return type can't be 'var'.",
+ 'VAR_RETURN_TYPE', "The return type can't be 'var'.",
correction:
"Try removing the keyword 'var', or replacing it with the name of the return type.");
const ParserErrorCode _VOID_WITH_TYPE_ARGUMENTS = ParserErrorCode(
- 'VOID_WITH_TYPE_ARGUMENTS', r"Type 'void' can't have type arguments.",
+ 'VOID_WITH_TYPE_ARGUMENTS', "Type 'void' can't have type arguments.",
correction: "Try removing the type arguments.");
const ParserErrorCode _WITH_BEFORE_EXTENDS = ParserErrorCode(
- 'WITH_BEFORE_EXTENDS',
- r"The extends clause must be before the with clause.",
+ 'WITH_BEFORE_EXTENDS', "The extends clause must be before the with clause.",
correction: "Try moving the extends clause before the with clause.");
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index 4cd3002..0754988 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -3049,7 +3049,7 @@
/**
* No parameters.
*/
- /* #### Description
+ // #### Description
//
// The analyzer produces this diagnostic when a named parameter has both the
// `required` modifier and a default value. If the parameter is required, then
@@ -3077,7 +3077,7 @@
//
// ```dart
// void log({String message = 'no message'}) {}
- // ``` */
+ // ```
static const CompileTimeErrorCode DEFAULT_VALUE_ON_REQUIRED_PARAMETER =
CompileTimeErrorCode('DEFAULT_VALUE_ON_REQUIRED_PARAMETER',
"Required named parameters can't have a default value.",
@@ -8468,7 +8468,7 @@
// #### Example
//
// The following code produces this diagnostic because the mixin `M` requires
- //that the class to which it's applied be a subclass of `A`, but `Object`
+ // that the class to which it's applied be a subclass of `A`, but `Object`
// isn't a subclass of `A`:
//
// ```dart
diff --git a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
index 9aa5e8e..a05f61d 100644
--- a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
+++ b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
@@ -365,6 +365,7 @@
int operator -();
int operator <<(int shiftAmount);
int operator >>(int shiftAmount);
+ int operator >>>(int shiftAmount);
int operator ^(int other);
int operator |(int other);
int operator ~();
diff --git a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
index 7b42573..9facdf6 100644
--- a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
+++ b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
@@ -177,6 +177,120 @@
);
}
+ test_identical_typeLiteral_explicitTypeArgs_differentTypeArgs() async {
+ await resolveTestCode('''
+class C<T> {}
+const c = identical(C<int>, C<String>);
+''');
+ expect(
+ _evaluateConstant('c'),
+ _boolValue(false),
+ );
+ }
+
+ test_identical_typeLiteral_explicitTypeArgs_differentTypes() async {
+ await resolveTestCode('''
+class C<T> {}
+class D<T> {}
+const c = identical(C<int>, D<int>);
+''');
+ expect(
+ _evaluateConstant('c'),
+ _boolValue(false),
+ );
+ }
+
+ test_identical_typeLiteral_explicitTypeArgs_sameType() async {
+ await resolveTestCode('''
+class C<T> {}
+const c = identical(C<int>, C<int>);
+''');
+ expect(
+ _evaluateConstant('c'),
+ _boolValue(true),
+ );
+ }
+
+ test_identical_typeLiteral_explicitTypeArgs_simpleTypeAlias() async {
+ await resolveTestCode('''
+class C<T> {}
+typedef TC = C<int>;
+const c = identical(C<int>, TC);
+''');
+ expect(
+ _evaluateConstant('c'),
+ _boolValue(true),
+ );
+ }
+
+ test_identical_typeLiteral_explicitTypeArgs_typeAlias() async {
+ await resolveTestCode('''
+class C<T> {}
+typedef TC<T> = C<T>;
+const c = identical(C<int>, TC<int>);
+''');
+ expect(
+ _evaluateConstant('c'),
+ _boolValue(true),
+ );
+ }
+
+ test_identical_typeLiteral_explicitTypeArgs_typeAlias_differentTypeArgs() async {
+ await resolveTestCode('''
+class C<T> {}
+typedef TC<T> = C<T>;
+const c = identical(C<int>, TC<String>);
+''');
+ expect(
+ _evaluateConstant('c'),
+ _boolValue(false),
+ );
+ }
+
+ test_identical_typeLiteral_explicitTypeArgs_typeAlias_implicitTypeArgs() async {
+ await resolveTestCode('''
+class C<T> {}
+typedef TC<T> = C<T>;
+const c = identical(C<dynamic>, TC);
+''');
+ expect(
+ _evaluateConstant('c'),
+ _boolValue(true),
+ );
+ }
+
+ test_identical_typeLiteral_explicitTypeArgs_typeAlias_implicitTypeArgs_bound() async {
+ await resolveTestCode('''
+class C<T extends num> {}
+typedef TC<T extends num> = C<T>;
+const c = identical(C<num>, TC);
+''');
+ expect(
+ _evaluateConstant('c'),
+ _boolValue(true),
+ );
+ }
+
+ test_identical_typeLiteral_simple_differentTypes() async {
+ await resolveTestCode('''
+const c = identical(int, String);
+''');
+ expect(
+ _evaluateConstant('c'),
+ _boolValue(false),
+ );
+ }
+
+ test_identical_typeLiteral_simple_sameType() async {
+ await resolveTestCode('''
+const c = identical(int, int);
+''');
+ expect(
+ _evaluateConstant('c'),
+ _boolValue(true),
+ );
+ }
+
test_visitAsExpression_potentialConstType() async {
await assertNoErrorsInCode('''
const num three = 3;
diff --git a/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart
index 5be34e4..47869ef 100644
--- a/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart
@@ -273,7 +273,7 @@
''');
assertTypeArgumentTypes(findNode.methodInvocation('f()'),
- [typeToStringWithNullability ? 'int' : 'num']);
+ [typeStringByNullability(nullable: 'int', legacy: 'num')]);
}
test_minus_int_double() async {
@@ -320,7 +320,7 @@
''');
assertTypeArgumentTypes(findNode.methodInvocation('f()'),
- [typeToStringWithNullability ? 'int' : 'num']);
+ [typeStringByNullability(nullable: 'int', legacy: 'num')]);
}
test_mod_int_double() async {
@@ -421,7 +421,7 @@
''');
assertTypeArgumentTypes(findNode.methodInvocation('f()'),
- [typeToStringWithNullability ? 'double' : 'num']);
+ [typeStringByNullability(nullable: 'double', legacy: 'num')]);
}
test_plus_int_context_int() async {
@@ -434,7 +434,7 @@
''');
assertTypeArgumentTypes(findNode.methodInvocation('f()'),
- [typeToStringWithNullability ? 'int' : 'num']);
+ [typeStringByNullability(nullable: 'int', legacy: 'num')]);
}
test_plus_int_context_int_target_rewritten() async {
@@ -447,7 +447,7 @@
''');
assertTypeArgumentTypes(findNode.methodInvocation('f()'),
- [typeToStringWithNullability ? 'int' : 'num']);
+ [typeStringByNullability(nullable: 'int', legacy: 'num')]);
}
test_plus_int_context_int_via_extension_explicit() async {
@@ -774,7 +774,7 @@
''');
assertTypeArgumentTypes(findNode.methodInvocation('f()'),
- [typeToStringWithNullability ? 'int' : 'num']);
+ [typeStringByNullability(nullable: 'int', legacy: 'num')]);
}
test_star_int_double() async {
diff --git a/pkg/analyzer/test/src/dart/resolution/index_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/index_expression_test.dart
index 20e87bf..c02261d 100644
--- a/pkg/analyzer/test/src/dart/resolution/index_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/index_expression_test.dart
@@ -189,7 +189,7 @@
numPlusElement,
isLegacy: isLegacyLibrary,
),
- type: typeToStringWithNullability ? 'double' : 'num',
+ type: typeStringByNullability(nullable: 'double', legacy: 'num'),
);
assertParameterElement(
assignment.rightHandSide,
diff --git a/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart b/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
index f9f50e2..17bac73 100644
--- a/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
@@ -33,9 +33,9 @@
''');
assertTypeArgumentTypes(findNode.methodInvocation('f(),'),
- [typeToStringWithNullability ? 'double' : 'num']);
+ [typeStringByNullability(nullable: 'double', legacy: 'num')]);
assertTypeArgumentTypes(findNode.methodInvocation('f())'),
- [typeToStringWithNullability ? 'double' : 'num']);
+ [typeStringByNullability(nullable: 'double', legacy: 'num')]);
}
test_clamp_double_context_int() async {
@@ -79,7 +79,8 @@
elementMatcher(numElement.getMethod('clamp'),
isLegacy: isLegacyLibrary),
'num Function(num, num)',
- expectedType: typeToStringWithNullability ? 'double' : 'num');
+ expectedType:
+ typeStringByNullability(nullable: 'double', legacy: 'num'));
}
test_clamp_double_double_int() async {
@@ -154,9 +155,9 @@
''');
assertTypeArgumentTypes(findNode.methodInvocation('f(),'),
- [typeToStringWithNullability ? 'int' : 'num']);
+ [typeStringByNullability(nullable: 'int', legacy: 'num')]);
assertTypeArgumentTypes(findNode.methodInvocation('f())'),
- [typeToStringWithNullability ? 'int' : 'num']);
+ [typeStringByNullability(nullable: 'int', legacy: 'num')]);
}
test_clamp_int_context_none() async {
@@ -288,7 +289,7 @@
elementMatcher(numElement.getMethod('clamp'),
isLegacy: isLegacyLibrary),
'num Function(num, num)',
- expectedType: typeToStringWithNullability ? 'int' : 'num');
+ expectedType: typeStringByNullability(nullable: 'int', legacy: 'num'));
}
test_clamp_int_int_int_from_cascade() async {
@@ -307,7 +308,7 @@
elementMatcher(numElement.getMethod('clamp'),
isLegacy: isLegacyLibrary),
'num Function(num, num)',
- expectedType: typeToStringWithNullability ? 'int' : 'num');
+ expectedType: typeStringByNullability(nullable: 'int', legacy: 'num'));
}
test_clamp_int_int_int_via_extension_explicit() async {
@@ -377,7 +378,8 @@
assertMethodInvocation(
findNode.methodInvocation('clamp'), isNull, 'dynamic',
- expectedType: typeToStringWithNullability ? 'Never' : 'dynamic');
+ expectedType:
+ typeStringByNullability(nullable: 'Never', legacy: 'dynamic'));
}
test_clamp_other_context_int() async {
@@ -2217,7 +2219,7 @@
''');
assertTypeArgumentTypes(findNode.methodInvocation('f()'),
- [typeToStringWithNullability ? 'int' : 'num']);
+ [typeStringByNullability(nullable: 'int', legacy: 'num')]);
}
test_remainder_int_context_int_target_rewritten() async {
@@ -2230,7 +2232,7 @@
''');
assertTypeArgumentTypes(findNode.methodInvocation('f()'),
- [typeToStringWithNullability ? 'int' : 'num']);
+ [typeStringByNullability(nullable: 'int', legacy: 'num')]);
}
test_remainder_int_context_int_via_extension_explicit() async {
@@ -2273,7 +2275,8 @@
elementMatcher(numElement.getMethod('remainder'),
isLegacy: isLegacyLibrary),
'num Function(num)',
- expectedType: typeToStringWithNullability ? 'double' : 'num');
+ expectedType:
+ typeStringByNullability(nullable: 'double', legacy: 'num'));
}
test_remainder_int_int() async {
@@ -2288,7 +2291,7 @@
elementMatcher(numElement.getMethod('remainder'),
isLegacy: isLegacyLibrary),
'num Function(num)',
- expectedType: typeToStringWithNullability ? 'int' : 'num');
+ expectedType: typeStringByNullability(nullable: 'int', legacy: 'num'));
}
test_remainder_int_int_target_rewritten() async {
@@ -2303,7 +2306,7 @@
elementMatcher(numElement.getMethod('remainder'),
isLegacy: isLegacyLibrary),
'num Function(num)',
- expectedType: typeToStringWithNullability ? 'int' : 'num');
+ expectedType: typeStringByNullability(nullable: 'int', legacy: 'num'));
}
test_remainder_other_context_int_via_extension_explicit() async {
diff --git a/pkg/analyzer/test/src/diagnostics/sdk_version_gt_gt_gt_operator_test.dart b/pkg/analyzer/test/src/diagnostics/sdk_version_gt_gt_gt_operator_test.dart
index ec6150f..fd70b98 100644
--- a/pkg/analyzer/test/src/diagnostics/sdk_version_gt_gt_gt_operator_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/sdk_version_gt_gt_gt_operator_test.dart
@@ -22,23 +22,16 @@
'${ExperimentStatus.currentVersion.minor}';
test_const_equals() async {
- // TODO(brianwilkerson) Add '>>>' to MockSdk and remove the code
- // UNDEFINED_OPERATOR when triple_shift is enabled by default.
await verifyVersion('2.5.0', '''
const a = 42 >>> 3;
-''', expectedErrors: [
- error(CompileTimeErrorCode.UNDEFINED_OPERATOR, 13, 3),
- ]);
+''');
}
test_const_lessThan() async {
- // TODO(brianwilkerson) Add '>>>' to MockSdk and remove the code
- // UNDEFINED_OPERATOR when triple_shift is enabled by default.
await verifyVersion('2.2.0', '''
const a = 42 >>> 3;
''', expectedErrors: [
error(HintCode.SDK_VERSION_GT_GT_GT_OPERATOR, 13, 3),
- error(CompileTimeErrorCode.UNDEFINED_OPERATOR, 13, 3),
]);
}
@@ -61,23 +54,16 @@
}
test_nonConst_equals() async {
- // TODO(brianwilkerson) Add '>>>' to MockSdk and remove the code
- // UNDEFINED_OPERATOR when triple_shift is enabled by default.
await verifyVersion('2.5.0', '''
var a = 42 >>> 3;
-''', expectedErrors: [
- error(CompileTimeErrorCode.UNDEFINED_OPERATOR, 11, 3),
- ]);
+''');
}
test_nonConst_lessThan() async {
- // TODO(brianwilkerson) Add '>>>' to MockSdk and remove the code
- // UNDEFINED_OPERATOR when triple_shift is enabled by default.
await verifyVersion('2.2.0', '''
var a = 42 >>> 3;
''', expectedErrors: [
error(HintCode.SDK_VERSION_GT_GT_GT_OPERATOR, 11, 3),
- error(CompileTimeErrorCode.UNDEFINED_OPERATOR, 11, 3),
]);
}
}
diff --git a/pkg/analyzer/tool/diagnostics/diagnostics.md b/pkg/analyzer/tool/diagnostics/diagnostics.md
index 2a99024..e41c85f 100644
--- a/pkg/analyzer/tool/diagnostics/diagnostics.md
+++ b/pkg/analyzer/tool/diagnostics/diagnostics.md
@@ -3096,6 +3096,40 @@
}
{% endprettify %}
+### default_value_on_required_parameter
+
+_Required named parameters can't have a default value._
+
+#### Description
+
+The analyzer produces this diagnostic when a named parameter has both the
+`required` modifier and a default value. If the parameter is required, then
+a value for the parameter is always provided at the call sites, so the
+default value can never be used.
+
+#### Examples
+
+The following code generates this diagnostic:
+
+{% prettify dart tag=pre+code %}
+void log({required String [!message!] = 'no message'}) {}
+{% endprettify %}
+
+#### Common fixes
+
+If the parameter is really required, then remove the default value:
+
+{% prettify dart tag=pre+code %}
+void log({required String message}) {}
+{% endprettify %}
+
+If the parameter isn't always required, then remove the `required`
+modifier:
+
+{% prettify dart tag=pre+code %}
+void log({String message = 'no message'}) {}
+{% endprettify %}
+
### deferred_import_of_extension
_Imports of deferred libraries must hide all extensions._
@@ -8401,6 +8435,7 @@
#### Example
The following code produces this diagnostic because the mixin `M` requires
+that the class to which it's applied be a subclass of `A`, but `Object`
isn't a subclass of `A`:
{% prettify dart tag=pre+code %}
@@ -12172,6 +12207,60 @@
}
{% endprettify %}
+### sdk_version_gt_gt_gt_operator
+
+_The operator '>>>' wasn't supported until version 2.3.2, but this code is
+required to be able to run on earlier versions._
+
+#### Description
+
+The analyzer produces this diagnostic when the operator `>>>` is used in
+code that has an SDK constraint whose lower bound is less than 2.X.0. This
+operator wasn't supported in earlier versions, so this code won't be able
+to run against earlier versions of the SDK.
+
+#### Examples
+
+Here's an example of a pubspec that defines an SDK constraint with a lower
+bound of less than 2.X.0:
+
+```yaml
+environment:
+ sdk: '>=2.0.0 <2.4.0'
+```
+
+In the package that has that pubspec, code like the following produces this
+diagnostic:
+
+{% prettify dart tag=pre+code %}
+int x = 3 [!>>>!] 4;
+{% endprettify %}
+
+#### Common fixes
+
+If you don't need to support older versions of the SDK, then you can
+increase the SDK constraint to allow the operator to be used:
+
+```yaml
+environment:
+ sdk: '>=2.3.2 <2.4.0'
+```
+
+If you need to support older versions of the SDK, then rewrite the code to
+not use the `>>>` operator:
+
+{% prettify dart tag=pre+code %}
+int x = logicalShiftRight(3, 4);
+
+int logicalShiftRight(int leftOperand, int rightOperand) {
+ int divisor = 1 << rightOperand;
+ if (divisor == 0) {
+ return 0;
+ }
+ return leftOperand ~/ divisor;
+}
+{% endprettify %}
+
### sdk_version_is_expression_in_const_context
_The use of an is expression in a constant context wasn't supported until
diff --git a/pkg/analyzer/tool/messages/error_code_info.dart b/pkg/analyzer/tool/messages/error_code_info.dart
new file mode 100644
index 0000000..322759b
--- /dev/null
+++ b/pkg/analyzer/tool/messages/error_code_info.dart
@@ -0,0 +1,122 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+
+/// Decodes a YAML object (obtained from `pkg/front_end/messages.yaml`) into a
+/// map from error name to [ErrorCodeInfo].
+Map<String, ErrorCodeInfo> decodeCfeMessagesYaml(Map<Object?, Object?> yaml) {
+ var result = <String, ErrorCodeInfo>{};
+ for (var entry in yaml.entries) {
+ result[entry.key as String] =
+ ErrorCodeInfo.fromYaml(entry.value as Map<Object?, Object?>);
+ }
+ return result;
+}
+
+/// In-memory representation of error code information obtained from a
+/// `messages.yaml` file.
+class ErrorCodeInfo {
+ /// Pattern used by the front end to identify placeholders in error message
+ /// strings. TODO(paulberry): share this regexp (and the code for interpreting
+ /// it) between the CFE and analyzer.
+ static final RegExp _placeholderPattern =
+ RegExp("#\([-a-zA-Z0-9_]+\)(?:%\([0-9]*\)\.\([0-9]+\))?");
+
+ /// For error code information obtained from the CFE, the set of analyzer
+ /// error codes that corresponds to this error code, if any.
+ final List<String> analyzerCode;
+
+ /// `true` if diagnostics with this code have documentation for them that has
+ /// been published.
+ final bool hasPublishedDocs;
+
+ /// For error code information obtained from the CFE, the index of the error
+ /// in the analyzer's `fastaAnalyzerErrorCodes` table.
+ final int? index;
+
+ /// The template for the error message.
+ final String template;
+
+ /// If the error code has an associated tip/correction message, the template
+ /// for it.
+ final String? tip;
+
+ ErrorCodeInfo(
+ {this.analyzerCode = const [],
+ this.hasPublishedDocs = false,
+ this.index,
+ required this.template,
+ this.tip});
+
+ /// Decodes an [ErrorCodeInfo] object from its YAML representation.
+ ErrorCodeInfo.fromYaml(Map<Object?, Object?> yaml)
+ : this(
+ analyzerCode: _decodeAnalyzerCode(yaml['analyzerCode']),
+ hasPublishedDocs: yaml['hasPublishedDocs'] as bool? ?? false,
+ index: yaml['index'] as int?,
+ template: yaml['template'] as String,
+ tip: yaml['tip'] as String?);
+
+ /// Generates a dart declaration for this error code, suitable for inclusion
+ /// in the error class [className]. [errorCode] is the name of the error code
+ /// to be generated.
+ String toAnalyzerCode(String className, String errorCode) {
+ var out = StringBuffer();
+ out.writeln('$className(');
+ out.writeln("'$errorCode',");
+ final placeholderToIndexMap = _computePlaceholderToIndexMap();
+ out.writeln(json.encode(_convertTemplate(placeholderToIndexMap, template)));
+ final tip = this.tip;
+ if (tip is String) {
+ out.write(',correction: ');
+ out.writeln(json.encode(_convertTemplate(placeholderToIndexMap, tip)));
+ }
+ if (hasPublishedDocs) {
+ out.writeln(',hasPublishedDocs:true');
+ }
+ out.write(');');
+ return out.toString();
+ }
+
+ /// Given a messages.yaml entry, come up with a mapping from placeholder
+ /// patterns in its message and tip strings to their corresponding indices.
+ Map<String, int> _computePlaceholderToIndexMap() {
+ var mapping = <String, int>{};
+ for (var value in [template, tip]) {
+ if (value is! String) continue;
+ for (Match match in _placeholderPattern.allMatches(value)) {
+ // CFE supports a bunch of formatting options that we don't; make sure
+ // none of those are used.
+ if (match.group(0) != '#${match.group(1)}') {
+ throw 'Template string ${json.encode(value)} contains unsupported '
+ 'placeholder pattern ${json.encode(match.group(0))}';
+ }
+
+ mapping[match.group(0)!] ??= mapping.length;
+ }
+ }
+ return mapping;
+ }
+
+ /// Convert a CFE template string (which uses placeholders like `#string`) to
+ /// an analyzer template string (which uses placeholders like `{0}`).
+ static String _convertTemplate(
+ Map<String, int> placeholderToIndexMap, String entry) {
+ return entry.replaceAllMapped(_placeholderPattern,
+ (match) => '{${placeholderToIndexMap[match.group(0)!]}}');
+ }
+
+ static List<String> _decodeAnalyzerCode(Object? value) {
+ if (value == null) {
+ return const [];
+ } else if (value is String) {
+ return [value];
+ } else if (value is List) {
+ return [for (var s in value) s as String];
+ } else {
+ throw 'Unrecognized analyzer code: $value';
+ }
+ }
+}
diff --git a/pkg/analyzer/tool/messages/generate.dart b/pkg/analyzer/tool/messages/generate.dart
index 3747771..d9b973c 100644
--- a/pkg/analyzer/tool/messages/generate.dart
+++ b/pkg/analyzer/tool/messages/generate.dart
@@ -14,7 +14,6 @@
///
/// It is expected that 'pkg/front_end/tool/fasta generate-messages'
/// has already been successfully run.
-import 'dart:convert';
import 'dart:io';
import 'package:_fe_analyzer_shared/src/scanner/scanner.dart';
@@ -25,6 +24,8 @@
import 'package:path/path.dart';
import 'package:yaml/yaml.dart' show loadYaml;
+import 'error_code_info.dart';
+
main() async {
await GeneratedContent.generateAll(analyzerPkgPath, allTargets);
@@ -61,22 +62,17 @@
final String analyzerPkgPath =
normalize(join(pkg_root.packageRoot, 'analyzer'));
-/// Pattern used by the front end to identify placeholders in error message
-/// strings. TODO(paulberry): share this regexp (and the code for interpreting
-/// it) between the CFE and analyzer.
-final RegExp _placeholderPattern =
- RegExp("#\([-a-zA-Z0-9_]+\)(?:%\([0-9]*\)\.\([0-9]+\))?");
-
/// Return an entry containing 2 strings,
/// the name of the class containing the error and the name of the error,
/// or throw an exception if 'analyzerCode:' field is invalid.
-List<String> nameForEntry(Map entry) {
- final analyzerCode = entry['analyzerCode'];
- if (analyzerCode is String) {
- if (!analyzerCode.startsWith('ParserErrorCode.')) {
+List<String> nameForEntry(ErrorCodeInfo entry) {
+ final analyzerCode = entry.analyzerCode;
+ if (analyzerCode.length == 1) {
+ var code = analyzerCode.single;
+ if (!code.startsWith('ParserErrorCode.')) {
throw invalidAnalyzerCode;
}
- List<String> name = analyzerCode.split('.');
+ List<String> name = code.split('.');
if (name.length != 2 || name[1].isEmpty) {
throw invalidAnalyzerCode;
}
@@ -86,11 +82,11 @@
}
class _SyntacticErrorGenerator {
- final Map messagesYaml;
+ final Map<String, ErrorCodeInfo> messages;
final String errorConverterSource;
final String syntacticErrorsSource;
final String parserSource;
- final translatedEntries = <Map>[];
+ final translatedEntries = <ErrorCodeInfo>[];
final translatedFastaErrorCodes = <String>{};
final out = StringBuffer('''
//
@@ -120,18 +116,18 @@
joinAll(posix.split('lib/src/parser/parser.dart'))))
.readAsStringSync();
- return _SyntacticErrorGenerator._(messagesYaml, errorConverterSource,
- syntacticErrorsSource, parserSource);
+ return _SyntacticErrorGenerator._(decodeCfeMessagesYaml(messagesYaml),
+ errorConverterSource, syntacticErrorsSource, parserSource);
}
- _SyntacticErrorGenerator._(this.messagesYaml, this.errorConverterSource,
+ _SyntacticErrorGenerator._(this.messages, this.errorConverterSource,
this.syntacticErrorsSource, this.parserSource);
void checkForManualChanges() {
// Check for ParserErrorCodes that could be removed from
// error_converter.dart now that those ParserErrorCodes are auto generated.
int converterCount = 0;
- for (Map entry in translatedEntries) {
+ for (ErrorCodeInfo entry in translatedEntries) {
final name = nameForEntry(entry);
final errorCode = name[1];
if (errorConverterSource.contains('"$errorCode"')) {
@@ -151,7 +147,7 @@
// Check that the public ParserErrorCodes have been updated
// to reference the generated codes.
int publicCount = 0;
- for (Map entry in translatedEntries) {
+ for (ErrorCodeInfo entry in translatedEntries) {
final name = nameForEntry(entry);
final errorCode = name[1];
if (!syntacticErrorsSource.contains(' _$errorCode')) {
@@ -176,7 +172,7 @@
void generateErrorCodes() {
final sortedErrorCodes = <String>[];
- final entryMap = <String, Map>{};
+ final entryMap = <String, ErrorCodeInfo>{};
for (var entry in translatedEntries) {
final name = nameForEntry(entry);
final errorCode = name[1];
@@ -193,28 +189,14 @@
final className = nameForEntry(entry)[0];
out.writeln();
out.writeln('const $className _$errorCode =');
- out.writeln('$className(');
- out.writeln("'$errorCode',");
- final placeholderToIndexMap = _computePlaceholderToIndexMap(entry);
- out.writeln(
- 'r"${_convertTemplate(placeholderToIndexMap, entry['template'])}"');
- final tip = entry['tip'];
- if (tip is String) {
- out.writeln(
- ',correction: "${_convertTemplate(placeholderToIndexMap, tip)}"');
- }
- final hasPublishedDocs = entry['hasPublishedDocs'];
- if (hasPublishedDocs is bool && hasPublishedDocs) {
- out.writeln(',hasPublishedDocs:true');
- }
- out.writeln(');');
+ out.writeln(entry.toAnalyzerCode(className, errorCode));
}
}
void generateFastaAnalyzerErrorCodeList() {
- final sorted = List<Map?>.filled(translatedEntries.length, null);
+ final sorted = List<ErrorCodeInfo?>.filled(translatedEntries.length, null);
for (var entry in translatedEntries) {
- var index = entry['index'];
+ var index = entry.index;
if (index is int && index >= 1 && index <= sorted.length) {
if (sorted[index - 1] == null) {
sorted[index - 1] = entry;
@@ -232,15 +214,14 @@
}
void generateFormatCode() {
- messagesYaml.forEach((name, entry) {
- if (entry is Map) {
- if (entry['index'] is int) {
- if (entry['analyzerCode'] is String) {
- translatedFastaErrorCodes.add(name);
- translatedEntries.add(entry);
- } else {
- throw invalidAnalyzerCode;
- }
+ messages.forEach((name, entry) {
+ if (entry.index != null) {
+ // TODO(paulberry): handle multiple analyzer codes
+ if (entry.analyzerCode.length == 1) {
+ translatedFastaErrorCodes.add(name);
+ translatedEntries.add(entry);
+ } else {
+ throw invalidAnalyzerCode;
}
}
});
@@ -258,14 +239,14 @@
}
}
- String messageFromEntryTemplate(Map entry) {
- String template = entry['template'];
+ String messageFromEntryTemplate(ErrorCodeInfo entry) {
+ String template = entry.template;
String message = template.replaceAll(RegExp(r'#\w+'), '');
return message;
}
// Remove entries that have already been translated
- for (Map entry in translatedEntries) {
+ for (ErrorCodeInfo entry in translatedEntries) {
messageToName.remove(messageFromEntryTemplate(entry));
}
@@ -276,14 +257,12 @@
// List the ParserErrorCodes that could easily be auto generated
// but have not been already.
final analyzerToFasta = <String, List<String>>{};
- messagesYaml.forEach((fastaName, entry) {
- if (entry is Map) {
- final analyzerName = messageToName[messageFromEntryTemplate(entry)];
- if (analyzerName != null) {
- analyzerToFasta
- .putIfAbsent(analyzerName, () => <String>[])
- .add(fastaName);
- }
+ messages.forEach((fastaName, entry) {
+ final analyzerName = messageToName[messageFromEntryTemplate(entry)];
+ if (analyzerName != null) {
+ analyzerToFasta
+ .putIfAbsent(analyzerName, () => <String>[])
+ .add(fastaName);
}
});
if (analyzerToFasta.isNotEmpty) {
@@ -332,11 +311,12 @@
for (String fastaErrorCode in sorted) {
String analyzerCode = '';
String template = '';
- var entry = messagesYaml[fastaErrorCode];
- if (entry is Map) {
- if (entry['index'] is! int && entry['analyzerCode'] is String) {
- analyzerCode = entry['analyzerCode'];
- template = entry['template'];
+ var entry = messages[fastaErrorCode];
+ if (entry != null) {
+ // TODO(paulberry): handle multiple analyzer codes
+ if (entry.index == null && entry.analyzerCode.length == 1) {
+ analyzerCode = entry.analyzerCode.single;
+ template = entry.template;
}
}
print(' ${fastaErrorCode.padRight(30)} --> $analyzerCode'
@@ -344,33 +324,4 @@
}
}
}
-
- /// Given a messages.yaml entry, come up with a mapping from placeholder
- /// patterns in its message and tip strings to their corresponding indices.
- Map<String, int> _computePlaceholderToIndexMap(Map<Object?, Object?> entry) {
- var mapping = <String, int>{};
- for (var key in const ['template', 'tip']) {
- var value = entry[key];
- if (value is! String) continue;
- for (Match match in _placeholderPattern.allMatches(value)) {
- // CFE supports a bunch of formatting options that we don't; make sure
- // none of those are used.
- if (match.group(0) != '#${match.group(1)}') {
- throw 'Template string ${json.encode(entry)} contains unsupported '
- 'placeholder pattern ${json.encode(match.group(0))}';
- }
-
- mapping[match.group(0)!] ??= mapping.length;
- }
- }
- return mapping;
- }
-
- /// Convert a CFE template string (which uses placeholders like `#string`) to
- /// an analyzer template string (which uses placeholders like `{0}`).
- String _convertTemplate(
- Map<String, int> placeholderToIndexMap, String entry) {
- return entry.replaceAllMapped(_placeholderPattern,
- (match) => '{${placeholderToIndexMap[match.group(0)!]}}');
- }
}
diff --git a/sdk/lib/async/future.dart b/sdk/lib/async/future.dart
index e43b92a..f663b08 100644
--- a/sdk/lib/async/future.dart
+++ b/sdk/lib/async/future.dart
@@ -780,7 +780,8 @@
///
/// Not all futures need to be awaited.
/// The Dart linter has an optional ["unawaited futures" lint](https://dart-lang.github.io/linter/lints/unawaited_futures.html)
-/// which enforces that futures (expressions with a static type of [Future])
+/// which enforces that potential futures
+/// (expressions with a static type of [Future] or `Future?`)
/// in asynchronous functions are handled *somehow*.
/// If a particular future value doesn't need to be awaited,
/// you can call `unawaited(...)` with it, which will avoid the lint,
@@ -797,8 +798,8 @@
/// are *expected* to complete with a value.
/// You can use [FutureExtensions.ignore] if you also don't want to know
/// about errors from this future.
-@Since("2.14")
-void unawaited(Future<void> future) {}
+@Since("2.15")
+void unawaited(Future<void>? future) {}
/// Convenience methods on futures.
///
diff --git a/tests/language/explicit_type_instantiation_parsing_test.dart b/tests/language/explicit_type_instantiation_parsing_test.dart
index f848e9b..e0584e7 100644
--- a/tests/language/explicit_type_instantiation_parsing_test.dart
+++ b/tests/language/explicit_type_instantiation_parsing_test.dart
@@ -292,20 +292,14 @@
// [cfe] A comparison expression can't be an operand of another comparison expression.
// [analyzer] SYNTACTIC_ERROR.EQUALITY_CANNOT_BE_EQUALITY_OPERAND
- // Parsed as a generic instantiation, but `v` is not generic function or type.
- // Would be valid if parsed as operators.
+ // Parsed as a generic invocation. Valid because of the `call` extension
+ // method on `Object?`.
expect1(v < X, X > (2));
- // ^^^^^^^^
- // [cfe] unspecified
- // [analyzer] unspecified
- // Parsed as a generic instantiation, but `d` is not generic function or type.
- // Being dynamic doesn't help.
- // Would be valid if parsed as operators.
+ // Parsed as a generic invocation. Valid because this is an *invocation*
+ // rather than an *instantiation*. We don't allow instantiation on `dynamic`,
+ // but we do allow calling.
expect1(d < X, X > (2));
- // ^^^^^^^^
- // [cfe] unspecified
- // [analyzer] unspecified
// Valid only if parenthesized.
expect1((Z < X, X >) * 2);
diff --git a/tests/lib/async/unawaited_test.dart b/tests/lib/async/unawaited_test.dart
index dc095cc..5ed05af 100644
--- a/tests/lib/async/unawaited_test.dart
+++ b/tests/lib/async/unawaited_test.dart
@@ -14,13 +14,16 @@
void testUnawaited() {
// Exists where expected.
- prefix.unawaited.expectStaticType<Exactly<void Function(Future<Object?>)>>();
+ prefix.unawaited.expectStaticType<Exactly<void Function(Future<Object?>?)>>();
var future = Future<int>.value(42);
captureStaticType(unawaited(future), <T>(value) {
Expect.equals(typeOf<void>(), T);
});
+ Future<Never>? noFuture = null;
+ unawaited(noFuture); // Doesn't throw on null.
+
asyncStart();
// Unawaited futures still throw.
{
diff --git a/tests/lib_2/async/unawaited_test.dart b/tests/lib_2/async/unawaited_test.dart
index 16bd285..5554a48 100644
--- a/tests/lib_2/async/unawaited_test.dart
+++ b/tests/lib_2/async/unawaited_test.dart
@@ -23,6 +23,9 @@
Expect.equals(typeOf<void>(), T);
});
+ Future<Never> noFuture = null;
+ unawaited(noFuture); // Doesn't throw on `null`.
+
asyncStart();
// Unawaited futures still throw.
{
diff --git a/tools/VERSION b/tools/VERSION
index 4291b21..9ad0a02 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 15
PATCH 0
-PRERELEASE 152
+PRERELEASE 153
PRERELEASE_PATCH 0
\ No newline at end of file