diff --git a/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer.dart b/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer.dart index 33e2e4e4b36..e24d463420d 100644 --- a/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer.dart +++ b/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer.dart @@ -1184,6 +1184,12 @@ mixin TypeAnalyzer< _finishJoinedVariables(variables, reportErrors: false); handleCase_afterCaseHeads(node, caseIndex, variables.values); // Stack: (Expression, numExecutionPaths * StatementCase, CaseHeads) + // If there are joined variables, declare them. + if (heads.length > 1 || memberInfo.hasLabels) { + for (Variable variable in variables.values) { + flow?.declare(variable, true); + } + } for (Statement statement in memberInfo.body) { dispatchStatement(statement); } diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart index 6cdf6326219..ae0929a8f8f 100644 --- a/pkg/analyzer/lib/src/dart/ast/ast.dart +++ b/pkg/analyzer/lib/src/dart/ast/ast.dart @@ -12513,6 +12513,9 @@ class SwitchStatementCaseGroup { final List members; final bool hasLabels; + /// Joined variables declared in [members], available in [statements]. + late final Map variables; + SwitchStatementCaseGroup(this.members, this.hasLabels); NodeListImpl get statements { diff --git a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart index 9b961bc9efa..6e18d0b62c3 100644 --- a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart +++ b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart @@ -670,14 +670,29 @@ class _AssignedVariablesVisitor extends RecursiveAstVisitor { } @override - void visitSwitchStatement(SwitchStatement node) { - var expression = node.expression; - var members = node.members; - - expression.accept(this); + void visitSwitchStatement(covariant SwitchStatementImpl node) { + node.expression.accept(this); assignedVariables.beginNode(); - members.accept(this); + for (var group in node.memberGroups) { + for (var member in group.members) { + if (member is SwitchCaseImpl) { + member.expression.accept(this); + } else if (member is SwitchPatternCaseImpl) { + var guardedPattern = member.guardedPattern; + assignedVariables.beginNode(); + for (var variable in guardedPattern.variables.values) { + assignedVariables.declare(variable); + } + guardedPattern.whenClause?.accept(this); + assignedVariables.endNode(node); + } + } + for (var variable in group.variables.values) { + assignedVariables.declare(variable); + } + group.statements.accept(this); + } assignedVariables.endNode(node); } diff --git a/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart index 9ad8615e361..b454767af8a 100644 --- a/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart +++ b/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart @@ -1162,8 +1162,8 @@ class ResolutionVisitor extends RecursiveAstVisitor { if (group.hasLabels) { _patternVariables.switchStatementSharedCaseScopeEmpty(node); } - // TODO(scheglov) use variables - _patternVariables.switchStatementSharedCaseScopeFinish(node); + group.variables = + _patternVariables.switchStatementSharedCaseScopeFinish(node); _withNameScope(() { var statements = group.statements; _buildLocalElements(statements); diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart index 7a649e9863d..d977a62e7c7 100644 --- a/pkg/analyzer/lib/src/generated/resolver.dart +++ b/pkg/analyzer/lib/src/generated/resolver.dart @@ -942,7 +942,7 @@ class ResolverVisitor extends ThrowingAstVisitor var guardedPattern = member.guardedPattern; return CaseHeadOrDefaultInfo( pattern: guardedPattern.pattern, - variables: {}, // TODO(scheglov) use actual + variables: guardedPattern.variables, guard: guardedPattern.whenClause?.expression, ); } else { @@ -958,7 +958,7 @@ class ResolverVisitor extends ThrowingAstVisitor return SwitchStatementMemberInfo( group.members.map(ofMember).toList(), group.statements, - {}, + group.variables, hasLabels: group.hasLabels, ); } @@ -4585,23 +4585,7 @@ class ScopeResolverVisitor extends UnifyingAstVisitor { } @override - void visitSwitchCase(SwitchCase node) { - node.expression.accept(this); - - _withDeclaredLocals(node, node.statements, () { - node.statements.accept(this); - }); - } - - @override - void visitSwitchDefault(SwitchDefault node) { - _withDeclaredLocals(node, node.statements, () { - node.statements.accept(this); - }); - } - - @override - void visitSwitchStatement(SwitchStatement node) { + void visitSwitchStatement(covariant SwitchStatementImpl node) { var outerScope = labelScope; ImplicitLabelScope outerImplicitScope = _implicitLabelScope; try { @@ -4614,17 +4598,34 @@ class ScopeResolverVisitor extends UnifyingAstVisitor { LabelScope(labelScope, labelName.name, member, labelElement); } } - visitSwitchStatementInScope(node); + node.expression.accept(this); + for (var group in node.memberGroups) { + for (var member in group.members) { + if (member is SwitchCaseImpl) { + member.expression.accept(this); + } else if (member is SwitchPatternCaseImpl) { + _withNameScope(() { + var variables = member.guardedPattern.variables; + for (var variable in variables.values) { + _define(variable); + } + member.guardedPattern.accept(this); + }); + } + } + _withDeclaredLocals(node, group.statements, () { + for (var variable in group.variables.values) { + _define(variable); + } + group.statements.accept(this); + }); + } } finally { labelScope = outerScope; _implicitLabelScope = outerImplicitScope; } } - void visitSwitchStatementInScope(SwitchStatement node) { - super.visitSwitchStatement(node); - } - @override void visitVariableDeclaration(VariableDeclaration node) { super.visitVariableDeclaration(node); diff --git a/pkg/analyzer/test/src/dart/resolution/local_function_test.dart b/pkg/analyzer/test/src/dart/resolution/local_function_test.dart index 7cc499539ec..72abcb131f4 100644 --- a/pkg/analyzer/test/src/dart/resolution/local_function_test.dart +++ b/pkg/analyzer/test/src/dart/resolution/local_function_test.dart @@ -45,7 +45,6 @@ f() { expect(element.nameOffset, 23); } - @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/50502') test_element_switchCase() async { await assertNoErrorsInCode(r''' f(int a) { diff --git a/pkg/analyzer/test/src/dart/resolution/switch_statement_test.dart b/pkg/analyzer/test/src/dart/resolution/switch_statement_test.dart index 8a0df8cf6a9..3c05cb4d64c 100644 --- a/pkg/analyzer/test/src/dart/resolution/switch_statement_test.dart +++ b/pkg/analyzer/test/src/dart/resolution/switch_statement_test.dart @@ -2,18 +2,20 @@ // 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 'context_collection_resolution.dart'; main() { defineReflectiveSuite(() { - defineReflectiveTests(SwitchStatementPatternTest); + defineReflectiveTests(SwitchStatementResolutionTest); + defineReflectiveTests(SwitchStatementResolutionTest_Language218); }); } @reflectiveTest -class SwitchStatementPatternTest extends PatternsResolutionTest { +class SwitchStatementResolutionTest extends PubPackageResolutionTest { test_default() async { await assertNoErrorsInCode(r''' void f(Object? x) { @@ -228,6 +230,797 @@ SwitchStatement '''); } + test_variables_joinedCase_declareBoth_consistent() async { + await assertNoErrorsInCode(r''' +void f(Object? x) { + switch (x) { + case int a when a < 0: + case int a when a > 0: + a; + } +} +'''); + + final node = findNode.switchStatement('switch'); + assertResolvedNodeText(node, r''' +SwitchStatement + switchKeyword: switch + leftParenthesis: ( + expression: SimpleIdentifier + token: x + staticElement: self::@function::f::@parameter::x + staticType: Object? + rightParenthesis: ) + leftBracket: { + members + SwitchPatternCase + keyword: case + guardedPattern: GuardedPattern + pattern: VariablePattern + type: NamedType + name: SimpleIdentifier + token: int + staticElement: dart:core::@class::int + staticType: null + type: int + name: a + declaredElement: a@48 + type: int + whenClause: WhenClause + whenKeyword: when + expression: BinaryExpression + leftOperand: SimpleIdentifier + token: a + staticElement: a@48 + staticType: int + operator: < + rightOperand: IntegerLiteral + literal: 0 + parameter: dart:core::@class::num::@method::<::@parameter::other + staticType: int + staticElement: dart:core::@class::num::@method::< + staticInvokeType: bool Function(num) + staticType: bool + colon: : + SwitchPatternCase + keyword: case + guardedPattern: GuardedPattern + pattern: VariablePattern + type: NamedType + name: SimpleIdentifier + token: int + staticElement: dart:core::@class::int + staticType: null + type: int + name: a + declaredElement: a@75 + type: int + whenClause: WhenClause + whenKeyword: when + expression: BinaryExpression + leftOperand: SimpleIdentifier + token: a + staticElement: a@75 + staticType: int + operator: > + rightOperand: IntegerLiteral + literal: 0 + parameter: dart:core::@class::num::@method::>::@parameter::other + staticType: int + staticElement: dart:core::@class::num::@method::> + staticInvokeType: bool Function(num) + staticType: bool + colon: : + statements + ExpressionStatement + expression: SimpleIdentifier + token: a + staticElement: a[a@48, a@75] + staticType: int + semicolon: ; + rightBracket: } +'''); + } + + test_variables_joinedCase_declareBoth_consistent_final() async { + await assertNoErrorsInCode(r''' +void f(Object? x) { + switch (x) { + case final int a when a < 0: + case final int a when a > 0: + a; + } +} +'''); + + final node = findNode.switchStatement('switch'); + assertResolvedNodeText(node, r''' +SwitchStatement + switchKeyword: switch + leftParenthesis: ( + expression: SimpleIdentifier + token: x + staticElement: self::@function::f::@parameter::x + staticType: Object? + rightParenthesis: ) + leftBracket: { + members + SwitchPatternCase + keyword: case + guardedPattern: GuardedPattern + pattern: VariablePattern + keyword: final + type: NamedType + name: SimpleIdentifier + token: int + staticElement: dart:core::@class::int + staticType: null + type: int + name: a + declaredElement: isFinal a@54 + type: int + whenClause: WhenClause + whenKeyword: when + expression: BinaryExpression + leftOperand: SimpleIdentifier + token: a + staticElement: a@54 + staticType: int + operator: < + rightOperand: IntegerLiteral + literal: 0 + parameter: dart:core::@class::num::@method::<::@parameter::other + staticType: int + staticElement: dart:core::@class::num::@method::< + staticInvokeType: bool Function(num) + staticType: bool + colon: : + SwitchPatternCase + keyword: case + guardedPattern: GuardedPattern + pattern: VariablePattern + keyword: final + type: NamedType + name: SimpleIdentifier + token: int + staticElement: dart:core::@class::int + staticType: null + type: int + name: a + declaredElement: isFinal a@87 + type: int + whenClause: WhenClause + whenKeyword: when + expression: BinaryExpression + leftOperand: SimpleIdentifier + token: a + staticElement: a@87 + staticType: int + operator: > + rightOperand: IntegerLiteral + literal: 0 + parameter: dart:core::@class::num::@method::>::@parameter::other + staticType: int + staticElement: dart:core::@class::num::@method::> + staticInvokeType: bool Function(num) + staticType: bool + colon: : + statements + ExpressionStatement + expression: SimpleIdentifier + token: a + staticElement: final a[a@54, a@87] + staticType: int + semicolon: ; + rightBracket: } +'''); + } + + test_variables_joinedCase_declareBoth_notConsistent_differentFinality() async { + await assertNoErrorsInCode(r''' +void f(Object? x) { + switch (x) { + case final int a when a < 0: + case num a when a > 0: + a; + } +} +'''); + + final node = findNode.switchStatement('switch'); + assertResolvedNodeText(node, r''' +SwitchStatement + switchKeyword: switch + leftParenthesis: ( + expression: SimpleIdentifier + token: x + staticElement: self::@function::f::@parameter::x + staticType: Object? + rightParenthesis: ) + leftBracket: { + members + SwitchPatternCase + keyword: case + guardedPattern: GuardedPattern + pattern: VariablePattern + keyword: final + type: NamedType + name: SimpleIdentifier + token: int + staticElement: dart:core::@class::int + staticType: null + type: int + name: a + declaredElement: isFinal a@54 + type: int + whenClause: WhenClause + whenKeyword: when + expression: BinaryExpression + leftOperand: SimpleIdentifier + token: a + staticElement: a@54 + staticType: int + operator: < + rightOperand: IntegerLiteral + literal: 0 + parameter: dart:core::@class::num::@method::<::@parameter::other + staticType: int + staticElement: dart:core::@class::num::@method::< + staticInvokeType: bool Function(num) + staticType: bool + colon: : + SwitchPatternCase + keyword: case + guardedPattern: GuardedPattern + pattern: VariablePattern + type: NamedType + name: SimpleIdentifier + token: num + staticElement: dart:core::@class::num + staticType: null + type: num + name: a + declaredElement: a@81 + type: num + whenClause: WhenClause + whenKeyword: when + expression: BinaryExpression + leftOperand: SimpleIdentifier + token: a + staticElement: a@81 + staticType: num + operator: > + rightOperand: IntegerLiteral + literal: 0 + parameter: dart:core::@class::num::@method::>::@parameter::other + staticType: int + staticElement: dart:core::@class::num::@method::> + staticInvokeType: bool Function(num) + staticType: bool + colon: : + statements + ExpressionStatement + expression: SimpleIdentifier + token: a + staticElement: notConsistent a[a@54, a@81] + staticType: dynamic + semicolon: ; + rightBracket: } +'''); + } + + test_variables_joinedCase_declareBoth_notConsistent_differentTypes() async { + await assertNoErrorsInCode(r''' +void f(Object? x) { + switch (x) { + case int a when a < 0: + case num a when a > 0: + a; + } +} +'''); + + final node = findNode.switchStatement('switch'); + assertResolvedNodeText(node, r''' +SwitchStatement + switchKeyword: switch + leftParenthesis: ( + expression: SimpleIdentifier + token: x + staticElement: self::@function::f::@parameter::x + staticType: Object? + rightParenthesis: ) + leftBracket: { + members + SwitchPatternCase + keyword: case + guardedPattern: GuardedPattern + pattern: VariablePattern + type: NamedType + name: SimpleIdentifier + token: int + staticElement: dart:core::@class::int + staticType: null + type: int + name: a + declaredElement: a@48 + type: int + whenClause: WhenClause + whenKeyword: when + expression: BinaryExpression + leftOperand: SimpleIdentifier + token: a + staticElement: a@48 + staticType: int + operator: < + rightOperand: IntegerLiteral + literal: 0 + parameter: dart:core::@class::num::@method::<::@parameter::other + staticType: int + staticElement: dart:core::@class::num::@method::< + staticInvokeType: bool Function(num) + staticType: bool + colon: : + SwitchPatternCase + keyword: case + guardedPattern: GuardedPattern + pattern: VariablePattern + type: NamedType + name: SimpleIdentifier + token: num + staticElement: dart:core::@class::num + staticType: null + type: num + name: a + declaredElement: a@75 + type: num + whenClause: WhenClause + whenKeyword: when + expression: BinaryExpression + leftOperand: SimpleIdentifier + token: a + staticElement: a@75 + staticType: num + operator: > + rightOperand: IntegerLiteral + literal: 0 + parameter: dart:core::@class::num::@method::>::@parameter::other + staticType: int + staticElement: dart:core::@class::num::@method::> + staticInvokeType: bool Function(num) + staticType: bool + colon: : + statements + ExpressionStatement + expression: SimpleIdentifier + token: a + staticElement: notConsistent a[a@48, a@75] + staticType: dynamic + semicolon: ; + rightBracket: } +'''); + } + + test_variables_joinedCase_declareFirst() async { + await assertNoErrorsInCode(r''' +void f(Object? x) { + switch (x) { + case 0: + case int a when a > 0: + a; + } +} +'''); + + final node = findNode.switchStatement('switch'); + assertResolvedNodeText(node, r''' +SwitchStatement + switchKeyword: switch + leftParenthesis: ( + expression: SimpleIdentifier + token: x + staticElement: self::@function::f::@parameter::x + staticType: Object? + rightParenthesis: ) + leftBracket: { + members + SwitchPatternCase + keyword: case + guardedPattern: GuardedPattern + pattern: ConstantPattern + expression: IntegerLiteral + literal: 0 + staticType: int + colon: : + SwitchPatternCase + keyword: case + guardedPattern: GuardedPattern + pattern: VariablePattern + type: NamedType + name: SimpleIdentifier + token: int + staticElement: dart:core::@class::int + staticType: null + type: int + name: a + declaredElement: a@60 + type: int + whenClause: WhenClause + whenKeyword: when + expression: BinaryExpression + leftOperand: SimpleIdentifier + token: a + staticElement: a@60 + staticType: int + operator: > + rightOperand: IntegerLiteral + literal: 0 + parameter: dart:core::@class::num::@method::>::@parameter::other + staticType: int + staticElement: dart:core::@class::num::@method::> + staticInvokeType: bool Function(num) + staticType: bool + colon: : + statements + ExpressionStatement + expression: SimpleIdentifier + token: a + staticElement: notConsistent a[a@60] + staticType: int + semicolon: ; + rightBracket: } +'''); + } + + test_variables_joinedCase_declareSecond() async { + await assertNoErrorsInCode(r''' +void f(Object? x) { + switch (x) { + case int a when a > 0: + case 0: + a; + } +} +'''); + + final node = findNode.switchStatement('switch'); + assertResolvedNodeText(node, r''' +SwitchStatement + switchKeyword: switch + leftParenthesis: ( + expression: SimpleIdentifier + token: x + staticElement: self::@function::f::@parameter::x + staticType: Object? + rightParenthesis: ) + leftBracket: { + members + SwitchPatternCase + keyword: case + guardedPattern: GuardedPattern + pattern: VariablePattern + type: NamedType + name: SimpleIdentifier + token: int + staticElement: dart:core::@class::int + staticType: null + type: int + name: a + declaredElement: a@48 + type: int + whenClause: WhenClause + whenKeyword: when + expression: BinaryExpression + leftOperand: SimpleIdentifier + token: a + staticElement: a@48 + staticType: int + operator: > + rightOperand: IntegerLiteral + literal: 0 + parameter: dart:core::@class::num::@method::>::@parameter::other + staticType: int + staticElement: dart:core::@class::num::@method::> + staticInvokeType: bool Function(num) + staticType: bool + colon: : + SwitchPatternCase + keyword: case + guardedPattern: GuardedPattern + pattern: ConstantPattern + expression: IntegerLiteral + literal: 0 + staticType: int + colon: : + statements + ExpressionStatement + expression: SimpleIdentifier + token: a + staticElement: notConsistent a[a@48] + staticType: int + semicolon: ; + rightBracket: } +'''); + } + + test_variables_joinedCase_hasDefault() async { + await assertNoErrorsInCode(r''' +void f(Object? x) { + switch (x) { + case int a when a > 0: + default: + a; + } +} +'''); + + final node = findNode.switchStatement('switch'); + assertResolvedNodeText(node, r''' +SwitchStatement + switchKeyword: switch + leftParenthesis: ( + expression: SimpleIdentifier + token: x + staticElement: self::@function::f::@parameter::x + staticType: Object? + rightParenthesis: ) + leftBracket: { + members + SwitchPatternCase + keyword: case + guardedPattern: GuardedPattern + pattern: VariablePattern + type: NamedType + name: SimpleIdentifier + token: int + staticElement: dart:core::@class::int + staticType: null + type: int + name: a + declaredElement: a@48 + type: int + whenClause: WhenClause + whenKeyword: when + expression: BinaryExpression + leftOperand: SimpleIdentifier + token: a + staticElement: a@48 + staticType: int + operator: > + rightOperand: IntegerLiteral + literal: 0 + parameter: dart:core::@class::num::@method::>::@parameter::other + staticType: int + staticElement: dart:core::@class::num::@method::> + staticInvokeType: bool Function(num) + staticType: bool + colon: : + SwitchDefault + keyword: default + colon: : + statements + ExpressionStatement + expression: SimpleIdentifier + token: a + staticElement: notConsistent a[a@48] + staticType: int + semicolon: ; + rightBracket: } +'''); + } + + test_variables_joinedCase_hasLabel() async { + await assertErrorsInCode(r''' +void f(Object? x) { + switch (x) { + myLabel: + case int a when a > 0: + a; + } +} +''', [ + error(HintCode.UNUSED_LABEL, 39, 8), + ]); + + final node = findNode.switchStatement('switch'); + assertResolvedNodeText(node, r''' +SwitchStatement + switchKeyword: switch + leftParenthesis: ( + expression: SimpleIdentifier + token: x + staticElement: self::@function::f::@parameter::x + staticType: Object? + rightParenthesis: ) + leftBracket: { + members + SwitchPatternCase + labels + Label + label: SimpleIdentifier + token: myLabel + staticElement: myLabel@39 + staticType: null + colon: : + keyword: case + guardedPattern: GuardedPattern + pattern: VariablePattern + type: NamedType + name: SimpleIdentifier + token: int + staticElement: dart:core::@class::int + staticType: null + type: int + name: a + declaredElement: a@61 + type: int + whenClause: WhenClause + whenKeyword: when + expression: BinaryExpression + leftOperand: SimpleIdentifier + token: a + staticElement: a@61 + staticType: int + operator: > + rightOperand: IntegerLiteral + literal: 0 + parameter: dart:core::@class::num::@method::>::@parameter::other + staticType: int + staticElement: dart:core::@class::num::@method::> + staticInvokeType: bool Function(num) + staticType: bool + colon: : + statements + ExpressionStatement + expression: SimpleIdentifier + token: a + staticElement: notConsistent a[a@61] + staticType: int + semicolon: ; + rightBracket: } +'''); + } + + test_variables_scope() async { + await assertErrorsInCode(r''' +const a = 0; +void f(Object? x) { + switch (x) { + case [int a, == a] when a > 0: + a; + } +} +''', [ + error(CompileTimeErrorCode.REFERENCED_BEFORE_DECLARATION, 68, 1, + contextMessages: [message('/home/test/lib/test.dart', 62, 1)]), + ]); + + final node = findNode.switchStatement('switch'); + assertResolvedNodeText(node, r''' +SwitchStatement + switchKeyword: switch + leftParenthesis: ( + expression: SimpleIdentifier + token: x + staticElement: self::@function::f::@parameter::x + staticType: Object? + rightParenthesis: ) + leftBracket: { + members + SwitchPatternCase + keyword: case + guardedPattern: GuardedPattern + pattern: ListPattern + leftBracket: [ + elements + VariablePattern + type: NamedType + name: SimpleIdentifier + token: int + staticElement: dart:core::@class::int + staticType: null + type: int + name: a + declaredElement: a@62 + type: int + RelationalPattern + operator: == + operand: SimpleIdentifier + token: a + staticElement: a@62 + staticType: int + element: dart:core::@class::Object::@method::== + rightBracket: ] + requiredType: List + whenClause: WhenClause + whenKeyword: when + expression: BinaryExpression + leftOperand: SimpleIdentifier + token: a + staticElement: a@62 + staticType: int + operator: > + rightOperand: IntegerLiteral + literal: 0 + parameter: dart:core::@class::num::@method::>::@parameter::other + staticType: int + staticElement: dart:core::@class::num::@method::> + staticInvokeType: bool Function(num) + staticType: bool + colon: : + statements + ExpressionStatement + expression: SimpleIdentifier + token: a + staticElement: a@62 + staticType: int + semicolon: ; + rightBracket: } +'''); + } + + test_variables_singleCase() async { + await assertNoErrorsInCode(r''' +void f(Object? x) { + switch (x) { + case int a when a > 0: + a; + } +} +'''); + + final node = findNode.switchStatement('switch'); + assertResolvedNodeText(node, r''' +SwitchStatement + switchKeyword: switch + leftParenthesis: ( + expression: SimpleIdentifier + token: x + staticElement: self::@function::f::@parameter::x + staticType: Object? + rightParenthesis: ) + leftBracket: { + members + SwitchPatternCase + keyword: case + guardedPattern: GuardedPattern + pattern: VariablePattern + type: NamedType + name: SimpleIdentifier + token: int + staticElement: dart:core::@class::int + staticType: null + type: int + name: a + declaredElement: a@48 + type: int + whenClause: WhenClause + whenKeyword: when + expression: BinaryExpression + leftOperand: SimpleIdentifier + token: a + staticElement: a@48 + staticType: int + operator: > + rightOperand: IntegerLiteral + literal: 0 + parameter: dart:core::@class::num::@method::>::@parameter::other + staticType: int + staticElement: dart:core::@class::num::@method::> + staticInvokeType: bool Function(num) + staticType: bool + colon: : + statements + ExpressionStatement + expression: SimpleIdentifier + token: a + staticElement: a@48 + staticType: int + semicolon: ; + rightBracket: } +'''); + } + test_whenClause() async { await assertNoErrorsInCode(r''' void f(Object? x) { @@ -271,3 +1064,107 @@ SwitchStatement '''); } } + +@reflectiveTest +class SwitchStatementResolutionTest_Language218 extends PubPackageResolutionTest + with WithLanguage218Mixin { + test_default() async { + await assertNoErrorsInCode(r''' +void f(Object? x) { + switch (x) { + case 0: + break; + default: + break; + } +} +'''); + + final node = findNode.switchStatement('switch'); + assertResolvedNodeText(node, r''' +SwitchStatement + switchKeyword: switch + leftParenthesis: ( + expression: SimpleIdentifier + token: x + staticElement: self::@function::f::@parameter::x + staticType: Object? + rightParenthesis: ) + leftBracket: { + members + SwitchCase + keyword: case + expression: IntegerLiteral + literal: 0 + staticType: int + colon: : + statements + BreakStatement + breakKeyword: break + semicolon: ; + SwitchDefault + keyword: default + colon: : + statements + BreakStatement + breakKeyword: break + semicolon: ; + rightBracket: } +'''); + } + + test_mergeCases() async { + await assertNoErrorsInCode(r''' +void f(Object? x) { + switch (x) { + case 0: + case 1: + break; + case 2: + break; + } +} +'''); + + final node = findNode.switchStatement('switch'); + assertResolvedNodeText(node, r''' +SwitchStatement + switchKeyword: switch + leftParenthesis: ( + expression: SimpleIdentifier + token: x + staticElement: self::@function::f::@parameter::x + staticType: Object? + rightParenthesis: ) + leftBracket: { + members + SwitchCase + keyword: case + expression: IntegerLiteral + literal: 0 + staticType: int + colon: : + SwitchCase + keyword: case + expression: IntegerLiteral + literal: 1 + staticType: int + colon: : + statements + BreakStatement + breakKeyword: break + semicolon: ; + SwitchCase + keyword: case + expression: IntegerLiteral + literal: 2 + staticType: int + colon: : + statements + BreakStatement + breakKeyword: break + semicolon: ; + rightBracket: } +'''); + } +} diff --git a/pkg/analyzer/test/src/diagnostics/referenced_before_declaration_test.dart b/pkg/analyzer/test/src/diagnostics/referenced_before_declaration_test.dart index f9c5d357ac1..2c61e807e3e 100644 --- a/pkg/analyzer/test/src/diagnostics/referenced_before_declaration_test.dart +++ b/pkg/analyzer/test/src/diagnostics/referenced_before_declaration_test.dart @@ -116,7 +116,6 @@ print(x) {} ]); } - @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/50502') test_hideInSwitchCase_function() async { await assertErrorsInCode(r''' var v = 0; @@ -156,7 +155,6 @@ void f(int a) { assertElement(findNode.simple('v;'), findElement.localFunction('v')); } - @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/50502') test_hideInSwitchCase_local() async { await assertErrorsInCode(r''' var v = 0;