Checks whether the type of a switch expression is assignable to the
types of its case expressions.
Resolves the first part of
https://github.com/dart-lang/sdk/issues/34207. According to the
language team the second part may soon become irrelevant.
Change-Id: Ifce38f2a62c293156dafa94f16799d5a126c6b9c
Reviewed-on: https://dart-review.googlesource.com/71981
Commit-Queue: Daniel Hillerström <hillerstrom@google.com>
Reviewed-by: Aske Simon Christensen <askesc@google.com>
diff --git a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
index 1e4d3a4..7855f44 100644
--- a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
+++ b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
@@ -6747,6 +6747,54 @@
message: r"""Switch case may fall through to the next case.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+ Message Function(
+ DartType _type,
+ DartType
+ _type2)> templateSwitchExpressionNotAssignable = const Template<
+ Message Function(DartType _type, DartType _type2)>(
+ messageTemplate:
+ r"""Type '#type' of the switch expression isn't assignable to the type '#type2' of this case expression.""",
+ withArguments: _withArgumentsSwitchExpressionNotAssignable);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(DartType _type, DartType _type2)>
+ codeSwitchExpressionNotAssignable =
+ const Code<Message Function(DartType _type, DartType _type2)>(
+ "SwitchExpressionNotAssignable", templateSwitchExpressionNotAssignable,
+ analyzerCode: "SWITCH_EXPRESSION_NOT_ASSIGNABLE",
+ severity: Severity.error);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsSwitchExpressionNotAssignable(
+ DartType _type, DartType _type2) {
+ NameSystem nameSystem = new NameSystem();
+ StringBuffer buffer;
+ buffer = new StringBuffer();
+ new Printer(buffer, syntheticNames: nameSystem).writeNode(_type);
+ String type = '$buffer';
+
+ buffer = new StringBuffer();
+ new Printer(buffer, syntheticNames: nameSystem).writeNode(_type2);
+ String type2 = '$buffer';
+
+ return new Message(codeSwitchExpressionNotAssignable,
+ message:
+ """Type '${type}' of the switch expression isn't assignable to the type '${type2}' of this case expression.""",
+ arguments: {'type': _type, 'type2': _type2});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeSwitchExpressionNotAssignableCause =
+ messageSwitchExpressionNotAssignableCause;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageSwitchExpressionNotAssignableCause = const MessageCode(
+ "SwitchExpressionNotAssignableCause",
+ severity: Severity.context,
+ message: r"""The switch expression is here.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeSwitchHasCaseAfterDefault =
messageSwitchHasCaseAfterDefault;
diff --git a/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart b/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart
index a1ca4c0..af00914 100644
--- a/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart
@@ -158,7 +158,8 @@
void addCompileTimeError(Message message, int charOffset, int length,
{List<LocatedMessage> context});
- void addProblem(Message message, int charOffset, int length);
+ void addProblem(Message message, int charOffset, int length,
+ {List<LocatedMessage> context});
void addProblemErrorIfConst(Message message, int charOffset, int length);
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
index 88b7b7e..c6ab5e4 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
@@ -37,12 +37,14 @@
import '../fasta_codes.dart'
show
+ messageSwitchExpressionNotAssignableCause,
messageVoidExpression,
noLength,
templateCantInferTypeDueToCircularity,
templateCantUseSuperBoundedTypeForInstanceCreation,
templateForInLoopElementTypeNotAssignable,
- templateForInLoopTypeNotIterable;
+ templateForInLoopTypeNotIterable,
+ templateSwitchExpressionNotAssignable;
import '../problems.dart' show unhandled, unsupported;
@@ -2710,14 +2712,30 @@
var expressionJudgment = this.expressionJudgment;
inferrer.inferExpression(expressionJudgment, const UnknownType(), true);
var expressionType = expressionJudgment.inferredType;
+
for (var switchCase in caseJudgments) {
for (var caseExpression in switchCase.expressionJudgments) {
- inferrer.inferExpression(caseExpression, expressionType, false);
+ DartType caseExpressionType =
+ inferrer.inferExpression(caseExpression, expressionType, true);
+
+ // Check whether the expression type is assignable to the case expression type.
+ if (!inferrer.isAssignable(expressionType, caseExpressionType)) {
+ inferrer.helper.addProblem(
+ templateSwitchExpressionNotAssignable.withArguments(
+ expressionType, caseExpressionType),
+ caseExpression.fileOffset,
+ noLength,
+ context: [
+ messageSwitchExpressionNotAssignableCause.withLocation(
+ inferrer.uri, expressionJudgment.fileOffset, noLength)
+ ]);
+ }
}
inferrer.inferStatement(switchCase.bodyJudgment);
// TODO(paulberry): support labels.
inferrer.listener.switchCase(switchCase, null, null, null, null, null);
}
+
inferrer.listener
.switchStatement(this, fileOffset, tokens, expression, cases);
}
diff --git a/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart b/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart
index 38505c3..1a05738 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart
@@ -16,7 +16,8 @@
LocatedMessage checkArgumentsForType(
FunctionType function, ArgumentsJudgment arguments, int offset);
- void addProblem(Message message, int charOffset, int length);
+ void addProblem(Message message, int charOffset, int length,
+ {List<LocatedMessage> context});
Expression wrapInProblem(Expression expression, Message message, int length,
{List<LocatedMessage> context});
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index fe4e2fb..a1be91c 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -2152,6 +2152,22 @@
tip: "To delegate a constructor to a super constructor, put the super call as an initializer."
analyzerCode: SUPER_AS_EXPRESSION
+SwitchExpressionNotAssignable:
+ template: "Type '#type' of the switch expression isn't assignable to the type '#type2' of this case expression."
+ severity: ERROR
+ analyzerCode: SWITCH_EXPRESSION_NOT_ASSIGNABLE
+ script:
+ - >-
+ void f() {
+ switch (42) {
+ case "foo": break;
+ }
+ }
+
+SwitchExpressionNotAssignableCause:
+ template: "The switch expression is here."
+ severity: CONTEXT
+
SwitchHasCaseAfterDefault:
template: "The default case should be the last case in a switch statement."
tip: "Try moving the default case after the other case clauses."
diff --git a/tests/co19/co19-kernel.status b/tests/co19/co19-kernel.status
index 594f662..3eab189 100644
--- a/tests/co19/co19-kernel.status
+++ b/tests/co19/co19-kernel.status
@@ -1049,9 +1049,6 @@
Language/Statements/Switch/execution_case_no_default_t02: CompileTimeError
Language/Statements/Switch/execution_case_t02: CompileTimeError
Language/Statements/Switch/execution_t01: CompileTimeError
-Language/Statements/Switch/expressions_t01: MissingCompileTimeError
-Language/Statements/Switch/expressions_t02: MissingCompileTimeError
-Language/Statements/Switch/expressions_t04: MissingCompileTimeError
Language/Statements/Switch/last_statement_t01: CompileTimeError
Language/Statements/Switch/scope_t02: CompileTimeError
Language/Statements/Switch/type_t01: CompileTimeError
diff --git a/tests/co19_2/co19_2-kernel.status b/tests/co19_2/co19_2-kernel.status
index 140c019..b78c3e4 100644
--- a/tests/co19_2/co19_2-kernel.status
+++ b/tests/co19_2/co19_2-kernel.status
@@ -155,12 +155,6 @@
Language/Statements/Continue/label_t07: MissingCompileTimeError # Issue 34206
Language/Statements/Switch/equal_operator_t01: MissingCompileTimeError # Issue 32557
Language/Statements/Switch/equal_operator_t02: MissingCompileTimeError # Issue 32557
-Language/Statements/Switch/execution_t01: MissingCompileTimeError # Issue 34207
-Language/Statements/Switch/expressions_t01: MissingCompileTimeError # Issue 34207
-Language/Statements/Switch/expressions_t02: MissingCompileTimeError # Issue 34207
-Language/Statements/Switch/expressions_t04: MissingCompileTimeError # Issue 34207
-Language/Statements/Switch/type_t01: MissingCompileTimeError # Issue 34207
-Language/Statements/Switch/type_t02: MissingCompileTimeError # Issue 34207
Language/Statements/Try/catch_scope_t01: CompileTimeError
Language/Types/Dynamic_Type_System/malbounded_type_error_t01: MissingCompileTimeError # Issue 33308
Language/Types/Interface_Types/subtype_t30: CompileTimeError
diff --git a/tests/language_2/language_2_dart2js.status b/tests/language_2/language_2_dart2js.status
index a079eb5..98d11b6 100644
--- a/tests/language_2/language_2_dart2js.status
+++ b/tests/language_2/language_2_dart2js.status
@@ -219,7 +219,6 @@
const_init2_test/02: MissingCompileTimeError
const_map2_test/00: MissingCompileTimeError
const_map3_test/00: MissingCompileTimeError
-const_switch2_test/01: MissingCompileTimeError
const_switch_test/02: RuntimeError, OK # constant identity based on JS constants
const_switch_test/04: RuntimeError, OK # constant identity based on JS constants
const_types_test/01: MissingCompileTimeError
@@ -557,7 +556,6 @@
const_map2_test/00: MissingCompileTimeError
const_map3_test/00: MissingCompileTimeError
const_map4_test: RuntimeError
-const_switch2_test/01: MissingCompileTimeError
const_switch_test/02: RuntimeError, OK # constant identity based on JS constants
const_switch_test/04: RuntimeError, OK # constant identity based on JS constants
constructor12_test: RuntimeError
diff --git a/tests/language_2/language_2_dartdevc.status b/tests/language_2/language_2_dartdevc.status
index cb05f47..6b9305d 100644
--- a/tests/language_2/language_2_dartdevc.status
+++ b/tests/language_2/language_2_dartdevc.status
@@ -263,7 +263,6 @@
const_map2_test/00: MissingCompileTimeError
const_map3_test/00: MissingCompileTimeError
const_optional_args_test/01: MissingCompileTimeError
-const_switch2_test/01: MissingCompileTimeError
const_syntax_test/05: MissingCompileTimeError
constants_test/05: MissingCompileTimeError
covariant_subtyping_test: RuntimeError
diff --git a/tests/language_2/language_2_kernel.status b/tests/language_2/language_2_kernel.status
index ca5235e..ea7e5db 100644
--- a/tests/language_2/language_2_kernel.status
+++ b/tests/language_2/language_2_kernel.status
@@ -355,7 +355,6 @@
[ $compiler != dart2analyzer && $fasta ]
const_map2_test/00: MissingCompileTimeError # KernelVM bug: Constant evaluation.
const_map3_test/00: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-const_switch2_test/01: MissingCompileTimeError # KernelVM bug: Constant evaluation.
invalid_returns/async_invalid_return_05_test: MissingCompileTimeError
invalid_returns/async_invalid_return_06_test: MissingCompileTimeError
invalid_returns/async_invalid_return_07_test: MissingCompileTimeError