mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 08:24:39 +00:00
Report RELATIONAL_PATTERN_ARGUMENT_TYPE_NOT_ASSIGNABLE instead.
Bug: https://github.com/dart-lang/sdk/issues/51679 Change-Id: Ia0655afa328dbc20ee7ee0fb62675a0f26f9be19 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/287940 Reviewed-by: Samuel Rawlins <srawlins@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
parent
d0024e9931
commit
74fb9e190f
|
@ -1653,9 +1653,10 @@ mixin TypeAnalyzer<
|
|||
Type argumentType =
|
||||
isEquality ? operations.promoteToNonNull(operandType) : operandType;
|
||||
if (!operations.isAssignableTo(argumentType, operator.parameterType)) {
|
||||
argumentTypeNotAssignableError = errors.argumentTypeNotAssignable(
|
||||
argument: operand,
|
||||
argumentType: argumentType,
|
||||
argumentTypeNotAssignableError =
|
||||
errors.relationalPatternOperandTypeNotAssignable(
|
||||
pattern: node,
|
||||
operandType: argumentType,
|
||||
parameterType: operator.parameterType,
|
||||
);
|
||||
}
|
||||
|
@ -2511,14 +2512,6 @@ abstract class TypeAnalyzerErrors<
|
|||
Type extends Object,
|
||||
Pattern extends Node,
|
||||
Error> implements TypeAnalyzerErrorsBase {
|
||||
/// Called if [argument] has type [argumentType], which is not assignable
|
||||
/// to [parameterType].
|
||||
Error argumentTypeNotAssignable({
|
||||
required Expression argument,
|
||||
required Type argumentType,
|
||||
required Type parameterType,
|
||||
});
|
||||
|
||||
/// Called if pattern support is disabled and a case constant's static type
|
||||
/// doesn't properly match the scrutinee's static type.
|
||||
Error caseExpressionTypeMismatch(
|
||||
|
@ -2627,6 +2620,14 @@ abstract class TypeAnalyzerErrors<
|
|||
Error refutablePatternInIrrefutableContext(
|
||||
{required Node pattern, required Node context});
|
||||
|
||||
/// Called if the operand of the [pattern] has the type [operandType], which
|
||||
/// is not assignable to [parameterType] of the invoked relational operator.
|
||||
Error relationalPatternOperandTypeNotAssignable({
|
||||
required Pattern pattern,
|
||||
required Type operandType,
|
||||
required Type parameterType,
|
||||
});
|
||||
|
||||
/// Called if the [returnType] of the invoked relational operator is not
|
||||
/// assignable to `bool`.
|
||||
Error relationalPatternOperatorReturnTypeNotAssignableToBool({
|
||||
|
|
|
@ -2991,19 +2991,6 @@ class _MiniAstErrors
|
|||
/// highlight the point of failure.
|
||||
StackTrace? _assertInErrorRecoveryStack;
|
||||
|
||||
@override
|
||||
void argumentTypeNotAssignable({
|
||||
required Expression argument,
|
||||
required Type argumentType,
|
||||
required Type parameterType,
|
||||
}) {
|
||||
_recordError('argumentTypeNotAssignable', {
|
||||
'argument': argument,
|
||||
'argumentType': argumentType,
|
||||
'parameterType': parameterType,
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void assertInErrorRecovery() {
|
||||
if (_accumulatedErrors.isEmpty) {
|
||||
|
@ -3181,6 +3168,19 @@ class _MiniAstErrors
|
|||
{'pattern': pattern, 'context': context});
|
||||
}
|
||||
|
||||
@override
|
||||
void relationalPatternOperandTypeNotAssignable({
|
||||
required Pattern pattern,
|
||||
required Type operandType,
|
||||
required Type parameterType,
|
||||
}) {
|
||||
_recordError('relationalPatternOperandTypeNotAssignable', {
|
||||
'pattern': pattern,
|
||||
'operandType': operandType,
|
||||
'parameterType': parameterType,
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void relationalPatternOperatorReturnTypeNotAssignableToBool({
|
||||
required Pattern pattern,
|
||||
|
|
|
@ -3633,13 +3633,13 @@ main() {
|
|||
h.run([
|
||||
ifCase(
|
||||
expr('int').checkContext('?'),
|
||||
relationalPattern('>', expr('String')..errorId = 'OPERAND'),
|
||||
relationalPattern('>', expr('String'))..errorId = 'PATTERN',
|
||||
[],
|
||||
).checkIr('ifCase(expr(int), >(expr(String), '
|
||||
'matchedType: int), variables(), true, block(), noop)')
|
||||
], expectedErrors: {
|
||||
'argumentTypeNotAssignable(argument: OPERAND, '
|
||||
'argumentType: String, parameterType: num)'
|
||||
'relationalPatternOperandTypeNotAssignable(pattern: PATTERN, '
|
||||
'operandType: String, parameterType: num)'
|
||||
});
|
||||
});
|
||||
test('return type is not assignable to bool', () {
|
||||
|
|
|
@ -1017,6 +1017,8 @@ CompileTimeErrorCode.REFERENCED_BEFORE_DECLARATION:
|
|||
status: needsEvaluation
|
||||
CompileTimeErrorCode.REFUTABLE_PATTERN_IN_IRREFUTABLE_CONTEXT:
|
||||
status: noFix
|
||||
CompileTimeErrorCode.RELATIONAL_PATTERN_OPERAND_TYPE_NOT_ASSIGNABLE:
|
||||
status: noFix
|
||||
CompileTimeErrorCode.RELATIONAL_PATTERN_OPERATOR_RETURN_TYPE_NOT_ASSIGNABLE_TO_BOOL:
|
||||
status: noFix
|
||||
CompileTimeErrorCode.REST_ELEMENT_NOT_LAST_IN_MAP_PATTERN:
|
||||
|
|
|
@ -28,19 +28,6 @@ class SharedTypeAnalyzerErrors
|
|||
|
||||
SharedTypeAnalyzerErrors(this._errorReporter);
|
||||
|
||||
@override
|
||||
void argumentTypeNotAssignable({
|
||||
required Expression argument,
|
||||
required DartType argumentType,
|
||||
required DartType parameterType,
|
||||
}) {
|
||||
_errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE,
|
||||
argument,
|
||||
[argumentType, parameterType],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void assertInErrorRecovery() {}
|
||||
|
||||
|
@ -233,6 +220,19 @@ class SharedTypeAnalyzerErrors
|
|||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void relationalPatternOperandTypeNotAssignable({
|
||||
required covariant RelationalPatternImpl pattern,
|
||||
required DartType operandType,
|
||||
required DartType parameterType,
|
||||
}) {
|
||||
_errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.RELATIONAL_PATTERN_OPERAND_TYPE_NOT_ASSIGNABLE,
|
||||
pattern.operand,
|
||||
[operandType, parameterType, pattern.operator.lexeme],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void relationalPatternOperatorReturnTypeNotAssignableToBool({
|
||||
required covariant RelationalPatternImpl pattern,
|
||||
|
|
|
@ -4265,6 +4265,17 @@ class CompileTimeErrorCode extends AnalyzerErrorCode {
|
|||
"instead.",
|
||||
);
|
||||
|
||||
/// Parameters:
|
||||
/// 0: the operand type
|
||||
/// 1: the parameter type of the invoked operator
|
||||
/// 2: the name of the invoked operator
|
||||
static const CompileTimeErrorCode
|
||||
RELATIONAL_PATTERN_OPERAND_TYPE_NOT_ASSIGNABLE = CompileTimeErrorCode(
|
||||
'RELATIONAL_PATTERN_OPERAND_TYPE_NOT_ASSIGNABLE',
|
||||
"The constant expression type '{0}' is not assignable to the parameter "
|
||||
"type '{1}' of the '{2}' operator.",
|
||||
);
|
||||
|
||||
static const CompileTimeErrorCode
|
||||
RELATIONAL_PATTERN_OPERATOR_RETURN_TYPE_NOT_ASSIGNABLE_TO_BOOL =
|
||||
CompileTimeErrorCode(
|
||||
|
|
|
@ -432,6 +432,7 @@ const List<ErrorCode> errorCodeValues = [
|
|||
CompileTimeErrorCode.REDIRECT_TO_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER,
|
||||
CompileTimeErrorCode.REFERENCED_BEFORE_DECLARATION,
|
||||
CompileTimeErrorCode.REFUTABLE_PATTERN_IN_IRREFUTABLE_CONTEXT,
|
||||
CompileTimeErrorCode.RELATIONAL_PATTERN_OPERAND_TYPE_NOT_ASSIGNABLE,
|
||||
CompileTimeErrorCode
|
||||
.RELATIONAL_PATTERN_OPERATOR_RETURN_TYPE_NOT_ASSIGNABLE_TO_BOOL,
|
||||
CompileTimeErrorCode.REST_ELEMENT_NOT_LAST_IN_MAP_PATTERN,
|
||||
|
|
|
@ -12464,6 +12464,13 @@ CompileTimeErrorCode:
|
|||
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.
|
||||
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: |-
|
||||
Parameters:
|
||||
0: the operand type
|
||||
1: the parameter type of the invoked operator
|
||||
2: the name of the invoked operator
|
||||
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'.
|
||||
|
|
|
@ -217,135 +217,6 @@ void g() {
|
|||
error(CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 44, 12),
|
||||
]);
|
||||
}
|
||||
|
||||
test_relationalPattern_bangEq_matchedValueNullable() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
class A {}
|
||||
|
||||
void f(A? x) {
|
||||
switch (x) {
|
||||
case != null:
|
||||
break;
|
||||
}
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_relationalPattern_bangEq_operandNull() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
class A {}
|
||||
|
||||
void f(A x) {
|
||||
switch (x) {
|
||||
case != null:
|
||||
break;
|
||||
}
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_relationalPattern_bangEq_operandNullable() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
class A {}
|
||||
|
||||
const int? y = 0;
|
||||
|
||||
void f(A x) {
|
||||
switch (x) {
|
||||
case != y:
|
||||
break;
|
||||
}
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_relationalPattern_eqEq() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
class A {}
|
||||
|
||||
void f(A x) {
|
||||
switch (x) {
|
||||
case == 0:
|
||||
break;
|
||||
}
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_relationalPattern_eqEq_covariantParameterType() async {
|
||||
await assertErrorsInCode(r'''
|
||||
class A {
|
||||
bool operator ==(covariant A other) => true;
|
||||
}
|
||||
|
||||
void f(A x) {
|
||||
switch (x) {
|
||||
case == 0:
|
||||
break;
|
||||
}
|
||||
}
|
||||
''', [
|
||||
error(CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 101, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
test_relationalPattern_eqEq_matchedValueNullable() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
class A {}
|
||||
|
||||
void f(A? x) {
|
||||
switch (x) {
|
||||
case == null:
|
||||
break;
|
||||
}
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_relationalPattern_eqEq_operandNull() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
class A {}
|
||||
|
||||
void f(A x) {
|
||||
switch (x) {
|
||||
case == null:
|
||||
break;
|
||||
}
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_relationalPattern_eqEq_operandNullable() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
class A {}
|
||||
|
||||
const int? y = 0;
|
||||
|
||||
void f(A x) {
|
||||
switch (x) {
|
||||
case == y:
|
||||
break;
|
||||
}
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_relationalPattern_greaterThan() async {
|
||||
await assertErrorsInCode(r'''
|
||||
class A {
|
||||
bool operator >(A other) => true;
|
||||
}
|
||||
|
||||
void f(A x) {
|
||||
switch (x) {
|
||||
case > 0:
|
||||
break;
|
||||
}
|
||||
}
|
||||
''', [
|
||||
error(CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 89, 1),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
mixin ArgumentTypeNotAssignableTestCases on PubPackageResolutionTest {
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
// Copyright (c) 2023, 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 'package:analyzer/src/error/codes.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import '../dart/resolution/context_collection_resolution.dart';
|
||||
|
||||
main() {
|
||||
defineReflectiveSuite(() {
|
||||
defineReflectiveTests(RelationalPatternArgumentTypeNotAssignableTest);
|
||||
});
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class RelationalPatternArgumentTypeNotAssignableTest
|
||||
extends PubPackageResolutionTest {
|
||||
test_bangEq_matchedValueNullable() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
class A {}
|
||||
|
||||
void f(A? x) {
|
||||
switch (x) {
|
||||
case != null:
|
||||
break;
|
||||
}
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_bangEq_operandNull() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
class A {}
|
||||
|
||||
void f(A x) {
|
||||
switch (x) {
|
||||
case != null:
|
||||
break;
|
||||
}
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_bangEq_operandNullable() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
class A {}
|
||||
|
||||
const int? y = 0;
|
||||
|
||||
void f(A x) {
|
||||
switch (x) {
|
||||
case != y:
|
||||
break;
|
||||
}
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_eqEq() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
class A {}
|
||||
|
||||
void f(A x) {
|
||||
switch (x) {
|
||||
case == 0:
|
||||
break;
|
||||
}
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_eqEq_covariantParameterType() async {
|
||||
await assertErrorsInCode(r'''
|
||||
class A {
|
||||
bool operator ==(covariant A other) => true;
|
||||
}
|
||||
|
||||
void f(A x) {
|
||||
switch (x) {
|
||||
case == 0:
|
||||
break;
|
||||
}
|
||||
}
|
||||
''', [
|
||||
error(CompileTimeErrorCode.RELATIONAL_PATTERN_OPERAND_TYPE_NOT_ASSIGNABLE,
|
||||
101, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
test_eqEq_matchedValueNullable() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
class A {}
|
||||
|
||||
void f(A? x) {
|
||||
switch (x) {
|
||||
case == null:
|
||||
break;
|
||||
}
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_eqEq_operandNull() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
class A {}
|
||||
|
||||
void f(A x) {
|
||||
switch (x) {
|
||||
case == null:
|
||||
break;
|
||||
}
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_eqEq_operandNullable() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
class A {}
|
||||
|
||||
const int? y = 0;
|
||||
|
||||
void f(A x) {
|
||||
switch (x) {
|
||||
case == y:
|
||||
break;
|
||||
}
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_greaterThan() async {
|
||||
await assertErrorsInCode(r'''
|
||||
class A {
|
||||
bool operator >(A other) => true;
|
||||
}
|
||||
|
||||
void f(A x) {
|
||||
switch (x) {
|
||||
case > 0:
|
||||
break;
|
||||
}
|
||||
}
|
||||
''', [
|
||||
error(CompileTimeErrorCode.RELATIONAL_PATTERN_OPERAND_TYPE_NOT_ASSIGNABLE,
|
||||
89, 1),
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -691,6 +691,8 @@ import 'referenced_before_declaration_test.dart'
|
|||
as referenced_before_declaration;
|
||||
import 'refutable_pattern_in_irrefutable_context_test.dart'
|
||||
as refutable_pattern_in_irrefutable_context;
|
||||
import 'relational_pattern_operand_type_not_assignable_test.dart'
|
||||
as relational_pattern_operand_type_not_assignable;
|
||||
import 'relational_pattern_operator_return_type_not_assignable_to_bool_test.dart'
|
||||
as relational_pattern_operator_return_type_not_assignable_to_bool;
|
||||
import 'removed_lint_use_test.dart' as removed_lint_in_ignore;
|
||||
|
@ -1324,6 +1326,7 @@ main() {
|
|||
redirect_to_type_alias_expands_to_type_parameter.main();
|
||||
referenced_before_declaration.main();
|
||||
refutable_pattern_in_irrefutable_context.main();
|
||||
relational_pattern_operand_type_not_assignable.main();
|
||||
relational_pattern_operator_return_type_not_assignable_to_bool.main();
|
||||
removed_lint_in_ignore.main();
|
||||
replaced_lint_in_ignore.main();
|
||||
|
|
|
@ -36,19 +36,6 @@ class SharedTypeAnalyzerErrors
|
|||
required this.coreTypes,
|
||||
required this.isNonNullableByDefault});
|
||||
|
||||
@override
|
||||
InvalidExpression argumentTypeNotAssignable({
|
||||
required Expression argument,
|
||||
required DartType argumentType,
|
||||
required DartType parameterType,
|
||||
}) {
|
||||
return helper.buildProblem(
|
||||
templateArgumentTypeNotAssignable.withArguments(
|
||||
argumentType, parameterType, isNonNullableByDefault),
|
||||
argument.fileOffset,
|
||||
noLength);
|
||||
}
|
||||
|
||||
@override
|
||||
void assertInErrorRecovery() {
|
||||
// TODO(paulberry): figure out how to do this.
|
||||
|
@ -164,12 +151,6 @@ class SharedTypeAnalyzerErrors
|
|||
messageNonBoolCondition, node.fileOffset, noLength);
|
||||
}
|
||||
|
||||
@override
|
||||
void patternDoesNotAllowLate({required TreeNode pattern}) {
|
||||
// TODO(johnniwinther): Is late even supported by the grammar or parser?
|
||||
throw new UnimplementedError('TODO(paulberry)');
|
||||
}
|
||||
|
||||
@override
|
||||
InvalidExpression nonExhaustiveSwitch(
|
||||
{required TreeNode node, required DartType scrutineeType}) {
|
||||
|
@ -188,6 +169,12 @@ class SharedTypeAnalyzerErrors
|
|||
noLength);
|
||||
}
|
||||
|
||||
@override
|
||||
void patternDoesNotAllowLate({required TreeNode pattern}) {
|
||||
// TODO(johnniwinther): Is late even supported by the grammar or parser?
|
||||
throw new UnimplementedError('TODO(paulberry)');
|
||||
}
|
||||
|
||||
@override
|
||||
InvalidExpression patternForInExpressionIsNotIterable({
|
||||
required TreeNode node,
|
||||
|
@ -217,6 +204,19 @@ class SharedTypeAnalyzerErrors
|
|||
pattern.fileOffset, noLength);
|
||||
}
|
||||
|
||||
@override
|
||||
InvalidExpression relationalPatternOperandTypeNotAssignable({
|
||||
required covariant RelationalPattern pattern,
|
||||
required DartType operandType,
|
||||
required DartType parameterType,
|
||||
}) {
|
||||
return helper.buildProblem(
|
||||
templateArgumentTypeNotAssignable.withArguments(
|
||||
operandType, parameterType, isNonNullableByDefault),
|
||||
pattern.expression.fileOffset,
|
||||
noLength);
|
||||
}
|
||||
|
||||
@override
|
||||
InvalidExpression relationalPatternOperatorReturnTypeNotAssignableToBool({
|
||||
required Pattern pattern,
|
||||
|
|
Loading…
Reference in a new issue