Resolve VariablePattern.

Change-Id: Ibfd32610e86aa3396495b3ba7210612a17756fc4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/261782
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov 2022-09-28 22:09:07 +00:00 committed by Commit Queue
parent b48846c1ea
commit e1b5cbd266
9 changed files with 249 additions and 48 deletions

View file

@ -5420,7 +5420,7 @@ abstract class VariablePattern implements DartPattern {
/// Return the element associated with this declaration, or `null` if either
/// the variable name is `_` (in which case no variable is defined) or the AST
/// structure has not been resolved.
VariableElement? get declaredElement;
VariablePatternElement? get declaredElement;
/// The 'var' or 'final' keyword used when there is no [type], or `null` if a
/// type is given.

View file

@ -2388,6 +2388,15 @@ abstract class VariableElement implements Element, ConstantEvaluationTarget {
DartObject? computeConstantValue();
}
/// A pattern variable.
///
/// Clients may not extend, implement or mix-in this class.
@experimental
abstract class VariablePatternElement implements LocalVariableElement {
/// Aliases of this variable in logical-or patterns.
List<VariablePatternElement> get aliases;
}
/// This class exists to provide non-nullable overrides for existing elements,
/// as opposite to artificial "multiply defined" element.
abstract class _ExistingElement implements Element {

View file

@ -13422,7 +13422,7 @@ class VariableDeclarationStatementImpl extends StatementImpl
@experimental
class VariablePatternImpl extends DartPatternImpl implements VariablePattern {
@override
VariableElement? declaredElement;
VariablePatternElementImpl? declaredElement;
@override
final Token? keyword;
@ -13463,7 +13463,9 @@ class VariablePatternImpl extends DartPatternImpl implements VariablePattern {
DartType matchedType,
Map<PromotableElement, VariableTypeInfo<AstNode, DartType>> typeInfos,
MatchContext<AstNode, Expression> context) {
// TODO(scheglov) https://github.com/dart-lang/sdk/issues/50066
resolverVisitor.analyzeVariablePattern(matchedType, typeInfos, context,
this, declaredElement, type?.typeOrThrow,
isFinal: keyword?.keyword == Keyword.FINAL);
}
@override

View file

@ -6479,6 +6479,14 @@ abstract class VariableElementImpl extends ElementImpl
DartObject? computeConstantValue() => null;
}
class VariablePatternElementImpl extends LocalVariableElementImpl
implements VariablePatternElement {
@override
final List<VariablePatternElementImpl> aliases = [];
VariablePatternElementImpl(super.name, super.offset);
}
abstract class _ExistingElementImpl extends ElementImpl with _HasLibraryMixin {
_ExistingElementImpl(super.name, super.offset, {super.reference});
}

View file

@ -4,6 +4,7 @@
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
@ -1177,6 +1178,22 @@ class ResolutionVisitor extends RecursiveAstVisitor<void> {
}
}
@override
void visitVariablePattern(covariant VariablePatternImpl node) {
node.type?.accept(this);
if (node.name.lexeme != '_') {
final element = VariablePatternElementImpl(
node.name.lexeme,
node.name.offset,
);
node.declaredElement = element;
_elementHolder.enclose(element);
element.isFinal = node.keyword?.keyword == Keyword.FINAL;
element.hasImplicitType = node.type == null;
}
}
/// Builds the label elements associated with [labels] and stores them in the
/// element holder.
void _buildLabelElements(

View file

@ -1140,7 +1140,11 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
@override
void setVariableType(PromotableElement variable, DartType type) {
throw UnimplementedError('TODO(paulberry)');
if (variable is LocalVariableElementImpl) {
variable.type = type;
} else {
throw UnimplementedError('TODO(paulberry)');
}
}
void setWriteElement(Expression node, Element? element) {
@ -1241,7 +1245,8 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
@override
DartType variableTypeFromInitializerType(DartType type) {
throw UnimplementedError('TODO(paulberry)');
// TODO(scheglov) https://github.com/dart-lang/sdk/issues/50078
return type;
}
@override

View file

@ -82,16 +82,18 @@ ExtractorPattern
test_inside_ifStatement_case() async {
await assertNoErrorsInCode(r'''
void f(x) {
void f(int? x) {
if (x case var y!) {}
}
''');
final node = findNode.caseClause('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
PostfixPattern
operand: VariablePattern
keyword: var
name: y
declaredElement: hasImplicitType y@34
type: int
operator: !
''');
}
@ -252,13 +254,14 @@ void f(x) {
}
''');
final node = findNode.switchPatternCase('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
ParenthesizedPattern
leftParenthesis: (
pattern: PostfixPattern
operand: ConstantPattern
expression: IntegerLiteral
literal: 0
staticType: int
operator: !
rightParenthesis: )
''');
@ -444,16 +447,18 @@ ExtractorPattern
test_inside_ifStatement_case() async {
await assertNoErrorsInCode(r'''
void f(x) {
void f(int? x) {
if (x case var y?) {}
}
''');
final node = findNode.caseClause('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
PostfixPattern
operand: VariablePattern
keyword: var
name: y
declaredElement: hasImplicitType y@34
type: int
operator: ?
''');
}
@ -614,13 +619,14 @@ void f(x) {
}
''');
final node = findNode.switchPatternCase('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
ParenthesizedPattern
leftParenthesis: (
pattern: PostfixPattern
operand: ConstantPattern
expression: IntegerLiteral
literal: 0
staticType: int
operator: ?
rightParenthesis: )
''');

View file

@ -16,7 +16,7 @@ main() {
class VariablePatternResolutionTest extends PatternsResolutionTest {
test_final_inside_castPattern() async {
await assertNoErrorsInCode(r'''
void f(x) {
void f(int x) {
switch (x) {
case final y as Object:
break;
@ -24,35 +24,42 @@ void f(x) {
}
''');
final node = findNode.switchPatternCase('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
CastPattern
pattern: VariablePattern
keyword: final
name: y
declaredElement: hasImplicitType isFinal y@46
type: Object
asToken: as
type: NamedType
name: SimpleIdentifier
token: Object
staticElement: dart:core::@class::Object
staticType: null
type: Object
''');
}
test_final_inside_ifStatement_case() async {
await assertNoErrorsInCode(r'''
void f(x) {
void f(int x) {
if (x case final y) {}
}
''');
final node = findNode.caseClause('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
VariablePattern
keyword: final
name: y
declaredElement: hasImplicitType isFinal y@35
type: int
''');
}
test_final_inside_nullAssert() async {
await assertNoErrorsInCode(r'''
void f(x) {
void f(int? x) {
switch (x) {
case final y!:
break;
@ -60,18 +67,20 @@ void f(x) {
}
''');
final node = findNode.switchPatternCase('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
PostfixPattern
operand: VariablePattern
keyword: final
name: y
declaredElement: hasImplicitType isFinal y@47
type: int
operator: !
''');
}
test_final_inside_nullCheck() async {
await assertNoErrorsInCode(r'''
void f(x) {
void f(int? x) {
switch (x) {
case final y?:
break;
@ -79,18 +88,20 @@ void f(x) {
}
''');
final node = findNode.switchPatternCase('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
PostfixPattern
operand: VariablePattern
keyword: final
name: y
declaredElement: hasImplicitType isFinal y@47
type: int
operator: ?
''');
}
test_final_inside_switchStatement_case() async {
await assertNoErrorsInCode(r'''
void f(x) {
void f(int x) {
switch (x) {
case final y:
break;
@ -98,10 +109,12 @@ void f(x) {
}
''');
final node = findNode.switchPatternCase('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
VariablePattern
keyword: final
name: y
declaredElement: hasImplicitType isFinal y@46
type: int
''');
}
@ -115,18 +128,26 @@ void f(x) {
}
''');
final node = findNode.switchPatternCase('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
CastPattern
pattern: VariablePattern
keyword: final
type: NamedType
name: SimpleIdentifier
token: int
staticElement: dart:core::@class::int
staticType: null
type: int
name: y
declaredElement: isFinal y@46
type: int
asToken: as
type: NamedType
name: SimpleIdentifier
token: Object
staticElement: dart:core::@class::Object
staticType: null
type: Object
''');
}
@ -137,13 +158,18 @@ void f(x) {
}
''');
final node = findNode.caseClause('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
VariablePattern
keyword: final
type: NamedType
name: SimpleIdentifier
token: int
staticElement: dart:core::@class::int
staticType: null
type: int
name: y
declaredElement: isFinal y@35
type: int
''');
}
@ -157,14 +183,19 @@ void f(x) {
}
''');
final node = findNode.switchPatternCase('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
PostfixPattern
operand: VariablePattern
keyword: final
type: NamedType
name: SimpleIdentifier
token: int
staticElement: dart:core::@class::int
staticType: null
type: int
name: y
declaredElement: isFinal y@46
type: int
operator: !
''');
}
@ -179,14 +210,19 @@ void f(x) {
}
''');
final node = findNode.switchPatternCase('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
PostfixPattern
operand: VariablePattern
keyword: final
type: NamedType
name: SimpleIdentifier
token: int
staticElement: dart:core::@class::int
staticType: null
type: int
name: y
declaredElement: isFinal y@46
type: int
operator: ?
''');
}
@ -201,13 +237,18 @@ void f(x) {
}
''');
final node = findNode.switchPatternCase('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
VariablePattern
keyword: final
type: NamedType
name: SimpleIdentifier
token: int
staticElement: dart:core::@class::int
staticType: null
type: int
name: y
declaredElement: isFinal y@46
type: int
''');
}
@ -221,17 +262,25 @@ void f(x) {
}
''');
final node = findNode.switchPatternCase('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
CastPattern
pattern: VariablePattern
type: NamedType
name: SimpleIdentifier
token: int
staticElement: dart:core::@class::int
staticType: null
type: int
name: y
declaredElement: y@40
type: int
asToken: as
type: NamedType
name: SimpleIdentifier
token: Object
staticElement: dart:core::@class::Object
staticType: null
type: Object
''');
}
@ -242,12 +291,17 @@ void f(x) {
}
''');
final node = findNode.caseClause('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
VariablePattern
type: NamedType
name: SimpleIdentifier
token: int
staticElement: dart:core::@class::int
staticType: null
type: int
name: y
declaredElement: y@29
type: int
''');
}
@ -261,13 +315,18 @@ void f(x) {
}
''');
final node = findNode.switchPatternCase('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
PostfixPattern
operand: VariablePattern
type: NamedType
name: SimpleIdentifier
token: int
staticElement: dart:core::@class::int
staticType: null
type: int
name: y
declaredElement: y@40
type: int
operator: !
''');
}
@ -282,13 +341,18 @@ void f(x) {
}
''');
final node = findNode.switchPatternCase('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
PostfixPattern
operand: VariablePattern
type: NamedType
name: SimpleIdentifier
token: int
staticElement: dart:core::@class::int
staticType: null
type: int
name: y
declaredElement: y@40
type: int
operator: ?
''');
}
@ -303,12 +367,17 @@ void f(x) {
}
''');
final node = findNode.switchPatternCase('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
VariablePattern
type: NamedType
name: SimpleIdentifier
token: int
staticElement: dart:core::@class::int
staticType: null
type: int
name: y
declaredElement: y@40
type: int
''');
}
@ -322,17 +391,25 @@ void f(x) {
}
''');
final node = findNode.switchPatternCase('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
CastPattern
pattern: VariablePattern
type: NamedType
name: SimpleIdentifier
token: int
staticElement: dart:core::@class::int
staticType: null
type: int
name: as
declaredElement: as@40
type: int
asToken: as
type: NamedType
name: SimpleIdentifier
token: Object
staticElement: dart:core::@class::Object
staticType: null
type: Object
''');
}
@ -408,12 +485,17 @@ void f(x) {
}
''');
final node = findNode.caseClause('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
VariablePattern
type: NamedType
name: SimpleIdentifier
token: int
staticElement: dart:core::@class::int
staticType: null
type: int
name: as
declaredElement: as@29
type: int
''');
}
@ -573,13 +655,18 @@ void f(x) {
}
''');
final node = findNode.switchPatternCase('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
PostfixPattern
operand: VariablePattern
type: NamedType
name: SimpleIdentifier
token: int
staticElement: dart:core::@class::int
staticType: null
type: int
name: as
declaredElement: as@40
type: int
operator: !
''');
}
@ -594,13 +681,18 @@ void f(x) {
}
''');
final node = findNode.switchPatternCase('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
PostfixPattern
operand: VariablePattern
type: NamedType
name: SimpleIdentifier
token: int
staticElement: dart:core::@class::int
staticType: null
type: int
name: as
declaredElement: as@40
type: int
operator: ?
''');
}
@ -615,14 +707,19 @@ void f(x) {
}
''');
final node = findNode.switchPatternCase('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
ParenthesizedPattern
leftParenthesis: (
pattern: VariablePattern
type: NamedType
name: SimpleIdentifier
token: int
staticElement: dart:core::@class::int
staticType: null
type: int
name: as
declaredElement: as@41
type: int
rightParenthesis: )
''');
}
@ -726,18 +823,45 @@ void f(x) {
}
''');
final node = findNode.switchPatternCase('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
VariablePattern
type: NamedType
name: SimpleIdentifier
token: int
staticElement: dart:core::@class::int
staticType: null
type: int
name: as
declaredElement: as@40
type: int
''');
}
test_typed_wildcard_inside_switchStatement_case() async {
await assertNoErrorsInCode(r'''
void f(x) {
switch (x) {
case int _:
break;
}
}
''');
final node = findNode.switchPatternCase('case').pattern;
assertResolvedNodeText(node, r'''
VariablePattern
type: NamedType
name: SimpleIdentifier
token: int
staticElement: dart:core::@class::int
staticType: null
type: int
name: _
''');
}
test_var_inside_castPattern() async {
await assertNoErrorsInCode(r'''
void f(x) {
void f(int x) {
switch (x) {
case var y as Object:
break;
@ -745,35 +869,42 @@ void f(x) {
}
''');
final node = findNode.switchPatternCase('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
CastPattern
pattern: VariablePattern
keyword: var
name: y
declaredElement: hasImplicitType y@44
type: Object
asToken: as
type: NamedType
name: SimpleIdentifier
token: Object
staticElement: dart:core::@class::Object
staticType: null
type: Object
''');
}
test_var_inside_ifStatement_case() async {
await assertNoErrorsInCode(r'''
void f(x) {
void f(int x) {
if (x case var y) {}
}
''');
final node = findNode.caseClause('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
VariablePattern
keyword: var
name: y
declaredElement: hasImplicitType y@33
type: int
''');
}
test_var_inside_nullAssert() async {
await assertNoErrorsInCode(r'''
void f(x) {
void f(int? x) {
switch (x) {
case var y!:
break;
@ -781,18 +912,20 @@ void f(x) {
}
''');
final node = findNode.switchPatternCase('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
PostfixPattern
operand: VariablePattern
keyword: var
name: y
declaredElement: hasImplicitType y@45
type: int
operator: !
''');
}
test_var_inside_nullCheck() async {
await assertNoErrorsInCode(r'''
void f(x) {
void f(int? x) {
switch (x) {
case var y?:
break;
@ -800,18 +933,20 @@ void f(x) {
}
''');
final node = findNode.switchPatternCase('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
PostfixPattern
operand: VariablePattern
keyword: var
name: y
declaredElement: hasImplicitType y@45
type: int
operator: ?
''');
}
test_var_inside_switchStatement_case() async {
await assertNoErrorsInCode(r'''
void f(x) {
void f(int x) {
switch (x) {
case var y:
break;
@ -819,10 +954,12 @@ void f(x) {
}
''');
final node = findNode.switchPatternCase('case').pattern;
assertParsedNodeText(node, r'''
assertResolvedNodeText(node, r'''
VariablePattern
keyword: var
name: y
declaredElement: hasImplicitType y@44
type: int
''');
}
}

View file

@ -1405,7 +1405,18 @@ class ResolvedAstPrinter extends ThrowingAstVisitor<void> {
_withIndent(() {
_writeNamedChildEntities(node);
if (_withResolution) {
_writeElement('declaredElement', node.declaredElement);
final element = node.declaredElement;
if (element != null) {
element as VariablePatternElementImpl;
_sink.write(_indent);
_sink.write('declaredElement: ');
_writeIf(element.hasImplicitType, 'hasImplicitType ');
_writeIf(element.isFinal, 'isFinal ');
_sink.writeln('${element.name}@${element.nameOffset}');
_withIndent(() {
_writeType('type', element.type);
});
}
}
});
}
@ -1676,6 +1687,12 @@ class ResolvedAstPrinter extends ThrowingAstVisitor<void> {
}
}
void _writeIf(bool flag, String str) {
if (flag) {
_sink.write(str);
}
}
void _writeLibraryExportElement(LibraryExportElement element) {
_writeln('LibraryExportElement');
_withIndent(() {