blob: 5c14d7c3ccba8a08647a47462f6f9be76ec2f41e [file] [log] [blame]
// Copyright (c) 2022, 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 'context_collection_resolution.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(SwitchExpressionResolutionTest);
});
}
@reflectiveTest
class SwitchExpressionResolutionTest extends PubPackageResolutionTest {
test_case_expression_void() async {
await assertNoErrorsInCode(r'''
void f(Object? x) {
(switch(x) {
0 => 0,
_ => g(),
});
}
void g() {}
''');
var node = findNode.singleSwitchExpression;
assertResolvedNodeText(node, r'''
SwitchExpression
switchKeyword: switch
leftParenthesis: (
expression: SimpleIdentifier
token: x
staticElement: self::@function::f::@parameter::x
staticType: Object?
rightParenthesis: )
leftBracket: {
cases
SwitchExpressionCase
guardedPattern: GuardedPattern
pattern: ConstantPattern
expression: IntegerLiteral
literal: 0
staticType: int
matchedValueType: Object?
arrow: =>
expression: IntegerLiteral
literal: 0
staticType: int
SwitchExpressionCase
guardedPattern: GuardedPattern
pattern: WildcardPattern
name: _
matchedValueType: Object?
arrow: =>
expression: MethodInvocation
methodName: SimpleIdentifier
token: g
staticElement: self::@function::g
staticType: void Function()
argumentList: ArgumentList
leftParenthesis: (
rightParenthesis: )
staticInvokeType: void Function()
staticType: void
rightBracket: }
staticType: void
''');
}
test_cases_empty() async {
await assertErrorsInCode(r'''
final a = switch (0) {};
''', [
error(CompileTimeErrorCode.NON_EXHAUSTIVE_SWITCH_EXPRESSION, 10, 6),
]);
var node = findNode.singleSwitchExpression;
assertResolvedNodeText(node, r'''
SwitchExpression
switchKeyword: switch
leftParenthesis: (
expression: IntegerLiteral
literal: 0
staticType: int
rightParenthesis: )
leftBracket: {
rightBracket: }
staticType: Never
''');
}
test_contextType_case_expression() async {
await assertNoErrorsInCode(r'''
class A {
T foo<T>() => throw 0;
int bar(Object? x) {
return switch (x) {
_ => foo(),
};
}
}
''');
var node = findNode.switchExpression('switch');
assertResolvedNodeText(node, r'''
SwitchExpression
switchKeyword: switch
leftParenthesis: (
expression: SimpleIdentifier
token: x
staticElement: self::@class::A::@method::bar::@parameter::x
staticType: Object?
rightParenthesis: )
leftBracket: {
cases
SwitchExpressionCase
guardedPattern: GuardedPattern
pattern: WildcardPattern
name: _
matchedValueType: Object?
arrow: =>
expression: MethodInvocation
methodName: SimpleIdentifier
token: foo
staticElement: self::@class::A::@method::foo
staticType: T Function<T>()
argumentList: ArgumentList
leftParenthesis: (
rightParenthesis: )
staticInvokeType: int Function()
staticType: int
typeArgumentTypes
int
rightBracket: }
staticType: int
''');
}
test_expression_void() async {
await assertErrorsInCode('''
void f(void x) {
(switch(x) {
_ => 0,
});
}
''', [
error(CompileTimeErrorCode.USE_OF_VOID_RESULT, 27, 1),
]);
var node = findNode.singleSwitchExpression;
assertResolvedNodeText(node, r'''
SwitchExpression
switchKeyword: switch
leftParenthesis: (
expression: SimpleIdentifier
token: x
staticElement: self::@function::f::@parameter::x
staticType: void
rightParenthesis: )
leftBracket: {
cases
SwitchExpressionCase
guardedPattern: GuardedPattern
pattern: WildcardPattern
name: _
matchedValueType: void
arrow: =>
expression: IntegerLiteral
literal: 0
staticType: int
rightBracket: }
staticType: int
''');
}
test_location_topLevel() async {
await assertNoErrorsInCode(r'''
num a = 0;
final b = switch (a) {
int(:var isEven) when isEven => 1,
_ => 0,
};
''');
var node = findNode.singleSwitchExpression;
assertResolvedNodeText(node, r'''
SwitchExpression
switchKeyword: switch
leftParenthesis: (
expression: SimpleIdentifier
token: a
staticElement: self::@getter::a
staticType: num
rightParenthesis: )
leftBracket: {
cases
SwitchExpressionCase
guardedPattern: GuardedPattern
pattern: ObjectPattern
type: NamedType
name: int
element: dart:core::@class::int
type: int
leftParenthesis: (
fields
PatternField
name: PatternFieldName
colon: :
pattern: DeclaredVariablePattern
keyword: var
name: isEven
declaredElement: hasImplicitType isEven@46
type: bool
matchedValueType: bool
element: dart:core::@class::int::@getter::isEven
rightParenthesis: )
matchedValueType: num
whenClause: WhenClause
whenKeyword: when
expression: SimpleIdentifier
token: isEven
staticElement: isEven@46
staticType: bool
arrow: =>
expression: IntegerLiteral
literal: 1
staticType: int
SwitchExpressionCase
guardedPattern: GuardedPattern
pattern: WildcardPattern
name: _
matchedValueType: num
arrow: =>
expression: IntegerLiteral
literal: 0
staticType: int
rightBracket: }
staticType: int
''');
}
test_rewrite_case_expression() async {
await assertNoErrorsInCode(r'''
void f(Object? x, int Function() a) {
(switch (x) {
_ => a(),
});
}
''');
var node = findNode.switchExpressionCase('_');
assertResolvedNodeText(node, r'''
SwitchExpressionCase
guardedPattern: GuardedPattern
pattern: WildcardPattern
name: _
matchedValueType: Object?
arrow: =>
expression: FunctionExpressionInvocation
function: SimpleIdentifier
token: a
staticElement: self::@function::f::@parameter::a
staticType: int Function()
argumentList: ArgumentList
leftParenthesis: (
rightParenthesis: )
staticElement: <null>
staticInvokeType: int Function()
staticType: int
''');
}
test_rewrite_case_pattern() async {
await assertNoErrorsInCode(r'''
void f(Object? x) {
(switch (x) {
const A() => 0,
_ => 1,
});
}
class A {
const A();
}
''');
var node = findNode.switchExpressionCase('=> 0');
assertResolvedNodeText(node, r'''
SwitchExpressionCase
guardedPattern: GuardedPattern
pattern: ConstantPattern
const: const
expression: InstanceCreationExpression
constructorName: ConstructorName
type: NamedType
name: A
element: self::@class::A
type: A
staticElement: self::@class::A::@constructor::new
argumentList: ArgumentList
leftParenthesis: (
rightParenthesis: )
staticType: A
matchedValueType: Object?
arrow: =>
expression: IntegerLiteral
literal: 0
staticType: int
''');
}
test_rewrite_case_whenClause() async {
await assertNoErrorsInCode(r'''
void f(Object? x, bool Function() a) {
(switch (x) {
0 when a() => true,
_ => false,
});
}
''');
var node = findNode.switchExpressionCase('=> true');
assertResolvedNodeText(node, r'''
SwitchExpressionCase
guardedPattern: GuardedPattern
pattern: ConstantPattern
expression: IntegerLiteral
literal: 0
staticType: int
matchedValueType: Object?
whenClause: WhenClause
whenKeyword: when
expression: FunctionExpressionInvocation
function: SimpleIdentifier
token: a
staticElement: self::@function::f::@parameter::a
staticType: bool Function()
argumentList: ArgumentList
leftParenthesis: (
rightParenthesis: )
staticElement: <null>
staticInvokeType: bool Function()
staticType: bool
arrow: =>
expression: BooleanLiteral
literal: true
staticType: bool
''');
}
test_rewrite_expression() async {
await assertNoErrorsInCode(r'''
void f(int Function() a) {
(switch (a()) {
_ => 0,
});
}
''');
var node = findNode.switchExpression('switch');
assertResolvedNodeText(node, r'''
SwitchExpression
switchKeyword: switch
leftParenthesis: (
expression: FunctionExpressionInvocation
function: SimpleIdentifier
token: a
staticElement: self::@function::f::@parameter::a
staticType: int Function()
argumentList: ArgumentList
leftParenthesis: (
rightParenthesis: )
staticElement: <null>
staticInvokeType: int Function()
staticType: int
rightParenthesis: )
leftBracket: {
cases
SwitchExpressionCase
guardedPattern: GuardedPattern
pattern: WildcardPattern
name: _
matchedValueType: int
arrow: =>
expression: IntegerLiteral
literal: 0
staticType: int
rightBracket: }
staticType: int
''');
}
test_staticType_cases_leastUpperBound() async {
await assertNoErrorsInCode(r'''
void f(Object? x) {
(switch (x) {
true => 0,
_ => null,
});
}
''');
var node = findNode.switchExpression('switch');
assertResolvedNodeText(node, r'''
SwitchExpression
switchKeyword: switch
leftParenthesis: (
expression: SimpleIdentifier
token: x
staticElement: self::@function::f::@parameter::x
staticType: Object?
rightParenthesis: )
leftBracket: {
cases
SwitchExpressionCase
guardedPattern: GuardedPattern
pattern: ConstantPattern
expression: BooleanLiteral
literal: true
staticType: bool
matchedValueType: Object?
arrow: =>
expression: IntegerLiteral
literal: 0
staticType: int
SwitchExpressionCase
guardedPattern: GuardedPattern
pattern: WildcardPattern
name: _
matchedValueType: Object?
arrow: =>
expression: NullLiteral
literal: null
staticType: Null
rightBracket: }
staticType: int?
''');
}
test_staticType_cases_same() async {
await assertNoErrorsInCode(r'''
void f(Object? x) {
(switch (x) {
true => 0,
_ => 1,
});
}
''');
var node = findNode.switchExpression('switch');
assertResolvedNodeText(node, r'''
SwitchExpression
switchKeyword: switch
leftParenthesis: (
expression: SimpleIdentifier
token: x
staticElement: self::@function::f::@parameter::x
staticType: Object?
rightParenthesis: )
leftBracket: {
cases
SwitchExpressionCase
guardedPattern: GuardedPattern
pattern: ConstantPattern
expression: BooleanLiteral
literal: true
staticType: bool
matchedValueType: Object?
arrow: =>
expression: IntegerLiteral
literal: 0
staticType: int
SwitchExpressionCase
guardedPattern: GuardedPattern
pattern: WildcardPattern
name: _
matchedValueType: Object?
arrow: =>
expression: IntegerLiteral
literal: 1
staticType: int
rightBracket: }
staticType: int
''');
}
test_variables_logicalOr() async {
await assertErrorsInCode(r'''
void f(Object? x) {
(switch (x) {
<int>[var a || var a] => a,
_ => 0,
});
}
''', [
error(WarningCode.DEAD_CODE, 52, 8),
]);
var node = findNode.switchExpression('switch');
assertResolvedNodeText(node, r'''
SwitchExpression
switchKeyword: switch
leftParenthesis: (
expression: SimpleIdentifier
token: x
staticElement: self::@function::f::@parameter::x
staticType: Object?
rightParenthesis: )
leftBracket: {
cases
SwitchExpressionCase
guardedPattern: GuardedPattern
pattern: ListPattern
typeArguments: TypeArgumentList
leftBracket: <
arguments
NamedType
name: int
element: dart:core::@class::int
type: int
rightBracket: >
leftBracket: [
elements
LogicalOrPattern
leftOperand: DeclaredVariablePattern
keyword: var
name: a
declaredElement: hasImplicitType a@50
type: int
matchedValueType: int
operator: ||
rightOperand: DeclaredVariablePattern
keyword: var
name: a
declaredElement: hasImplicitType a@59
type: int
matchedValueType: int
matchedValueType: int
rightBracket: ]
matchedValueType: Object?
requiredType: List<int>
arrow: =>
expression: SimpleIdentifier
token: a
staticElement: a[a@50, a@59]
staticType: int
SwitchExpressionCase
guardedPattern: GuardedPattern
pattern: WildcardPattern
name: _
matchedValueType: Object?
arrow: =>
expression: IntegerLiteral
literal: 0
staticType: int
rightBracket: }
staticType: int
''');
}
test_variables_scope() async {
await assertErrorsInCode(r'''
const a = 0;
void f(Object? x) {
(switch (x) {
[int a, == a] when a > 0 => a,
_ => 0,
});
}
''', [
error(CompileTimeErrorCode.NON_CONSTANT_RELATIONAL_PATTERN_EXPRESSION, 64,
1),
error(CompileTimeErrorCode.REFERENCED_BEFORE_DECLARATION, 64, 1,
contextMessages: [message(testFile, 58, 1)]),
]);
var node = findNode.switchExpression('switch');
assertResolvedNodeText(node, r'''
SwitchExpression
switchKeyword: switch
leftParenthesis: (
expression: SimpleIdentifier
token: x
staticElement: self::@function::f::@parameter::x
staticType: Object?
rightParenthesis: )
leftBracket: {
cases
SwitchExpressionCase
guardedPattern: GuardedPattern
pattern: ListPattern
leftBracket: [
elements
DeclaredVariablePattern
type: NamedType
name: int
element: dart:core::@class::int
type: int
name: a
declaredElement: a@58
type: int
matchedValueType: Object?
RelationalPattern
operator: ==
operand: SimpleIdentifier
token: a
staticElement: a@58
staticType: int
element: dart:core::@class::Object::@method::==
matchedValueType: Object?
rightBracket: ]
matchedValueType: Object?
requiredType: List<Object?>
whenClause: WhenClause
whenKeyword: when
expression: BinaryExpression
leftOperand: SimpleIdentifier
token: a
staticElement: a@58
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
arrow: =>
expression: SimpleIdentifier
token: a
staticElement: a@58
staticType: int
SwitchExpressionCase
guardedPattern: GuardedPattern
pattern: WildcardPattern
name: _
matchedValueType: Object?
arrow: =>
expression: IntegerLiteral
literal: 0
staticType: int
rightBracket: }
staticType: int
''');
}
test_variables_singleCase() async {
await assertErrorsInCode(r'''
void f(Object? x) {
(switch (x) {
int a when a > 0 => a,
_ => a,
});
}
''', [
error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 72, 1),
]);
var node = findNode.switchExpression('switch');
assertResolvedNodeText(node, r'''
SwitchExpression
switchKeyword: switch
leftParenthesis: (
expression: SimpleIdentifier
token: x
staticElement: self::@function::f::@parameter::x
staticType: Object?
rightParenthesis: )
leftBracket: {
cases
SwitchExpressionCase
guardedPattern: GuardedPattern
pattern: DeclaredVariablePattern
type: NamedType
name: int
element: dart:core::@class::int
type: int
name: a
declaredElement: a@44
type: int
matchedValueType: Object?
whenClause: WhenClause
whenKeyword: when
expression: BinaryExpression
leftOperand: SimpleIdentifier
token: a
staticElement: a@44
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
arrow: =>
expression: SimpleIdentifier
token: a
staticElement: a@44
staticType: int
SwitchExpressionCase
guardedPattern: GuardedPattern
pattern: WildcardPattern
name: _
matchedValueType: Object?
arrow: =>
expression: SimpleIdentifier
token: a
staticElement: <null>
staticType: InvalidType
rightBracket: }
staticType: InvalidType
''');
}
}