From 0196a5b296790a2ed4ce4d8352b59d5b2f6b33e1 Mon Sep 17 00:00:00 2001 From: Robert Nystrom Date: Fri, 31 Mar 2023 20:50:52 +0000 Subject: [PATCH] Allow static error tests to detect unreachable case hints from analyzer. Eventually, these hints should probably be moved over to warnings. But for now, this makes it possible to write static error language tests that validate that analyzer produces unreachable case warnings/hints where expected. Also updated the patterns/ and switch/ tests now that those errors must be expected by the test. Change-Id: If1fb92602c4bde2819b9eec73598033009054947 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/291967 Auto-Submit: Bob Nystrom Reviewed-by: Konstantin Shcheglov Reviewed-by: Samuel Rawlins Commit-Queue: Bob Nystrom --- pkg/test_runner/lib/src/command_output.dart | 18 +- pkg/test_runner/lib/src/static_error.dart | 1 + .../exhaustiveness/bool_switch_test.dart | 6 +- .../exhaustiveness/enum_switch_test.dart | 12 +- .../object_pattern_switch_test.dart | 6 +- .../record_literal_named_switch_test.dart | 6 +- .../record_literal_switch_test.dart | 6 +- .../exhaustiveness/record_switch_test.dart | 6 +- .../sealed_class_switch_test.dart | 6 +- .../variable_pattern_switch_test.dart | 6 +- .../invalid_const_pattern_binary_test.dart | 214 +++++++++++++- .../patterns/invalid_const_pattern_test.dart | 276 ++++++++++++++++++ .../switch_case_scope_error_test.dart | 2 +- .../version_2_29_changes_error_test.dart | 6 +- tests/language/switch/case_runtime_test.dart | 17 +- 15 files changed, 548 insertions(+), 40 deletions(-) diff --git a/pkg/test_runner/lib/src/command_output.dart b/pkg/test_runner/lib/src/command_output.dart index 73100c36b8b..ab4742d32f0 100644 --- a/pkg/test_runner/lib/src/command_output.dart +++ b/pkg/test_runner/lib/src/command_output.dart @@ -480,6 +480,13 @@ class AnalyzerError implements Comparable { 'unnecessary_null_check_pattern', }; + /// The set of hints which must be expected in a test. Any hint not specified + /// here which is reported by the analyzer does not need to be expected, and + /// never causes a test to fail. + static const Set _specifiedHints = { + 'unreachable_switch_case', + }; + /// Parses all errors from analyzer [stdout] output. static List parseStdout(String stdout) { var result = []; @@ -494,8 +501,10 @@ class AnalyzerError implements Comparable { for (var diagnostic in jsonData['diagnostics'] as List) { var diagnosticMap = diagnostic as Map; + var code = diagnosticMap['code'] as String; var type = diagnosticMap['type'] as String?; - if (type == 'HINT') { + + if (type == 'HINT' && !_specifiedHints.contains(code)) { // The analyzer can report hints which do not need to be expected in // the test source. These can be ignored. // TODO(srawlins): Hints will start to change to be warnings. There are @@ -505,10 +514,12 @@ class AnalyzerError implements Comparable { continue; } - var code = diagnosticMap['code'] as String; if (type == 'STATIC_WARNING' && !_specifiedWarnings.contains(code)) { continue; } + + if (type == 'LINT') continue; + var errorCode = '$type.${code.toUpperCase()}'; var error = _parse( @@ -610,7 +621,8 @@ class AnalysisCommandOutput extends CommandOutput with _StaticErrorOutput { for (var diagnostic in AnalyzerError.parseStdout(stdout)) { if (diagnostic.severity == 'ERROR') { errors.add(convert(diagnostic)); - } else if (diagnostic.severity == 'WARNING' && warnings != null) { + } else if (warnings != null && + (diagnostic.severity == 'WARNING' || diagnostic.severity == 'INFO')) { warnings.add(convert(diagnostic)); } } diff --git a/pkg/test_runner/lib/src/static_error.dart b/pkg/test_runner/lib/src/static_error.dart index 0fd262b3b0b..d3436edaf14 100644 --- a/pkg/test_runner/lib/src/static_error.dart +++ b/pkg/test_runner/lib/src/static_error.dart @@ -66,6 +66,7 @@ class StaticError implements Comparable { // of error codes in sdk/pkg/analyzer/lib/error/error.dart. Is there a more // systematic way to handle this? static const _analyzerWarningCodes = { + "HINT.UNREACHABLE_SWITCH_CASE", "STATIC_WARNING.ANALYSIS_OPTION_DEPRECATED", "STATIC_WARNING.INCLUDE_FILE_NOT_FOUND", "STATIC_WARNING.INCLUDED_FILE_WARNING", diff --git a/tests/language/patterns/exhaustiveness/bool_switch_test.dart b/tests/language/patterns/exhaustiveness/bool_switch_test.dart index d9c18f8e99c..7e7941b0ec5 100644 --- a/tests/language/patterns/exhaustiveness/bool_switch_test.dart +++ b/tests/language/patterns/exhaustiveness/bool_switch_test.dart @@ -131,7 +131,8 @@ void unreachableCase1(bool b) { print('false'); break; case true: // Unreachable -// ^ +// ^^^^ +// [analyzer] HINT.UNREACHABLE_SWITCH_CASE // [cfe] This case is covered by the previous cases. print('true2'); break; @@ -165,7 +166,8 @@ void unreachableCase3(bool? b) { print('null1'); break; case null: // Unreachable -// ^ +// ^^^^ +// [analyzer] HINT.UNREACHABLE_SWITCH_CASE // [cfe] This case is covered by the previous cases. print('null2'); break; diff --git a/tests/language/patterns/exhaustiveness/enum_switch_test.dart b/tests/language/patterns/exhaustiveness/enum_switch_test.dart index c19977d248f..b911e05a546 100644 --- a/tests/language/patterns/exhaustiveness/enum_switch_test.dart +++ b/tests/language/patterns/exhaustiveness/enum_switch_test.dart @@ -186,7 +186,8 @@ void unreachableCase1(Enum e) { print('b'); break; case Enum.a: // Unreachable -// ^ +// ^^^^ +// [analyzer] HINT.UNREACHABLE_SWITCH_CASE // [cfe] This case is covered by the previous cases. print('a2'); break; @@ -209,7 +210,8 @@ void unreachableCase2(Enum e) { print('b'); break; case Enum.a: // Unreachable -// ^ +// ^^^^ +// [analyzer] HINT.UNREACHABLE_SWITCH_CASE // [cfe] This case is covered by the previous cases. print('a2'); break; @@ -249,7 +251,8 @@ void unreachableCase4(Enum? e) { print('null1'); break; case null: // Unreachable -// ^ +// ^^^^ +// [analyzer] HINT.UNREACHABLE_SWITCH_CASE // [cfe] This case is covered by the previous cases. print('null2'); break; @@ -263,7 +266,8 @@ void unreachableCase5(Enum e) { break; case Enum.b: case Enum.a: // Unreachable -// ^ +// ^^^^ +// [analyzer] HINT.UNREACHABLE_SWITCH_CASE // [cfe] This case is covered by the previous cases. case Enum.c: print('c'); diff --git a/tests/language/patterns/exhaustiveness/object_pattern_switch_test.dart b/tests/language/patterns/exhaustiveness/object_pattern_switch_test.dart index 909c1a43704..889b812f91b 100644 --- a/tests/language/patterns/exhaustiveness/object_pattern_switch_test.dart +++ b/tests/language/patterns/exhaustiveness/object_pattern_switch_test.dart @@ -158,7 +158,8 @@ void unreachableCase1(A r) { print('A(b, true)'); break; case A(a: Enum.a, b: false): // Unreachable -// ^ +// ^^^^ +// [analyzer] HINT.UNREACHABLE_SWITCH_CASE // [cfe] This case is covered by the previous cases. print('(a, false) #2'); break; @@ -204,7 +205,8 @@ void unreachableCase3(A? r) { print('null #1'); break; case null: // Unreachable -// ^ +// ^^^^ +// [analyzer] HINT.UNREACHABLE_SWITCH_CASE // [cfe] This case is covered by the previous cases. print('null #2'); break; diff --git a/tests/language/patterns/exhaustiveness/record_literal_named_switch_test.dart b/tests/language/patterns/exhaustiveness/record_literal_named_switch_test.dart index 2ba7b620ba6..e56e1382bb3 100644 --- a/tests/language/patterns/exhaustiveness/record_literal_named_switch_test.dart +++ b/tests/language/patterns/exhaustiveness/record_literal_named_switch_test.dart @@ -147,7 +147,8 @@ void unreachableCase1(({Enum a, bool b}) r) { print('(b, true)'); break; case (a: Enum.a, b: false): // Unreachable -// ^ +// ^^^^ +// [analyzer] HINT.UNREACHABLE_SWITCH_CASE // [cfe] This case is covered by the previous cases. print('(a, false) #2'); break; @@ -193,7 +194,8 @@ void unreachableCase3(({Enum a, bool b})? r) { print('null #1'); break; case null: // Unreachable -// ^ +// ^^^^ +// [analyzer] HINT.UNREACHABLE_SWITCH_CASE // [cfe] This case is covered by the previous cases. print('null #2'); break; diff --git a/tests/language/patterns/exhaustiveness/record_literal_switch_test.dart b/tests/language/patterns/exhaustiveness/record_literal_switch_test.dart index 8fb76a87f13..5b8a9e6ae88 100644 --- a/tests/language/patterns/exhaustiveness/record_literal_switch_test.dart +++ b/tests/language/patterns/exhaustiveness/record_literal_switch_test.dart @@ -147,7 +147,8 @@ void unreachableCase1((Enum, bool) r) { print('(b, true)'); break; case (Enum.a, false): // Unreachable -// ^ +// ^^^^ +// [analyzer] HINT.UNREACHABLE_SWITCH_CASE // [cfe] This case is covered by the previous cases. print('(a, false) #2'); break; @@ -193,7 +194,8 @@ void unreachableCase3((Enum, bool)? r) { print('null1'); break; case null: // Unreachable -// ^ +// ^^^^ +// [analyzer] HINT.UNREACHABLE_SWITCH_CASE // [cfe] This case is covered by the previous cases. print('null2'); break; diff --git a/tests/language/patterns/exhaustiveness/record_switch_test.dart b/tests/language/patterns/exhaustiveness/record_switch_test.dart index d9eb00c6a9c..8e8de42b971 100644 --- a/tests/language/patterns/exhaustiveness/record_switch_test.dart +++ b/tests/language/patterns/exhaustiveness/record_switch_test.dart @@ -151,7 +151,8 @@ void unreachableCase1((Enum, bool) r) { print('(b, true)'); break; case r0: // Unreachable -// ^ +// ^^^^ +// [analyzer] HINT.UNREACHABLE_SWITCH_CASE // [cfe] This case is covered by the previous cases. print('(a, false) #2'); break; @@ -197,7 +198,8 @@ void unreachableCase3((Enum, bool)? r) { print('null1'); break; case null: // Unreachable -// ^ +// ^^^^ +// [analyzer] HINT.UNREACHABLE_SWITCH_CASE // [cfe] This case is covered by the previous cases. print('null2'); break; diff --git a/tests/language/patterns/exhaustiveness/sealed_class_switch_test.dart b/tests/language/patterns/exhaustiveness/sealed_class_switch_test.dart index 46d49e94d1e..6a7fff045bb 100644 --- a/tests/language/patterns/exhaustiveness/sealed_class_switch_test.dart +++ b/tests/language/patterns/exhaustiveness/sealed_class_switch_test.dart @@ -151,7 +151,8 @@ void unreachableCase1(A a) { print('D'); break; case A a: // Unreachable -// ^ +// ^^^^ +// [analyzer] HINT.UNREACHABLE_SWITCH_CASE // [cfe] This case is covered by the previous cases. print('A'); break; @@ -179,7 +180,8 @@ void unreachableCase3(A? a) { print('null #1'); break; case null: // Unreachable -// ^ +// ^^^^ +// [analyzer] HINT.UNREACHABLE_SWITCH_CASE // [cfe] This case is covered by the previous cases. print('null #2'); break; diff --git a/tests/language/patterns/exhaustiveness/variable_pattern_switch_test.dart b/tests/language/patterns/exhaustiveness/variable_pattern_switch_test.dart index 489a68e4c17..7cd6e93be94 100644 --- a/tests/language/patterns/exhaustiveness/variable_pattern_switch_test.dart +++ b/tests/language/patterns/exhaustiveness/variable_pattern_switch_test.dart @@ -143,7 +143,8 @@ void unreachableCase1((Enum, bool) r) { print('(b, true)'); break; case (Enum a, bool b): // Unreachable -// ^ +// ^^^^ +// [analyzer] HINT.UNREACHABLE_SWITCH_CASE // [cfe] This case is covered by the previous cases. print('(*, *)'); break; @@ -171,7 +172,8 @@ void unreachableCase3((Enum, bool)? r) { print('null1'); break; case null: // Unreachable -// ^ +// ^^^^ +// [analyzer] HINT.UNREACHABLE_SWITCH_CASE // [cfe] This case is covered by the previous cases. print('null2'); break; diff --git a/tests/language/patterns/invalid_const_pattern_binary_test.dart b/tests/language/patterns/invalid_const_pattern_binary_test.dart index b348d8dd01f..4e856822f8d 100644 --- a/tests/language/patterns/invalid_const_pattern_binary_test.dart +++ b/tests/language/patterns/invalid_const_pattern_binary_test.dart @@ -15,191 +15,389 @@ class Class { method(o) { switch (o) { case 1 || 2: // Ok + } + + switch (o) { case 1 && 2: // Ok + } + + switch (o) { case 1 as T: // Ok + } + + switch (o) { case const Object(): // Ok + } + + switch (o) { case 1 + 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_BINARY // [cfe] The binary operator + is not supported as a constant pattern. + } + + switch (o) { case 1 - 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_BINARY // [cfe] The binary operator - is not supported as a constant pattern. + } + + switch (o) { case 1 * 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_BINARY // [cfe] The binary operator * is not supported as a constant pattern. + } + + switch (o) { case 1 / 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_BINARY // [cfe] The binary operator / is not supported as a constant pattern. + } + + switch (o) { case 1 ~/ 2: // Error // ^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_BINARY // [cfe] The binary operator ~/ is not supported as a constant pattern. + } + + switch (o) { case 1 % 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_BINARY // [cfe] The binary operator % is not supported as a constant pattern. + } + + switch (o) { case 1 == 2: // Error // ^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_BINARY // [cfe] The binary operator == is not supported as a constant pattern. + } + + switch (o) { case 1 != 2: // Error // ^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_BINARY // [cfe] The binary operator != is not supported as a constant pattern. + } + + switch (o) { case 1 ^ 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_BINARY // [cfe] The binary operator ^ is not supported as a constant pattern. + } + + switch (o) { case 1 & 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_BINARY // [cfe] The binary operator & is not supported as a constant pattern. + } + + switch (o) { case 1 | 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_BINARY // [cfe] The binary operator | is not supported as a constant pattern. + } + + switch (o) { case 1 < 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_BINARY // [cfe] The binary operator < is not supported as a constant pattern. + } + + switch (o) { case 1 <= 2: // Error // ^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_BINARY // [cfe] The binary operator <= is not supported as a constant pattern. + } + + switch (o) { case 1 > 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_BINARY // [cfe] The binary operator > is not supported as a constant pattern. + } + + switch (o) { case 1 >= 2: // Error // ^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_BINARY // [cfe] The binary operator >= is not supported as a constant pattern. + } + + switch (o) { case 1 << 2: // Error // ^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_BINARY // [cfe] The binary operator << is not supported as a constant pattern. + } + + switch (o) { case 1 >> 2: // Error // ^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_BINARY // [cfe] The binary operator >> is not supported as a constant pattern. + } + + switch (o) { case 1 >>> 2: // Error // ^^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_BINARY // [cfe] The binary operator >>> is not supported as a constant pattern. + } + + switch (o) { case 1 + 2 + 3: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_BINARY // [cfe] The binary operator + is not supported as a constant pattern. + } + + switch (o) { case prefix.value as T: // Ok + } + + switch (o) { case prefix.Class.value as T: // Ok + } + + switch (o) { case const 1 as int: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const 1 + 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const 1 - 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const 1 * 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const 1 / 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const 1 ~/ 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const 1 % 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const 1 == 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const 1 != 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const 1 ^ 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const 1 & 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const 1 | 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const 1 < 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const 1 <= 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const 1 > 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const 1 >= 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const 1 << 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const 1 >> 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const 1 >>> 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const 1 + 2 + 3: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const Object() == 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const [] as List: // Ok + } + + switch (o) { case const (1 + 2): // Ok + } + + switch (o) { case const (1 - 2): // Ok + } + + switch (o) { case const (1 * 2): // Ok + } + + switch (o) { case const (1 / 2): // Ok + } + + switch (o) { case const (1 ~/ 2): // Ok + } + + switch (o) { case const (1 % 2): // Ok + } + + switch (o) { case const (1 == 2): // Ok + } + + switch (o) { case const (1 != 2): // Ok + } + + switch (o) { case const (1 ^ 2): // Ok + } + + switch (o) { case const (1 & 2): // Ok + } + + switch (o) { case const (1 | 2): // Ok + } + + switch (o) { case const (1 < 2): // Ok + } + + switch (o) { case const (1 <= 2): // Ok + } + + switch (o) { case const (1 > 2): // Ok + } + + switch (o) { case const (1 >= 2): // Ok + } + + switch (o) { case const (1 << 2): // Ok + } + + switch (o) { case const (1 >> 2): // Ok + } + + switch (o) { case const (1 >>> 2): // Ok + } + + switch (o) { case const (1 + 2 + 3): // Ok + } + + switch (o) { case 1 ?? 2: // Error // ^^ // [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN @@ -214,24 +412,32 @@ method(o) { // [analyzer] SYNTACTIC_ERROR.UNEXPECTED_TOKEN // [cfe] Expected an identifier, but got ':'. // [cfe] Unexpected token ':'. + } + + switch (o) { case o++: // Error - // ^ - // [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE // ^^^ // [analyzer] COMPILE_TIME_ERROR.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION // [cfe] Not a constant expression. + } + + switch (o) { case o--: // Error // ^^^ // [analyzer] COMPILE_TIME_ERROR.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION // [cfe] Not a constant expression. - // ^^ - // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_OPERATOR + } + + switch (o) { case ++o: // Error // ^^^ // [analyzer] COMPILE_TIME_ERROR.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION // ^ // [analyzer] COMPILE_TIME_ERROR.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION // [cfe] Not a constant expression. + } + + switch (o) { case --o: // Error // ^^^ // [analyzer] COMPILE_TIME_ERROR.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION diff --git a/tests/language/patterns/invalid_const_pattern_test.dart b/tests/language/patterns/invalid_const_pattern_test.dart index f29a9416e1e..206f0f700b0 100644 --- a/tests/language/patterns/invalid_const_pattern_test.dart +++ b/tests/language/patterns/invalid_const_pattern_test.dart @@ -22,42 +22,102 @@ class Class { dynamic variable = 0; switch (o) { case true: // Ok + } + + switch (o) { case null: // Ok + } + + switch (o) { case this: // Error // ^^^^ // [analyzer] COMPILE_TIME_ERROR.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION // [cfe] Not a constant expression. + } + + switch (o) { case this(): // Error // ^^^^^^ // [analyzer] COMPILE_TIME_ERROR.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION // [cfe] Not a constant expression. + } + + switch (o) { case super(): // Error // ^^^^^ // [analyzer] COMPILE_TIME_ERROR.INVOCATION_OF_NON_FUNCTION_EXPRESSION // ^^^^^^^ // [analyzer] COMPILE_TIME_ERROR.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION // [cfe] Method invocation is not a constant expression. + } + + switch (o) { case 42: // Ok + } + + switch (o) { case -42: // Ok + } + + switch (o) { case 42.5: // Ok + } + + switch (o) { case -42.5: // Ok + } + + switch (o) { case 'foo': // Ok + } + + switch (o) { case 'foo' 'bar': // Ok + } + + switch (o) { case value: // Ok + } + + switch (o) { case value!: // Ok + } + + switch (o) { case value?: // Ok + } + + switch (o) { case value as int: // Ok + } + + switch (o) { case -value: // Error // ^^^^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_NEGATION // [cfe] Only negation of a numeric literal is supported as a constant pattern. + } + + switch (o) { case local: // Ok + } + + switch (o) { case -local: // Error // ^^^^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_NEGATION // [cfe] Only negation of a numeric literal is supported as a constant pattern. + } + + switch (o) { case func: // Ok + } + + switch (o) { case prefix.value: // Ok + } + + switch (o) { case -prefix.value: // Error // ^^^^^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_NEGATION @@ -65,15 +125,27 @@ class Class { // ^^^^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_NEGATION // [cfe] Only negation of a numeric literal is supported as a constant pattern. + } + + switch (o) { case prefix.Class.named: // Ok + } + + switch (o) { case 1 + 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_BINARY // [cfe] The binary operator + is not supported as a constant pattern. + } + + switch (o) { case 1 * 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_BINARY // [cfe] The binary operator * is not supported as a constant pattern. + } + + switch (o) { case void fun() {}: // Error // ^ // [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN @@ -86,92 +158,155 @@ class Class { // [analyzer] SYNTACTIC_ERROR.UNEXPECTED_TOKEN // [cfe] Expected an identifier, but got ':'. // [cfe] Unexpected token ':'. + } + + switch (o) { case assert(false): // Error // ^^^^^^ // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_IDENTIFIER // ^^^^^^^^^^^^^ // [analyzer] COMPILE_TIME_ERROR.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION // [cfe] `assert` can't be used as an expression. + } + + switch (o) { case switch (o) { _ => true }: // Error // ^^^^^^^^^^^^^^^^^^^^^^^^ // [analyzer] COMPILE_TIME_ERROR.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION // [cfe] Not a constant expression. // ^ // [cfe] Not a constant expression. + } + + switch (o) { case await 0: // Error // ^^^^^^^ // [analyzer] COMPILE_TIME_ERROR.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION // [cfe] Not a constant expression. + } + + switch (o) { case !false: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_UNARY // [cfe] The unary operator ! is not supported as a constant pattern. + } + + switch (o) { case ~0: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_UNARY // [cfe] The unary operator ~ is not supported as a constant pattern. + } + + switch (o) { case ++variable: // Error // ^^^^^^^^^^ // [analyzer] COMPILE_TIME_ERROR.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION // ^^^^^^^^ // [analyzer] COMPILE_TIME_ERROR.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION // [cfe] Not a constant expression. + } + + switch (o) { case const 0: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const 0x0: // Error // ^^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const 0.5: // Error // ^^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const true: // Error // ^^^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const null: // Error // ^^^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const -0: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const 'foo': // Error // ^^^^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const #a: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const value: // Error // ^^^^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const local: // Error // ^^^^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const prefix.value: // Error // ^^^^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const -prefix.value: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const prefix.Class.named: // Error // ^^^^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const 1 + 2: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_CONST_PREFIX // [cfe] The expression can't be prefixed by 'const' to form a constant pattern. + } + + switch (o) { case const void fun() {}: // Error // ^ // [cfe] Not a constant expression. @@ -180,140 +315,281 @@ class Class { // [cfe] A function expression can't have a name. // ^^^^^ // [analyzer] COMPILE_TIME_ERROR.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION + } + + switch (o) { case const assert(false): // Error // ^^^^^^ // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_IDENTIFIER // ^^^^^^^^^^^^^ // [analyzer] COMPILE_TIME_ERROR.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION // [cfe] `assert` can't be used as an expression. + } + + switch (o) { case const switch (o) { _ => true }: // Error // ^^^^^^^^^^^^^^^^^^^^^^^^ // [analyzer] COMPILE_TIME_ERROR.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION // [cfe] Not a constant expression. // ^ // [cfe] Not a constant expression. + } + + switch (o) { case const await 0: // Error // ^^^^^^^ // [analyzer] COMPILE_TIME_ERROR.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION // [cfe] Not a constant expression. + } + + switch (o) { case const !false: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_UNARY // [cfe] The unary operator ! is not supported as a constant pattern. + } + + switch (o) { case const ~0: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_UNARY // [cfe] The unary operator ~ is not supported as a constant pattern. + } + + switch (o) { case const ++variable: // Error // ^^^^^^^^^^ // [analyzer] COMPILE_TIME_ERROR.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION // ^^^^^^^^ // [analyzer] COMPILE_TIME_ERROR.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION // [cfe] Not a constant expression. + } + + switch (o) { case const Class(): // Ok + } + + switch (o) { case const Class(0): // Ok + } + + switch (o) { case const GenericClass(): // Ok + } + + switch (o) { case const GenericClass(a: 0): // Ok + } + + switch (o) { case const GenericClass(): // Ok + } + + switch (o) { case const GenericClass(a: 0): // Ok + } + + switch (o) { case const GenericClass.new(): // Ok + } + + switch (o) { case const GenericClass.new(a: 1): // Ok + } + + switch (o) { case const []: // Ok + } + + switch (o) { case const []: // Ok + } + + switch (o) { case const {}: // Ok + } + + switch (o) { case const {}: // Ok + } + + switch (o) { case const const Class(): // Error // ^^^^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_DUPLICATE_CONST // [cfe] Duplicate 'const' keyword in constant expression. + } + + switch (o) { case const const Class(0): // Error // ^^^^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_DUPLICATE_CONST // [cfe] Duplicate 'const' keyword in constant expression. + } + + switch (o) { case const const GenericClass(): // Error // ^^^^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_DUPLICATE_CONST // [cfe] Duplicate 'const' keyword in constant expression. + } + + switch (o) { case const const GenericClass(a: 0): // Error // ^^^^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_DUPLICATE_CONST // [cfe] Duplicate 'const' keyword in constant expression. + } + + switch (o) { case const const GenericClass(): // Error // ^^^^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_DUPLICATE_CONST // [cfe] Duplicate 'const' keyword in constant expression. + } + + switch (o) { case const const GenericClass(a: 0): // Error // ^^^^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_DUPLICATE_CONST // [cfe] Duplicate 'const' keyword in constant expression. + } + + switch (o) { case const const []: // Error // ^^^^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_DUPLICATE_CONST // [cfe] Duplicate 'const' keyword in constant expression. + } + + switch (o) { case const const []: // Error // ^^^^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_DUPLICATE_CONST // [cfe] Duplicate 'const' keyword in constant expression. + } + + switch (o) { case const const {}: // Error // ^^^^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_DUPLICATE_CONST // [cfe] Duplicate 'const' keyword in constant expression. + } + + switch (o) { case const const {}: // Error // ^^^^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_DUPLICATE_CONST // [cfe] Duplicate 'const' keyword in constant expression. + } + + switch (o) { case const new Class(): // Error // ^^^^^^^^^^^ // [analyzer] COMPILE_TIME_ERROR.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION // [cfe] New expression is not a constant expression. // ^ // [cfe] New expression is not a constant expression. + } + + switch (o) { case new Class(): // Error // ^^^^^^^^^^^ // [analyzer] COMPILE_TIME_ERROR.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION // [cfe] New expression is not a constant expression. // ^ // [cfe] New expression is not a constant expression. + } + + switch (o) { case const (): // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_EMPTY_RECORD_LITERAL // [cfe] The empty record literal is not supported as a constant pattern. + } + + switch (o) { case const const (): // Error // ^^^^^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_DUPLICATE_CONST // [cfe] Duplicate 'const' keyword in constant expression. + } + + switch (o) { case const (1): // Ok + } + + switch (o) { case const (-1): // Ok + } + + switch (o) { case const (value): // Ok + } + + switch (o) { case const (-value): // Ok + } + + switch (o) { case const (1 + 2): // Ok + } + + switch (o) { case GenericClass: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_GENERIC // [cfe] This expression is not supported as a constant pattern. + } + + switch (o) { case prefix.GenericClass: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_GENERIC // [cfe] This expression is not supported as a constant pattern. + } + + switch (o) { case GenericClass.new: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_GENERIC // [cfe] This expression is not supported as a constant pattern. + } + + switch (o) { case prefix.GenericClass.new: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_GENERIC // [cfe] This expression is not supported as a constant pattern. + } + + switch (o) { case const GenericClass: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_GENERIC // [cfe] This expression is not supported as a constant pattern. + } + + switch (o) { case const prefix.GenericClass: // Error // ^ // [analyzer] SYNTACTIC_ERROR.INVALID_CONSTANT_PATTERN_GENERIC // [cfe] This expression is not supported as a constant pattern. + } + + switch (o) { case const (GenericClass): // Ok + } + + switch (o) { case const (prefix.GenericClass): // Ok + } + + switch (o) { case const (GenericClass.new): // Ok + } + + switch (o) { case const (prefix.GenericClass.new): // Ok print(0); } diff --git a/tests/language/patterns/switch_case_scope_error_test.dart b/tests/language/patterns/switch_case_scope_error_test.dart index 66028a2135d..884282b1d9e 100644 --- a/tests/language/patterns/switch_case_scope_error_test.dart +++ b/tests/language/patterns/switch_case_scope_error_test.dart @@ -10,7 +10,7 @@ main() { // If cases sharing a body don't agree on a variable's finality, it is still // considered in scope and an error to use. switch ('value') { - case final int local: + case final int local when false: // Guard to make the next case reachable. case int local: print(local); // ^^^^^ diff --git a/tests/language/patterns/version_2_29_changes_error_test.dart b/tests/language/patterns/version_2_29_changes_error_test.dart index 991aac285e2..af2e3a67c74 100644 --- a/tests/language/patterns/version_2_29_changes_error_test.dart +++ b/tests/language/patterns/version_2_29_changes_error_test.dart @@ -26,9 +26,9 @@ main() { // It's an error to have an empty map pattern. switch (map) { case {}: - // ^^ - // [analyzer] unspecified - // [cfe] unspecified +// ^^^^ +// [analyzer] HINT.UNREACHABLE_SWITCH_CASE +// [cfe] unspecified } // Later cases may be unreachable because map patterns ignore extra keys. diff --git a/tests/language/switch/case_runtime_test.dart b/tests/language/switch/case_runtime_test.dart index 44f2412499e..804230ca13d 100644 --- a/tests/language/switch/case_runtime_test.dart +++ b/tests/language/switch/case_runtime_test.dart @@ -1,6 +1,3 @@ -// TODO(multitest): This was automatically migrated from a multitest and may -// contain strange or dead code. - // Copyright (c) 2014, 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. @@ -16,8 +13,6 @@ class A { class B implements A { const B(); - - } class C implements D { @@ -32,27 +27,27 @@ class D implements A { } main() { - switch (new B()) { - - } - switch (new C()) { case const C(): Expect.fail("bad switch"); break; + } + + switch (new C()) { case const A.C() as C: Expect.fail("bad switch"); break; + } + + switch (new C()) { case const A.C2() as C: Expect.fail("bad switch"); break; - } switch (new A()) { case const A(): Expect.fail("bad switch"); break; - } }