blob: 71e48012e6967649252163089d5d27a1162e824a [file] [log] [blame]
// 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(NonExhaustiveSwitchExpressionTest);
defineReflectiveTests(NonExhaustiveSwitchStatementTest);
});
}
@reflectiveTest
class NonExhaustiveSwitchExpressionTest extends PubPackageResolutionTest {
test_bool_true() async {
await assertErrorsInCode(r'''
Object f(bool x) {
return switch (x) {
true => 0,
};
}
''', [
error(CompileTimeErrorCode.NON_EXHAUSTIVE_SWITCH_EXPRESSION, 28, 6),
]);
}
test_bool_true_false() async {
await assertNoErrorsInCode(r'''
Object f(bool x) {
return switch (x) {
true => 1,
false => 0,
};
}
''');
}
test_class_int_wildcard() async {
await assertNoErrorsInCode(r'''
Object f(int x) {
return switch (x) {
0 => 0,
_ => 1,
};
}
''');
}
test_class_withField_wildcard() async {
await assertNoErrorsInCode(r'''
Object f(int x) {
return switch (x) {
int(isEven: true) => 0,
_ => 1,
};
}
''');
}
test_enum_2at2_hasWhen() async {
await assertErrorsInCode(r'''
enum E {
a, b
}
Object f(E x) {
return switch (x) {
E.a when 1 == 0 => 0,
E.b => 1,
};
}
''', [
error(CompileTimeErrorCode.NON_EXHAUSTIVE_SWITCH_EXPRESSION, 44, 6,
correctionContains: 'E.a'),
]);
}
test_invalidType_empty() async {
await assertErrorsInCode(r'''
void f(Unresolved x) => switch (x) {};
''', [
error(CompileTimeErrorCode.UNDEFINED_CLASS, 7, 10),
]);
}
}
@reflectiveTest
class NonExhaustiveSwitchStatementTest extends PubPackageResolutionTest {
test_alwaysExhaustive_bool_true() async {
await assertErrorsInCode(r'''
void f(bool x) {
switch (x) {
case true:
break;
}
}
''', [
error(CompileTimeErrorCode.NON_EXHAUSTIVE_SWITCH_STATEMENT, 19, 6),
]);
}
test_alwaysExhaustive_bool_true_false() async {
await assertNoErrorsInCode(r'''
void f(bool x) {
switch (x) {
case true:
case false:
break;
}
}
''');
}
test_alwaysExhaustive_bool_wildcard_typed_bool() async {
await assertNoErrorsInCode(r'''
void f(bool x) {
switch (x) {
case bool _:
break;
}
}
''');
}
test_alwaysExhaustive_bool_wildcard_typed_int() async {
await assertErrorsInCode(r'''
void f(bool x) {
switch (x) {
case int _:
break;
}
}
''', [
error(CompileTimeErrorCode.NON_EXHAUSTIVE_SWITCH_STATEMENT, 19, 6),
error(WarningCode.PATTERN_NEVER_MATCHES_VALUE_TYPE, 41, 3),
]);
}
test_alwaysExhaustive_bool_wildcard_untyped() async {
await assertNoErrorsInCode(r'''
void f(bool x) {
switch (x) {
case _:
break;
}
}
''');
}
test_alwaysExhaustive_boolNullable_true_false() async {
await assertErrorsInCode(r'''
void f(bool? x) {
switch (x) {
case true:
case false:
break;
}
}
''', [
error(CompileTimeErrorCode.NON_EXHAUSTIVE_SWITCH_STATEMENT, 20, 6),
]);
}
test_alwaysExhaustive_boolNullable_true_false_null() async {
await assertNoErrorsInCode(r'''
void f(bool? x) {
switch (x) {
case true:
case false:
case null:
break;
}
}
''');
}
test_alwaysExhaustive_enum_2at1() async {
await assertErrorsInCode(r'''
enum E {
a, b
}
void f(E x) {
switch (x) {
case E.a:
break;
}
}
''', [
error(CompileTimeErrorCode.NON_EXHAUSTIVE_SWITCH_STATEMENT, 35, 6),
]);
}
test_alwaysExhaustive_enum_2at2_cases() async {
await assertNoErrorsInCode(r'''
enum E {
a, b
}
void f(E x) {
switch (x) {
case E.a:
case E.b:
break;
}
}
''');
}
test_alwaysExhaustive_enum_2at2_hasWhen() async {
await assertErrorsInCode(r'''
enum E {
a, b
}
void f(E x) {
switch (x) {
case E.a when 1 == 0:
case E.b:
break;
}
}
''', [
error(CompileTimeErrorCode.NON_EXHAUSTIVE_SWITCH_STATEMENT, 35, 6,
correctionContains: 'E.a'),
]);
}
test_alwaysExhaustive_enum_2at2_logicalOr() async {
await assertNoErrorsInCode(
r'''
enum E {
a, b
}
void f(E x) {
switch (x) {
case E.a || E.b:
break;
}
}
''',
);
}
test_alwaysExhaustive_enum_cannotCompute() async {
await assertErrorsInCode(r'''
enum E {
v1(v2), v2(v1);
const E(Object f);
}
void f(E x) {
switch (x) {
case E.v1:
case E.v2:
break;
}
}
''', [
error(CompileTimeErrorCode.RECURSIVE_COMPILE_TIME_CONSTANT, 11, 2),
error(CompileTimeErrorCode.RECURSIVE_COMPILE_TIME_CONSTANT, 19, 2),
]);
}
test_alwaysExhaustive_Null_hasError() async {
await assertErrorsInCode(r'''
void f(Null x) {
switch (x) {}
}
''', [
error(CompileTimeErrorCode.NON_EXHAUSTIVE_SWITCH_STATEMENT, 19, 6),
]);
}
test_alwaysExhaustive_Null_noError() async {
await assertNoErrorsInCode(r'''
void f(Null x) {
switch (x) {
case null:
break;
}
}
''');
}
test_alwaysExhaustive_recordType_bool_bool_4at4() async {
await assertNoErrorsInCode(r'''
void f((bool, bool) x) {
switch (x) {
case (false, false):
case (false, true):
case (true, false):
case (true, true):
break;
}
}
''');
}
test_alwaysExhaustive_sealedClass_2at1() async {
await assertErrorsInCode(r'''
sealed class A {}
class B extends A {}
class C extends A {}
void f(A x) {
switch (x) {
case B():
break;
}
}
''', [
error(CompileTimeErrorCode.NON_EXHAUSTIVE_SWITCH_STATEMENT, 77, 6),
]);
}
test_alwaysExhaustive_sealedClass_2at2() async {
await assertNoErrorsInCode(r'''
sealed class A {}
class B extends A {}
class C extends A {}
void f(A x) {
switch (x) {
case B():
break;
case C():
break;
}
}
''');
}
test_alwaysExhaustive_sealedClass_2at2_wildcard() async {
await assertNoErrorsInCode(r'''
sealed class A {}
class B extends A {}
class C extends A {}
void f(A x) {
switch (x) {
case B():
break;
case _:
break;
}
}
''');
}
test_alwaysExhaustive_sealedClass_constraintsMixin() async {
await assertErrorsInCode(r'''
sealed class A {}
class B extends A {}
mixin M on A {}
void f(A x) {
switch (x) {
case B _:
break;
}
}
''', [
error(CompileTimeErrorCode.NON_EXHAUSTIVE_SWITCH_STATEMENT, 74, 6),
]);
}
test_alwaysExhaustive_sealedClass_hasExtensionType_1of1() async {
await assertNoErrorsInCode(r'''
sealed class A {}
class B extends A {}
extension type EA(A it) implements A {}
void f(A x) {
switch (x) {
case B():
break;
}
}
''');
}
test_alwaysExhaustive_sealedClass_hasExtensionType_1of2() async {
await assertErrorsInCode(r'''
sealed class A {}
class B extends A {}
class C extends A {}
extension type EA(A it) implements A {}
void f(A x) {
switch (x) {
case B():
break;
}
}
''', [
error(CompileTimeErrorCode.NON_EXHAUSTIVE_SWITCH_STATEMENT, 117, 6),
]);
}
test_alwaysExhaustive_sealedClass_implementedByEnum_3at2() async {
await assertErrorsInCode(r'''
sealed class A {}
class B implements A {}
enum E implements A {
a, b
}
void f(A x) {
switch (x) {
case B _:
case E.a:
break;
}
}
''', [
error(CompileTimeErrorCode.NON_EXHAUSTIVE_SWITCH_STATEMENT, 92, 6),
]);
}
test_alwaysExhaustive_sealedClass_implementedByEnum_3at3() async {
await assertNoErrorsInCode(r'''
sealed class A {}
class B implements A {}
enum E implements A {
a, b
}
void f(A x) {
switch (x) {
case B _:
case E.a:
case E.b:
break;
}
}
''');
}
test_alwaysExhaustive_sealedClass_implementedByMixin_2at1() async {
await assertErrorsInCode(r'''
sealed class A {}
class B implements A {}
mixin M implements A {}
void f(A x) {
switch (x) {
case B _:
break;
}
}
''', [
error(CompileTimeErrorCode.NON_EXHAUSTIVE_SWITCH_STATEMENT, 85, 6),
]);
}
test_alwaysExhaustive_sealedClass_implementedByMixin_2at2() async {
await assertNoErrorsInCode(r'''
sealed class A {}
class B implements A {}
mixin M implements A {}
void f(A x) {
switch (x) {
case B _:
case M _:
break;
}
}
''');
}
test_alwaysExhaustive_sealedClass_unresolvedIdentifier() async {
await assertErrorsInCode(r'''
sealed class A {}
class B extends A {}
void f(A x) {
switch (x) {
case unresolved:
break;
}
}
''', [
error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 78, 10),
]);
}
test_alwaysExhaustive_sealedClass_unresolvedObject() async {
await assertErrorsInCode(r'''
sealed class A {}
class B extends A {}
void f(A x) {
switch (x) {
case Unresolved():
break;
}
}
''', [
error(CompileTimeErrorCode.UNDEFINED_CLASS, 78, 10),
]);
}
test_alwaysExhaustive_typeVariable_bound_bool_true() async {
await assertErrorsInCode(r'''
void f<T extends bool>(T x) {
switch (x) {
case true:
break;
}
}
''', [
error(CompileTimeErrorCode.NON_EXHAUSTIVE_SWITCH_STATEMENT, 32, 6),
]);
}
test_alwaysExhaustive_typeVariable_bound_bool_true_false() async {
await assertNoErrorsInCode(r'''
void f<T extends bool>(T x) {
switch (x) {
case true:
case false:
break;
}
}
''');
}
test_alwaysExhaustive_typeVariable_promoted_bool_true() async {
await assertErrorsInCode(r'''
void f<T>(T x) {
if (x is bool) {
switch (x) {
case true:
break;
}
}
}
''', [
error(CompileTimeErrorCode.NON_EXHAUSTIVE_SWITCH_STATEMENT, 40, 6),
]);
}
test_alwaysExhaustive_typeVariable_promoted_bool_true_false() async {
await assertNoErrorsInCode(r'''
void f<T>(T x) {
if (x is bool) {
switch (x) {
case true:
case false:
break;
}
}
}
''');
}
test_invalidType_empty() async {
await assertErrorsInCode(r'''
void f(Unresolved x) {
switch (x) {}
}
''', [
error(CompileTimeErrorCode.UNDEFINED_CLASS, 7, 10),
]);
}
test_notAlwaysExhaustive_int() async {
await assertNoErrorsInCode(r'''
void f(int x) {
switch (x) {
case 0:
break;
}
}
''');
}
}