mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 10:49:00 +00:00
CONSTANT_PATTERN_NEVER_MATCHES_VALUE_TYPE: allow int vs int, expand checks for generic types.
Change-Id: If360cdcba68b934d84fab816ef280598f8038624 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/285081 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
parent
8041daf7b0
commit
d1559a99b6
3 changed files with 153 additions and 5 deletions
|
@ -23,6 +23,7 @@ import 'package:analyzer/src/dart/constant/has_type_parameter_reference.dart';
|
|||
import 'package:analyzer/src/dart/constant/potentially_constant.dart';
|
||||
import 'package:analyzer/src/dart/constant/value.dart';
|
||||
import 'package:analyzer/src/dart/element/element.dart';
|
||||
import 'package:analyzer/src/dart/element/least_greatest_closure.dart';
|
||||
import 'package:analyzer/src/dart/element/type.dart';
|
||||
import 'package:analyzer/src/dart/element/type_system.dart';
|
||||
import 'package:analyzer/src/diagnostic/diagnostic_factory.dart';
|
||||
|
@ -447,15 +448,23 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
|
|||
/// `false`, taking into account the fact that [constantType] has primitive
|
||||
/// equality.
|
||||
bool _canBeEqual(DartType constantType, DartType valueType) {
|
||||
if (constantType is InterfaceType && constantType.typeArguments.isEmpty) {
|
||||
if (constantType is InterfaceType) {
|
||||
if (valueType is InterfaceType) {
|
||||
return valueType.typeArguments.isEmpty &&
|
||||
_typeSystem.isSubtypeOf(constantType, valueType);
|
||||
if (constantType.isDartCoreInt && valueType.isDartCoreDouble) {
|
||||
return true;
|
||||
}
|
||||
final valueTypeGreatest = PatternGreatestClosureHelper(
|
||||
topType: _typeSystem.objectQuestion,
|
||||
bottomType: NeverTypeImpl.instance,
|
||||
).eliminateToGreatest(valueType);
|
||||
return _typeSystem.isSubtypeOf(constantType, valueTypeGreatest);
|
||||
} else if (valueType is TypeParameterTypeImpl) {
|
||||
final bound = valueType.promotedBound ?? valueType.element.bound;
|
||||
if (bound != null && !hasTypeParameterReference(bound)) {
|
||||
return _canBeEqual(constantType, bound);
|
||||
}
|
||||
} else if (valueType is FunctionType) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// All other cases are not supported, so no warning.
|
||||
|
|
|
@ -94,3 +94,36 @@ class LeastGreatestClosureHelper extends ReplacementVisitor {
|
|||
return super.visitTypeParameterType(type);
|
||||
}
|
||||
}
|
||||
|
||||
class PatternGreatestClosureHelper extends ReplacementVisitor {
|
||||
final TypeImpl topType;
|
||||
final TypeImpl bottomType;
|
||||
bool _isCovariant = true;
|
||||
|
||||
PatternGreatestClosureHelper({
|
||||
required this.topType,
|
||||
required this.bottomType,
|
||||
});
|
||||
|
||||
@override
|
||||
void changeVariance() {
|
||||
_isCovariant = !_isCovariant;
|
||||
}
|
||||
|
||||
/// Returns a supertype of [type] for all values of type parameters.
|
||||
DartType eliminateToGreatest(DartType type) {
|
||||
_isCovariant = true;
|
||||
return type.accept(this) ?? type;
|
||||
}
|
||||
|
||||
@override
|
||||
DartType? visitTypeParameterType(TypeParameterType type) {
|
||||
final replacement = _isCovariant ? topType : bottomType;
|
||||
return replacement.withNullability(
|
||||
uniteNullabilities(
|
||||
replacement.nullabilitySuffix,
|
||||
type.nullabilitySuffix,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -182,6 +182,102 @@ class B extends A {
|
|||
]);
|
||||
}
|
||||
|
||||
test_custom_primitiveEquality_generic_differentElement_constantIsSubtypeOfValue() async {
|
||||
await assertNoErrorsInCode('''
|
||||
void f(A<int> x) {
|
||||
if (x case const B()) {}
|
||||
}
|
||||
|
||||
class A<T> {
|
||||
const A();
|
||||
}
|
||||
|
||||
class B extends A<int> {
|
||||
const B();
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_custom_primitiveEquality_generic_differentElement_constantIsSupertypeOfValue() async {
|
||||
await assertErrorsInCode('''
|
||||
void f(B x) {
|
||||
if (x case const A<int>()) {}
|
||||
}
|
||||
|
||||
class A<T> {
|
||||
const A();
|
||||
}
|
||||
|
||||
class B extends A<int> {
|
||||
const B();
|
||||
}
|
||||
''', [
|
||||
error(WarningCode.CONSTANT_PATTERN_NEVER_MATCHES_VALUE_TYPE, 33, 8),
|
||||
]);
|
||||
}
|
||||
|
||||
test_custom_primitiveEquality_generic_sameElement_constantIsSameTypeAsValue() async {
|
||||
await assertNoErrorsInCode('''
|
||||
void f(A<int> x) {
|
||||
if (x case const A<int>()) {}
|
||||
}
|
||||
|
||||
class A<T> {
|
||||
const A();
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_custom_primitiveEquality_generic_sameElement_constantIsSubtypeOfValue() async {
|
||||
await assertNoErrorsInCode('''
|
||||
void f(A<num> x) {
|
||||
if (x case const A<int>()) {}
|
||||
}
|
||||
|
||||
class A<T> {
|
||||
const A();
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_custom_primitiveEquality_generic_sameElement_constantIsSupertypeOfValue() async {
|
||||
await assertErrorsInCode('''
|
||||
void f(A<int> x) {
|
||||
if (x case const A<num>()) {}
|
||||
}
|
||||
|
||||
class A<T> {
|
||||
const A();
|
||||
}
|
||||
''', [
|
||||
error(WarningCode.CONSTANT_PATTERN_NEVER_MATCHES_VALUE_TYPE, 38, 8),
|
||||
]);
|
||||
}
|
||||
|
||||
test_custom_primitiveEquality_generic_sameElement_typeParameter() async {
|
||||
await assertNoErrorsInCode('''
|
||||
void f<T>(A<T> x) {
|
||||
if (x case const A<int>()) {}
|
||||
}
|
||||
|
||||
class A<T> {
|
||||
const A();
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_custom_primitiveEquality_generic_sameElement_typeParameter_contravariant() async {
|
||||
await assertNoErrorsInCode('''
|
||||
void f<T>(A<void Function(T)> x) {
|
||||
if (x case const A<void Function(int)>()) {}
|
||||
}
|
||||
|
||||
class A<T> {
|
||||
const A();
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_int_bool() async {
|
||||
await assertErrorsInCode('''
|
||||
void f(bool x) {
|
||||
|
@ -193,14 +289,24 @@ void f(bool x) {
|
|||
}
|
||||
|
||||
test_int_double() async {
|
||||
await assertErrorsInCode('''
|
||||
await assertNoErrorsInCode('''
|
||||
void f(double x) {
|
||||
if (x case (zero)) {}
|
||||
}
|
||||
|
||||
const zero = 0;
|
||||
''');
|
||||
}
|
||||
|
||||
test_int_functionType() async {
|
||||
await assertErrorsInCode('''
|
||||
void f(void Function() x) {
|
||||
if (x case (0)) {}
|
||||
}
|
||||
|
||||
class A {}
|
||||
''', [
|
||||
error(WarningCode.CONSTANT_PATTERN_NEVER_MATCHES_VALUE_TYPE, 33, 4),
|
||||
error(WarningCode.CONSTANT_PATTERN_NEVER_MATCHES_VALUE_TYPE, 42, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue