From 03ba5dabc275017074e0b7ed0a031dbd3c615130 Mon Sep 17 00:00:00 2001 From: Johnni Winther Date: Tue, 2 Jun 2026 06:08:24 -0700 Subject: [PATCH] [cfe][InternalNodes] Add InternalPattern hierarchy This adds an internal class hierarch for patterns. This allows for the internal nodes to use InternalVariable rather than Variable and only contain the fields created during body building. This is a step towards separating Variable and InternalVariable fully. Change-Id: I0e5241bc7163e0771d3420496b1f5ea02b433c87 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/508561 Reviewed-by: Chloe Stefantsova Commit-Queue: Johnni Winther --- .../lib/src/kernel/body_builder.dart | 205 ++-- .../lib/src/kernel/external_ast_helper.dart | 300 ++++- .../lib/src/kernel/internal_ast.dart | 862 +++++++++++++- .../lib/src/kernel/internal_ast_helper.dart | 158 ++- pkg/front_end/lib/src/source/value_kinds.dart | 16 +- .../context_allocation_strategy.dart | 1 - .../src/type_inference/inference_visitor.dart | 1042 +++++++++-------- .../type_inference/shared_type_analyzer.dart | 3 +- 8 files changed, 1933 insertions(+), 654 deletions(-) diff --git a/pkg/front_end/lib/src/kernel/body_builder.dart b/pkg/front_end/lib/src/kernel/body_builder.dart index 905ea3bf3ce..e08354b4e96 100644 --- a/pkg/front_end/lib/src/kernel/body_builder.dart +++ b/pkg/front_end/lib/src/kernel/body_builder.dart @@ -676,8 +676,8 @@ class BodyBuilderImpl extends StackListenerImpl return toValue(node); } - Pattern toPattern(Object? node) { - if (node is Pattern) { + InternalPattern toPattern(Object? node) { + if (node is InternalPattern) { return node; } else if (node is Generator) { return intern.createConstantPattern(node.buildSimpleRead()); @@ -1876,9 +1876,9 @@ class BodyBuilderImpl extends StackListenerImpl _localScope.kind == LocalScopeKind.orPatternRight; if (scopeKind != LocalScopeKind.orPatternRight && enclosingScopeIsPatternScope) { - if (pattern is Pattern) { - for (Variable variable in pattern.declaredVariables) { - declareVariable(variable as InternalVariable, _localScope); + if (pattern is InternalPattern) { + for (InternalVariable variable in pattern.internalDeclaredVariables) { + declareVariable(variable, _localScope); } } } @@ -1939,8 +1939,8 @@ class BodyBuilderImpl extends StackListenerImpl operatorToken.charOffset, operatorToken.charCount, ); - Pattern right = toPattern(pop()); - Pattern left = toPattern(pop()); + InternalPattern right = toPattern(pop()); + InternalPattern left = toPattern(pop()); String operator = operatorToken.lexeme; switch (operator) { @@ -1948,52 +1948,51 @@ class BodyBuilderImpl extends StackListenerImpl push(intern.createAndPattern(operatorToken.charOffset, left, right)); break; case '||': - Map leftVariablesByName = { - for (Variable leftVariable in left.declaredVariables) - leftVariable.name!: leftVariable, + Map leftVariablesByName = { + for (InternalVariable leftVariable in left.internalDeclaredVariables) + leftVariable.cosmeticName!: leftVariable, }; - for (Variable rightVariable in right.declaredVariables) { - if (!leftVariablesByName.containsKey(rightVariable.name)) { + for (InternalVariable rightVariable + in right.internalDeclaredVariables) { + if (!leftVariablesByName.containsKey(rightVariable.cosmeticName)) { addProblem( diag.missingVariablePattern.withArguments( - variableName: rightVariable.name!, + variableName: rightVariable.cosmeticName!, ), left.fileOffset, noLength, ); } } - Map rightVariablesByName = { - for (Variable rightVariable in right.declaredVariables) - rightVariable.name!: rightVariable, + Map rightVariablesByName = { + for (InternalVariable rightVariable + in right.internalDeclaredVariables) + rightVariable.cosmeticName!: rightVariable, }; - for (Variable leftVariable in left.declaredVariables) { - if (!rightVariablesByName.containsKey(leftVariable.name)) { + for (InternalVariable leftVariable in left.internalDeclaredVariables) { + if (!rightVariablesByName.containsKey(leftVariable.cosmeticName)) { addProblem( diag.missingVariablePattern.withArguments( - variableName: leftVariable.name!, + variableName: leftVariable.cosmeticName!, ), right.fileOffset, noLength, ); } } - List jointVariables = [ - for (Variable leftVariable in left.declaredVariables) - intern - .createSyntheticVariable( - isClosureContextLoweringEnabled: - isClosureContextLoweringEnabled, - name: leftVariable.name!, - fileOffset: leftVariable.fileOffset, - // TODO(johnniwinther): Should this be final if [leftVariable] - // is? - ) - .asVariableDeclaration, + List jointVariables = [ + for (InternalVariable leftVariable in left.internalDeclaredVariables) + intern.createSyntheticVariable( + isClosureContextLoweringEnabled: isClosureContextLoweringEnabled, + name: leftVariable.cosmeticName!, + fileOffset: leftVariable.fileOffset, + // TODO(johnniwinther): Should this be final if [leftVariable] + // is? + ), ]; - for (Variable variable in jointVariables) { - declareVariable(variable as InternalVariable, _localScope); - assignedVariables.declare(variable); + for (InternalVariable variable in jointVariables) { + declareVariable(variable, _localScope); + assignedVariables.declare(variable.astVariable); } push( intern.createOrPattern( @@ -3202,10 +3201,10 @@ class BodyBuilderImpl extends StackListenerImpl ]), ); - Pattern pattern = toPattern(peek()); + InternalPattern pattern = toPattern(peek()); createAndEnterLocalScope(kind: LocalScopeKind.ifCaseHead); - for (Variable variable in pattern.declaredVariables) { - declareVariable(variable as InternalVariable, _localScope); + for (InternalVariable variable in pattern.internalDeclaredVariables) { + declareVariable(variable, _localScope); } } @@ -3236,8 +3235,9 @@ class BodyBuilderImpl extends StackListenerImpl // to enter the scope and declare all of the pattern variables. if (patternGuard != null) { createAndEnterLocalScope(kind: LocalScopeKind.ifCaseHead); - for (Variable variable in patternGuard.pattern.declaredVariables) { - declareVariable(variable as InternalVariable, _localScope); + InternalPattern pattern = patternGuard.pattern as InternalPattern; + for (InternalVariable variable in pattern.internalDeclaredVariables) { + declareVariable(variable, _localScope); } LocalScope thenScope = _localScope.createNestedScope( kind: LocalScopeKind.statementLocalScope, @@ -3824,10 +3824,10 @@ class BodyBuilderImpl extends StackListenerImpl Object expression = pop() as Object; Object pattern = pop() as Object; - if (pattern is Pattern) { + if (pattern is InternalPattern) { pop(); // Metadata. - for (Variable variable in pattern.declaredVariables) { - declareVariable(variable as InternalVariable, _localScope); + for (InternalVariable variable in pattern.internalDeclaredVariables) { + declareVariable(variable, _localScope); } LocalScope forScope = _localScope.createNestedScope( kind: LocalScopeKind.forStatement, @@ -3842,14 +3842,14 @@ class BodyBuilderImpl extends StackListenerImpl // using the variables with the same name within the same block. List intermediateVariables = []; List internalVariables = []; - for (Variable variable in pattern.declaredVariables) { + for (InternalVariable variable in pattern.internalDeclaredVariables) { variable.isFinal |= isFinal; // TODO(johnniwinther): Can we avoid creating synthetic variables here? InternalVariable intermediateVariable = intern .createSyntheticVariableForValue( intern.createVariableGet( - variable as InternalVariable, + variable, fileOffset: variable.fileOffset, ), isClosureContextLoweringEnabled: isClosureContextLoweringEnabled, @@ -3858,7 +3858,7 @@ class BodyBuilderImpl extends StackListenerImpl InternalVariable internalVariable = intern.createSyntheticVariable( isClosureContextLoweringEnabled: isClosureContextLoweringEnabled, - name: variable.name!, + name: variable.cosmeticName!, initializer: intern.createVariableGet( intermediateVariable, fileOffset: variable.fileOffset, @@ -4302,9 +4302,9 @@ class BodyBuilderImpl extends StackListenerImpl leftBracket.charCount, ); - List patterns = new List.filled( + List patterns = new List.filled( count, - dummyPattern, + dummyInternalPattern, growable: true, ); for (int i = count - 1; i >= 0; i--) { @@ -4479,7 +4479,10 @@ class BodyBuilderImpl extends StackListenerImpl token.charCount, ); - List patterns = new List.filled(count, dummyPattern); + List patterns = new List.filled( + count, + dummyInternalPattern, + ); for (int i = count - 1; i >= 0; i--) { patterns[i] = toPattern(pop()); } @@ -4646,7 +4649,7 @@ class BodyBuilderImpl extends StackListenerImpl /* key */ unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]), ]), ); - Pattern value = toPattern(pop()); + InternalPattern value = toPattern(pop()); Expression key = toValue(pop()); push(intern.createMapPatternEntry(colon.charOffset, key, value)); } @@ -4669,19 +4672,19 @@ class BodyBuilderImpl extends StackListenerImpl leftBrace.charOffset, leftBrace.charCount, ); - List entries = []; + List entries = []; for (int i = 0; i < count; i++) { Object? entry = pop(); - if (entry is MapPatternEntry) { + if (entry is InternalMapPatternEntry) { entries.add(entry); } else { - entry as RestPattern; + entry as InternalRestPattern; entries.add(intern.createMapPatternRestEntry(entry.fileOffset)); } } for (int i = 0, j = entries.length - 1; i < j; i++, j--) { - MapPatternEntry entry = entries[i]; + InternalMapPatternEntry entry = entries[i]; entries[i] = entries[j]; entries[j] = entry; } @@ -5258,7 +5261,7 @@ class BodyBuilderImpl extends StackListenerImpl TypeUse.asType, allowPotentiallyConstantType: true, ); - Pattern operand = toPattern(pop()); + InternalPattern operand = toPattern(pop()); push(intern.createCastPattern(operator.charOffset, operand, type)); } @@ -7259,8 +7262,9 @@ class BodyBuilderImpl extends StackListenerImpl enterLocalScope(thenScope); } else { createAndEnterLocalScope(kind: LocalScopeKind.ifCaseHead); - for (Variable variable in patternGuard.pattern.declaredVariables) { - declareVariable(variable as InternalVariable, _localScope); + InternalPattern pattern = patternGuard.pattern as InternalPattern; + for (InternalVariable variable in pattern.internalDeclaredVariables) { + declareVariable(variable, _localScope); } LocalScope thenScope = _localScope.createNestedScope( kind: LocalScopeKind.ifElement, @@ -8288,12 +8292,12 @@ class BodyBuilderImpl extends StackListenerImpl Object expression = pop() as Object; Object pattern = pop() as Object; - if (pattern is Pattern) { + if (pattern is InternalPattern) { pop(); // Metadata. bool isFinal = patternKeyword?.lexeme == 'final'; - for (Variable variable in pattern.declaredVariables) { + for (InternalVariable variable in pattern.internalDeclaredVariables) { variable.isFinal |= isFinal; - declareVariable(variable as InternalVariable, _localScope); + declareVariable(variable, _localScope); } } @@ -8959,13 +8963,15 @@ class BodyBuilderImpl extends StackListenerImpl expressionOrPatterns[i]; PatternGuard? patternGuard = expressionOrPattern.patternGuard; if (patternGuard != null) { + InternalPattern pattern = patternGuard.pattern as InternalPattern; if (jointPatternVariables == null) { jointPatternVariables = [ - for (Variable variable in patternGuard.pattern.declaredVariables) + for (InternalVariable variable + in pattern.internalDeclaredVariables) intern.createSyntheticVariable( isClosureContextLoweringEnabled: isClosureContextLoweringEnabled, - name: variable.name!, + name: variable.cosmeticName!, isFinal: variable.isFinal, fileOffset: variable.fileOffset, ), @@ -8978,13 +8984,14 @@ class BodyBuilderImpl extends StackListenerImpl ); } } else { - Map patternVariablesByName = { - for (Variable variable in patternGuard.pattern.declaredVariables) - variable.name!: variable, + Map patternVariablesByName = { + for (InternalVariable variable + in pattern.internalDeclaredVariables) + variable.cosmeticName!: variable, }; for (InternalVariable jointVariable in jointPatternVariables) { String jointVariableName = jointVariable.cosmeticName!; - Variable? patternVariable = patternVariablesByName.remove( + InternalVariable? patternVariable = patternVariablesByName.remove( jointVariableName, ); if (patternVariable != null) { @@ -8998,11 +9005,11 @@ class BodyBuilderImpl extends StackListenerImpl } } if (patternVariablesByName.isNotEmpty) { - for (Variable variable in patternVariablesByName.values) { + for (InternalVariable variable in patternVariablesByName.values) { InternalVariable jointVariable = intern.createSyntheticVariable( isClosureContextLoweringEnabled: isClosureContextLoweringEnabled, - name: variable.name!, + name: variable.cosmeticName!, isFinal: variable.isFinal, fileOffset: variable.fileOffset, ); @@ -9081,9 +9088,9 @@ class BodyBuilderImpl extends StackListenerImpl // Here we declare the pattern variables in the scope of the case head. It // makes the variables visible in the 'when' clause of the head. Object? pattern = peek(); - if (pattern is Pattern) { - for (Variable variable in pattern.declaredVariables) { - declareVariable(variable as InternalVariable, _localScope); + if (pattern is InternalPattern) { + for (InternalVariable variable in pattern.internalDeclaredVariables) { + declareVariable(variable, _localScope); } } push(constantContext); @@ -9120,9 +9127,9 @@ class BodyBuilderImpl extends StackListenerImpl // Here we declare the pattern variables. It makes the variables visible // body of the case. Object? pattern = peek(); - if (pattern is Pattern) { - for (Variable variable in pattern.declaredVariables) { - declareVariable(variable as InternalVariable, _localScope); + if (pattern is InternalPattern) { + for (InternalVariable variable in pattern.internalDeclaredVariables) { + declareVariable(variable, _localScope); } } } @@ -9253,8 +9260,9 @@ class BodyBuilderImpl extends StackListenerImpl PatternGuard? patternGuard = expressionsOrPatternGuards.first.patternGuard; if (patternGuard != null) { - for (Variable variable in patternGuard.pattern.declaredVariables) { - String variableName = variable.name!; + InternalPattern pattern = patternGuard.pattern as InternalPattern; + for (InternalVariable variable in pattern.internalDeclaredVariables) { + String variableName = variable.cosmeticName!; if (usedNamesOffsets[variableName] case [int offset, ...]) { addProblem( diag.jointPatternVariableWithLabelDefault.withArguments( @@ -9442,9 +9450,9 @@ class BodyBuilderImpl extends StackListenerImpl ); Object? pattern = pop(); createAndEnterLocalScope(kind: LocalScopeKind.caseHead); - if (pattern is Pattern) { - for (Variable variable in pattern.declaredVariables) { - declareVariable(variable as InternalVariable, _localScope); + if (pattern is InternalPattern) { + for (InternalVariable variable in pattern.internalDeclaredVariables) { + declareVariable(variable, _localScope); } } push(pattern); @@ -10865,14 +10873,14 @@ class BodyBuilderImpl extends StackListenerImpl beginToken.charOffset, beginToken.charCount, ); - List? fields; + List? fields; for (int i = 0; i < count; i++) { Object? field = pop(); - if (field is NamedPattern) { - (fields ??= []).add(field); + if (field is InternalNamedPattern) { + (fields ??= []).add(field); } else { Pattern pattern = toPattern(field); - if (pattern is! InvalidPattern) { + if (pattern is! InternalInvalidPattern) { addProblem( diag.unnamedObjectPatternField, pattern.fileOffset, @@ -10883,7 +10891,7 @@ class BodyBuilderImpl extends StackListenerImpl } if (fields != null) { for (int i = 0, j = fields.length - 1; i < j; i++, j--) { - NamedPattern field = fields[i]; + InternalNamedPattern field = fields[i]; fields[i] = fields[j]; fields[j] = field; } @@ -10900,7 +10908,7 @@ class BodyBuilderImpl extends StackListenerImpl debugEvent("ObjectPattern"); assert( checkState(firstIdentifier, [ - ValueKinds.PatternListOrNull, + ValueKinds.NamedPatternListOrNull, ValueKinds.TypeArgumentsOrNull, ]), ); @@ -10911,7 +10919,7 @@ class BodyBuilderImpl extends StackListenerImpl firstIdentifier.charCount, ); - List? fields = pop() as List?; + List? fields = pop() as List?; List? typeArguments = pop() as List?; handleIdentifier(firstIdentifier, IdentifierContext.prefixedTypeReference); @@ -10932,12 +10940,15 @@ class BodyBuilderImpl extends StackListenerImpl allowPotentiallyConstantType: true, ); push( - new ObjectPatternInternal( - type, - fields ?? [], - typeDeclaration is TypeAliasBuilder ? typeDeclaration.typedef : null, + intern.createObjectPattern( + requiredType: type, + fields: fields ?? [], + typedef: typeDeclaration is TypeAliasBuilder + ? typeDeclaration.typedef + : null, hasExplicitTypeArguments: typeArguments != null, - )..fileOffset = firstIdentifier.charOffset, + fileOffset: firstIdentifier.charOffset, + ), ); } @@ -10955,7 +10966,7 @@ class BodyBuilderImpl extends StackListenerImpl ]), ); - Pattern? subPattern; + InternalPattern? subPattern; if (hasSubPattern) { subPattern = toPattern(pop()); } @@ -11032,7 +11043,7 @@ class BodyBuilderImpl extends StackListenerImpl bang.charOffset, bang.charCount, ); - Pattern operand = toPattern(pop()); + InternalPattern operand = toPattern(pop()); push(intern.createNullAssertPattern(bang.charOffset, operand)); } @@ -11053,7 +11064,7 @@ class BodyBuilderImpl extends StackListenerImpl question.charOffset, question.charCount, ); - Pattern operand = toPattern(pop()); + InternalPattern operand = toPattern(pop()); push(intern.createNullCheckPattern(question.charOffset, operand)); } @@ -11155,7 +11166,7 @@ class BodyBuilderImpl extends StackListenerImpl ); Object? value = pop(); - Pattern pattern = toPattern(value); + InternalPattern pattern = toPattern(value); if (colon != null) { Object? identifier = pop(); if (identifier is ParserRecovery) { @@ -11207,12 +11218,12 @@ class BodyBuilderImpl extends StackListenerImpl ]), ); Expression initializer = popForValue(); - Pattern pattern = toPattern(pop()); + InternalPattern pattern = toPattern(pop()); bool isFinal = keyword.lexeme == 'final'; - for (Variable variable in pattern.declaredVariables) { + for (InternalVariable variable in pattern.internalDeclaredVariables) { variable.isFinal = isFinal; variable.hasDeclaredInitializer = true; - declareVariable(variable as InternalVariable, _localScope); + declareVariable(variable, _localScope); } // TODO(johnniwinther,cstefantsova): Handle metadata. pop(NullValues.Metadata) as List?; diff --git a/pkg/front_end/lib/src/kernel/external_ast_helper.dart b/pkg/front_end/lib/src/kernel/external_ast_helper.dart index 374528a6872..a7eb62e12d1 100644 --- a/pkg/front_end/lib/src/kernel/external_ast_helper.dart +++ b/pkg/front_end/lib/src/kernel/external_ast_helper.dart @@ -47,6 +47,14 @@ LogicalExpression createAndExpression( ..fileOffset = fileOffset; } +AndPattern createAndPattern({ + required Pattern left, + required Pattern right, + required int fileOffset, +}) { + return new AndPattern(left, right)..fileOffset = fileOffset; +} + /// Creates an [Arguments] object for the [positional] and [named] arguments, /// and [types] as the type arguments. Arguments createArguments( @@ -99,6 +107,20 @@ AssertStatement createAssertStatement( )..fileOffset = fileOffset; } +AssignedVariablePattern createAssignedVariablePattern({ + required Variable variable, + required DartType matchedValueType, + required bool needsCast, + required bool hasObservableEffect, + required int fileOffset, +}) { + return new AssignedVariablePattern(variable) + ..matchedValueType = matchedValueType + ..needsCast = needsCast + ..hasObservableEffect = hasObservableEffect + ..fileOffset = fileOffset; +} + /// Creates a block containing the [statements]. Block createBlock( List statements, { @@ -133,6 +155,14 @@ BreakStatement createBreakStatement( return new BreakStatement(target)..fileOffset = fileOffset; } +CastPattern createCastPattern({ + required Pattern pattern, + required DartType type, + required int fileOffset, +}) { + return new CastPattern(pattern, type)..fileOffset = fileOffset; +} + CatchVariable createCatchVariable({ required String name, required DartType? type, @@ -148,27 +178,6 @@ CatchVariable createCatchVariable({ )..fileOffset = fileOffset; } -LateVariable createLateVariable({ - required String? cosmeticName, - required DartType? type, - bool isFinal = false, - bool isConst = false, - bool isWildcard = false, - required int fileOffset, - Expression? initializer, - bool hasDeclaredInitializer = false, -}) { - return new LateVariable( - cosmeticName: cosmeticName, - type: type, - isFinal: isFinal, - isConst: isConst, - isWildcard: isWildcard, - initializer: initializer, - hasDeclaredInitializer: hasDeclaredInitializer, - )..fileOffset = fileOffset; -} - /// Creates a conditional expression of the [condition] and the [then] and /// [otherwise] branches with the given [staticType] of the resulting /// expression. @@ -191,6 +200,20 @@ ConstantExpression createConstantExpression( return new ConstantExpression(constant, type)..fileOffset = fileOffset; } +ConstantPattern createConstantPattern({ + required Expression expression, + required DartType expressionType, + required Procedure equalsTarget, + required FunctionType equalsType, + required int fileOffset, +}) { + return new ConstantPattern(expression) + ..expressionType = expressionType + ..equalsTarget = equalsTarget + ..equalsType = equalsType + ..fileOffset = fileOffset; +} + Constructor createConstructor( FunctionNode function, { required Name name, @@ -510,6 +533,19 @@ InvalidInitializer createInvalidInitializer( ..isRedirectingInitializer = isRedirectingInitializer; } +InvalidPattern createInvalidPattern({ + required Expression error, + required List declaredVariables, + int? fileOffset, +}) { + return new InvalidPattern( + error, + declaredVariables: declaredVariables + .map((InternalVariable variable) => variable.astVariable) + .toList(), + )..fileOffset = fileOffset ?? error.fileOffset; +} + /// Creates an is-test on [operand] against [type]. IsExpression createIsExpression( Expression operand, @@ -527,6 +563,27 @@ LabeledStatement createLabeledStatement( return new LabeledStatement(statement)..fileOffset = fileOffset; } +LateVariable createLateVariable({ + required String? cosmeticName, + required DartType? type, + bool isFinal = false, + bool isConst = false, + bool isWildcard = false, + required int fileOffset, + Expression? initializer, + bool hasDeclaredInitializer = false, +}) { + return new LateVariable( + cosmeticName: cosmeticName, + type: type, + isFinal: isFinal, + isConst: isConst, + isWildcard: isWildcard, + initializer: initializer, + hasDeclaredInitializer: hasDeclaredInitializer, + )..fileOffset = fileOffset; +} + /// Creates a [Let] of [variable] with the given [body] using /// `variable.fileOffset` as the file offset for the let. Let createLet(Variable variable, Expression body) { @@ -541,6 +598,45 @@ Let createLetEffect({required Expression effect, required Expression result}) { ..fileOffset = effect.fileOffset; } +ListPattern createListPattern({ + required DartType? typeArgument, + required List patterns, + required DartType requiredType, + required DartType matchedValueType, + required bool needsCheck, + required DartType lookupType, + required bool hasRestPattern, + required Member lengthTarget, + required DartType lengthType, + required Procedure lengthCheckTarget, + required FunctionType lengthCheckType, + required Procedure sublistTarget, + required FunctionType sublistType, + required Procedure minusTarget, + required FunctionType minusType, + required Procedure indexGetTarget, + required FunctionType indexGetType, + required int fileOffset, +}) { + return new ListPattern(typeArgument, patterns) + ..requiredType = requiredType + ..matchedValueType = matchedValueType + ..needsCheck = needsCheck + ..lookupType = lookupType + ..hasRestPattern = hasRestPattern + ..lengthTarget = lengthTarget + ..lengthType = lengthType + ..lengthCheckTarget = lengthCheckTarget + ..lengthCheckType = lengthCheckType + ..sublistTarget = sublistTarget + ..sublistType = sublistType + ..minusTarget = minusTarget + ..minusType = minusType + ..indexGetTarget = indexGetTarget + ..indexGetType = indexGetType + ..fileOffset = fileOffset; +} + /// Creates an invocation of the local function [variable] with the provided /// [arguments]. LocalFunctionInvocation createLocalFunctionInvocation( @@ -566,6 +662,47 @@ MapLiteralEntry createMapLiteralEntry( return new MapLiteralEntry(key, value)..fileOffset = fileOffset; } +MapPattern createMapPattern({ + required DartType? keyType, + required DartType? valueType, + required List entries, + required DartType requiredType, + required DartType matchedValueType, + required bool needsCheck, + required DartType lookupType, + required Procedure containsKeyTarget, + required FunctionType containsKeyType, + required Procedure indexGetTarget, + required FunctionType indexGetType, + required int fileOffset, +}) { + return new MapPattern(keyType, valueType, entries) + ..requiredType = requiredType + ..matchedValueType = matchedValueType + ..needsCheck = needsCheck + ..lookupType = lookupType + ..containsKeyTarget = containsKeyTarget + ..containsKeyType = containsKeyType + ..indexGetTarget = indexGetTarget + ..indexGetType = indexGetType + ..fileOffset = fileOffset; +} + +MapPatternEntry createMapPatternEntry({ + required Expression key, + required DartType keyType, + required Pattern value, + required int fileOffset, +}) { + return new MapPatternEntry(key, value) + ..keyType = keyType + ..fileOffset = fileOffset; +} + +MapPatternRestEntry createMapPatternRestEntry({required int fileOffset}) { + return new MapPatternRestEntry()..fileOffset = fileOffset; +} + Field createMutableField( Name name, { DartType type = const DynamicType(), @@ -636,21 +773,64 @@ NamedParameter createNamedParameter({ )..fileOffset = fileOffset; } +NamedPattern createNamedPattern({ + required String name, + Name? fieldName, + required Pattern pattern, + required int fileOffset, +}) { + NamedPattern result = new NamedPattern(name, pattern) + ..fileOffset = fileOffset; + if (fieldName != null) { + result.fieldName = fieldName; + } + return result; +} + /// Creates a [Not] of [operand]. Not createNot(Expression operand) { return new Not(operand)..fileOffset = operand.fileOffset; } +NullAssertPattern createNullAssertPattern({ + required Pattern pattern, + required int fileOffset, +}) { + return new NullAssertPattern(pattern)..fileOffset = fileOffset; +} + /// Creates a [NullCheck] of [expression]. NullCheck createNullCheck(Expression expression, {required int fileOffset}) { return new NullCheck(expression)..fileOffset = fileOffset; } +NullCheckPattern createNullCheckPattern({ + required Pattern pattern, + required int fileOffset, +}) { + return new NullCheckPattern(pattern)..fileOffset = fileOffset; +} + /// Creates a null literal. NullLiteral createNullLiteral({required int fileOffset}) { return new NullLiteral()..fileOffset = fileOffset; } +ObjectPattern createObjectPattern({ + required DartType requiredType, + required List fields, + required DartType matchedValueType, + required bool needsCheck, + required DartType lookupType, + required int fileOffset, +}) { + return new ObjectPattern(requiredType, fields) + ..matchedValueType = matchedValueType + ..needsCheck = needsCheck + ..lookupType = lookupType + ..fileOffset = fileOffset; +} + /// Creates a logical or expression of [left] and [right]. LogicalExpression createOrExpression( Expression left, @@ -661,6 +841,19 @@ LogicalExpression createOrExpression( ..fileOffset = fileOffset; } +OrPattern createOrPattern({ + required Pattern left, + required Pattern right, + required List orPatternJointVariables, + required int fileOffset, +}) { + return new OrPattern( + left, + right, + orPatternJointVariables: orPatternJointVariables, + )..fileOffset = fileOffset; +} + // TODO(johnniwinther): Should this require a type? Variable createParameterVariable( String? name, { @@ -761,6 +954,53 @@ Procedure createProcedure( ..fileEndOffset = fileEndOffset; } +RecordPattern createRecordPattern({ + required List patterns, + required RecordType requiredType, + required DartType matchedValueType, + required bool needsCheck, + required RecordType lookupType, + + required int fileOffset, +}) { + return new RecordPattern(patterns) + ..requiredType = requiredType + ..matchedValueType = matchedValueType + ..needsCheck = needsCheck + ..lookupType = lookupType + ..fileOffset = fileOffset; +} + +RelationalPattern createRelationalPattern({ + required RelationalPatternKind kind, + required Expression expression, + required DartType expressionType, + required DartType matchedValueType, + required RelationalAccessKind accessKind, + required Name? name, + required Procedure? target, + required List? typeArguments, + required FunctionType? functionType, + required int fileOffset, +}) { + return new RelationalPattern(kind, expression) + ..expressionType = expressionType + ..matchedValueType = matchedValueType + ..accessKind = accessKind + ..name = name + ..target = target + ..typeArguments = typeArguments + ..functionType = functionType + ..fileOffset = fileOffset; +} + +RestPattern createRestPattern({ + required Pattern? subPattern, + required int fileOffset, +}) { + return new RestPattern(subPattern)..fileOffset; +} + ReturnStatement createReturnStatement( Expression expression, { int? fileOffset, @@ -951,6 +1191,17 @@ VariableGet createVariableGet( ..promotedType = promotedType != variable.type ? promotedType : null; } +VariablePattern createVariablePattern({ + required DartType? type, + required Variable variable, + required DartType matchedValueType, + required int fileOffset, +}) { + return new VariablePattern(type, variable) + ..matchedValueType = matchedValueType + ..fileOffset = fileOffset; +} + /// Creates a [VariableSet] of [variable] with the [value]. Expression createVariableSet( Variable variable, @@ -977,3 +1228,10 @@ VariableStatement createVariableStatement(VariableDeclaration declaration) { return new VariableStatement(declaration) ..fileOffset = declaration.fileOffset; } + +WildcardPattern createWildcardPattern({ + required DartType? type, + required int fileOffset, +}) { + return new WildcardPattern(type)..fileOffset = fileOffset; +} diff --git a/pkg/front_end/lib/src/kernel/internal_ast.dart b/pkg/front_end/lib/src/kernel/internal_ast.dart index b274ffd1588..02b0b82df4c 100644 --- a/pkg/front_end/lib/src/kernel/internal_ast.dart +++ b/pkg/front_end/lib/src/kernel/internal_ast.dart @@ -1483,7 +1483,6 @@ class InternalNamedParameter extends TreeNode } @override - // Coverage-ignore(suite): Not run. List get annotations => astVariable.annotations; @override @@ -1627,7 +1626,6 @@ mixin DelegatingVariableMixin on InternalVariableMixin } @override - // Coverage-ignore(suite): Not run. List get annotations => astVariable.annotations; @override @@ -1751,7 +1749,6 @@ mixin DelegatingVariableMixin on InternalVariableMixin } @override - // Coverage-ignore(suite): Not run. bool get isRequired => astVariable.isRequired; @override @@ -5360,26 +5357,6 @@ class InternalRecordLiteral extends InternalExpression { } } -/// Data structure used by the body builder in place of [ObjectPattern], to -/// allow additional information to be captured that is needed during type -/// inference. -class ObjectPatternInternal extends ObjectPattern { - /// If the type name in the object pattern refers to a typedef, the typedef in - /// question; otherwise `null`. - final Typedef? typedef; - - /// Indicates whether the object pattern included explicit type arguments; if - /// `true` this means that no further type inference needs to be performed. - final bool hasExplicitTypeArguments; - - ObjectPatternInternal( - super.requiredType, - super.fields, - this.typedef, { - required this.hasExplicitTypeArguments, - }); -} - class ExtensionTypeRedirectingInitializer extends InternalInitializer { Reference targetReference; ActualArguments arguments; @@ -6889,3 +6866,842 @@ class InternalFunctionDeclaration extends InternalStatement { return "$runtimeType(${toStringInternal()}"; } } + +// Coverage-ignore(suite): Not run. +sealed class InternalPattern extends AuxiliaryPattern { + List get internalDeclaredVariables; + + @override + @Deprecated('Use internalDeclaredVariables instead') + List get declaredVariables => + unsupported("${runtimeType}.declaredVariables", -1, null); + + @override + void replaceChild(TreeNode child, TreeNode replacement) { + // Do nothing. The node should not be part of the resulting AST, anyway. + } + + @override + void visitChildren(Visitor v) => + unsupported("${runtimeType}.visitChildren", -1, null); + + @override + void transformChildren(Transformer v) => + unsupported("${runtimeType}.transformChildren", -1, null); + + @override + void transformOrRemoveChildren(RemovingTransformer v) { + unsupported("${runtimeType}.transformOrRemoveChildren", -1, null); + } + + shared.PatternResult acceptInference( + InferenceVisitorImpl visitor, + SharedMatchContext context, + ); +} + +/// An [InternalPattern] for `pattern || pattern`. +class InternalOrPattern extends InternalPattern { + final InternalPattern left; + final InternalPattern right; + + final List orPatternJointVariables; + + @override + List get internalDeclaredVariables => + orPatternJointVariables; + + InternalOrPattern( + this.left, + this.right, { + required this.orPatternJointVariables, + required int fileOffset, + }) { + left.parent = this; + right.parent = this; + this.fileOffset = fileOffset; + } + + @override + shared.PatternResult acceptInference( + InferenceVisitorImpl visitor, + SharedMatchContext context, + ) { + return visitor.visitInternalOrPattern(this, context); + } + + @override + // Coverage-ignore(suite): Not run. + void toTextInternal(AstPrinter printer) { + left.toTextInternal(printer); + printer.write(' || '); + right.toTextInternal(printer); + } + + @override + String toString() { + return "$runtimeType(${toStringInternal()})"; + } +} + +/// An [InternalPattern] for `pattern && pattern`. +class InternalAndPattern extends InternalPattern { + final InternalPattern left; + final InternalPattern right; + + @override + List get internalDeclaredVariables => [ + ...left.internalDeclaredVariables, + ...right.internalDeclaredVariables, + ]; + + InternalAndPattern(this.left, this.right, {required int fileOffset}) { + left.parent = this; + right.parent = this; + this.fileOffset = fileOffset; + } + + @override + shared.PatternResult acceptInference( + InferenceVisitorImpl visitor, + SharedMatchContext context, + ) { + return visitor.visitInternalAndPattern(this, context); + } + + @override + // Coverage-ignore(suite): Not run. + void toTextInternal(AstPrinter printer) { + left.toTextInternal(printer); + printer.write(' && '); + right.toTextInternal(printer); + } + + @override + String toString() { + return "$runtimeType(${toStringInternal()})"; + } +} + +/// An [InternalPattern] based on a constant [Expression]. +class InternalConstantPattern extends InternalPattern { + final Expression expression; + + InternalConstantPattern({required this.expression, required int fileOffset}) { + expression.parent = this; + this.fileOffset = fileOffset; + } + + @override + List get internalDeclaredVariables => const []; + + @override + shared.PatternResult acceptInference( + InferenceVisitorImpl visitor, + SharedMatchContext context, + ) { + return visitor.visitInternalConstantPattern(this, context); + } + + @override + // Coverage-ignore(suite): Not run. + void toTextInternal(AstPrinter printer) { + expression.toTextInternal(printer); + } + + @override + String toString() { + return "ConstantPattern(${toStringInternal()})"; + } +} + +class InternalAssignedVariablePattern extends InternalPattern { + final InternalVariable variable; + + InternalAssignedVariablePattern(this.variable, {required int fileOffset}) { + this.fileOffset = fileOffset; + } + + @override + List get internalDeclaredVariables => const []; + + @override + String get variableName => variable.cosmeticName!; + + @override + shared.PatternResult acceptInference( + InferenceVisitorImpl visitor, + SharedMatchContext context, + ) { + return visitor.visitInternalAssignedVariablePattern(this, context); + } + + @override + // Coverage-ignore(suite): Not run. + void toTextInternal(AstPrinter printer) { + printer.write(variable.cosmeticName!); + } + + @override + String toString() { + return "$runtimeType(${toStringInternal()})"; + } +} + +/// An [InternalPattern] for `pattern as type`. +class InternalCastPattern extends InternalPattern { + final InternalPattern pattern; + final DartType type; + + InternalCastPattern(this.pattern, this.type, {required int fileOffset}) { + pattern.parent = this; + this.fileOffset = fileOffset; + } + + @override + String? get variableName => pattern.variableName; + + @override + List get internalDeclaredVariables => + pattern.internalDeclaredVariables; + + @override + shared.PatternResult acceptInference( + InferenceVisitorImpl visitor, + SharedMatchContext context, + ) { + return visitor.visitInternalCastPattern(this, context); + } + + @override + // Coverage-ignore(suite): Not run. + void toTextInternal(AstPrinter printer) { + pattern.toTextInternal(printer); + printer.write(' as '); + printer.writeType(type); + } + + @override + String toString() { + return "$runtimeType(${toStringInternal()})"; + } +} + +class InternalInvalidPattern extends InternalPattern { + final Expression invalidExpression; + + @override + final List internalDeclaredVariables; + + InternalInvalidPattern({ + required this.invalidExpression, + required this.internalDeclaredVariables, + required int fileOffset, + }) { + invalidExpression.parent = this; + this.fileOffset = fileOffset; + } + + @override + shared.PatternResult acceptInference( + InferenceVisitorImpl visitor, + SharedMatchContext context, + ) { + return visitor.visitInternalInvalidPattern(this, context); + } + + @override + // Coverage-ignore(suite): Not run. + void toTextInternal(AstPrinter printer) { + printer.writeExpression(invalidExpression); + } + + @override + String toString() { + return "$runtimeType(${toStringInternal()})"; + } +} + +/// An [InternalPattern] for `[pattern0, ... patternN]`. +class InternalListPattern extends InternalPattern { + /// The element type argument as specified by the list pattern syntax. + DartType? typeArgument; + + List patterns; + + @override + List get internalDeclaredVariables => [ + for (InternalPattern pattern in patterns) + ...pattern.internalDeclaredVariables, + ]; + + InternalListPattern({ + required this.typeArgument, + required this.patterns, + required int fileOffset, + }) { + setParents(patterns, this); + this.fileOffset = fileOffset; + } + + @override + shared.PatternResult acceptInference( + InferenceVisitorImpl visitor, + SharedMatchContext context, + ) { + return visitor.visitInternalListPattern(this, context); + } + + @override + // Coverage-ignore(suite): Not run. + void toTextInternal(AstPrinter printer) { + if (typeArgument != null) { + printer.write('<'); + printer.writeType(typeArgument!); + printer.write('>'); + } + printer.write('['); + String comma = ''; + for (Pattern pattern in patterns) { + printer.write(comma); + pattern.toTextInternal(printer); + comma = ', '; + } + printer.write(']'); + } + + @override + String toString() { + return "$runtimeType(${toStringInternal()})"; + } +} + +final InternalPattern dummyInternalPattern = new InternalConstantPattern( + expression: dummyExpression, + fileOffset: TreeNode.noOffset, +); + +class InternalMapPattern extends InternalPattern { + /// The key type arguments as specific in the map pattern syntax. + DartType? keyType; + + /// The value type arguments as specific in the map pattern syntax. + DartType? valueType; + + final List entries; + + @override + List get internalDeclaredVariables => [ + for (InternalMapPatternEntry entry in entries) + if (entry is! InternalMapPatternRestEntry) + ...entry.value.internalDeclaredVariables, + ]; + + InternalMapPattern({ + required this.keyType, + required this.valueType, + required this.entries, + required int fileOffset, + }) : assert((keyType == null) == (valueType == null)) { + setParents(entries, this); + this.fileOffset = fileOffset; + } + + @override + shared.PatternResult acceptInference( + InferenceVisitorImpl visitor, + SharedMatchContext context, + ) { + return visitor.visitInternalMapPattern(this, context); + } + + @override + // Coverage-ignore(suite): Not run. + void toTextInternal(AstPrinter printer) { + if (keyType != null && valueType != null) { + printer.writeTypeArguments([keyType!, valueType!]); + } + printer.write('{'); + String comma = ''; + for (InternalMapPatternEntry entry in entries) { + printer.write(comma); + entry.toTextInternal(printer); + comma = ', '; + } + printer.write('}'); + } + + @override + String toString() { + return '$runtimeType(${toStringInternal()})'; + } +} + +class InternalMapPatternEntry extends TreeNode with InternalTreeNode { + final Expression key; + final InternalPattern value; + + InternalMapPatternEntry({ + required this.key, + required this.value, + required int fileOffset, + }) { + value.parent = this; + this.fileOffset = fileOffset; + } + + @override + R accept(TreeVisitor v) { + throw new UnimplementedError('${runtimeType}.accept'); + } + + @override + R accept1(TreeVisitor1 v, A arg) { + throw new UnimplementedError('${runtimeType}.accept1'); + } + + @override + // Coverage-ignore(suite): Not run. + void toTextInternal(AstPrinter printer) { + key.toTextInternal(printer); + printer.write(': '); + value.toTextInternal(printer); + } + + @override + String toString() { + return 'MapPatternEntry(${toStringInternal()})'; + } +} + +class InternalMapPatternRestEntry extends TreeNode + with InternalTreeNode + implements InternalMapPatternEntry { + InternalMapPatternRestEntry({required int fileOffset}) { + this.fileOffset = fileOffset; + } + + @override + // Coverage-ignore(suite): Not run. + Expression get key => throw new UnsupportedError('$runtimeType.key'); + + @override + // Coverage-ignore(suite): Not run. + InternalPattern get value => throw new UnsupportedError('$runtimeType.value'); + + @override + R accept(TreeVisitor v) { + throw new UnimplementedError('${runtimeType}.accept'); + } + + @override + R accept1(TreeVisitor1 v, A arg) { + throw new UnimplementedError('${runtimeType}.accept1'); + } + + @override + // Coverage-ignore(suite): Not run. + void toTextInternal(AstPrinter printer) { + printer.write('...'); + } + + @override + String toString() { + return '$runtimeType(${toStringInternal()})'; + } +} + +class InternalNamedPattern extends InternalPattern { + final String name; + final InternalPattern pattern; + + @override + List get internalDeclaredVariables => + pattern.internalDeclaredVariables; + + InternalNamedPattern({ + required this.name, + required this.pattern, + required int fileOffset, + }) { + pattern.parent = this; + this.fileOffset = fileOffset; + } + + @override + shared.PatternResult acceptInference( + InferenceVisitorImpl visitor, + SharedMatchContext context, + ) { + // InternalNamedPattern isn't a real pattern; this code should never be + // reached. + throw new StateError( + '$runtimeType.acceptInference should never be reached', + ); + } + + @override + // Coverage-ignore(suite): Not run. + void toTextInternal(AstPrinter printer) { + printer.write(name); + printer.write(': '); + pattern.toTextInternal(printer); + } + + @override + String toString() { + return '$runtimeType(${toStringInternal()})'; + } +} + +/// An [InternalPattern] for `pattern!`. +class InternalNullAssertPattern extends InternalPattern { + final InternalPattern pattern; + + InternalNullAssertPattern({required this.pattern, required int fileOffset}) { + pattern.parent = this; + this.fileOffset = fileOffset; + } + + @override + String? get variableName => pattern.variableName; + + @override + List get internalDeclaredVariables => + pattern.internalDeclaredVariables; + + @override + shared.PatternResult acceptInference( + InferenceVisitorImpl visitor, + SharedMatchContext context, + ) { + return visitor.visitInternalNullAssertPattern(this, context); + } + + @override + // Coverage-ignore(suite): Not run. + void toTextInternal(AstPrinter printer) { + pattern.toTextInternal(printer); + printer.write('!'); + } + + @override + String toString() { + return "$runtimeType(${toStringInternal()})"; + } +} + +/// An [InternalPattern] for `pattern?`. +class InternalNullCheckPattern extends InternalPattern { + final InternalPattern pattern; + + InternalNullCheckPattern({required this.pattern, required int fileOffset}) { + pattern.parent = this; + this.fileOffset = fileOffset; + } + + @override + String? get variableName => pattern.variableName; + + @override + List get internalDeclaredVariables => + pattern.internalDeclaredVariables; + + @override + shared.PatternResult acceptInference( + InferenceVisitorImpl visitor, + SharedMatchContext context, + ) { + return visitor.visitInternalNullCheckPattern(this, context); + } + + @override + // Coverage-ignore(suite): Not run. + void toTextInternal(AstPrinter printer) { + pattern.toTextInternal(printer); + printer.write('?'); + } + + @override + String toString() { + return "$runtimeType(${toStringInternal()})"; + } +} + +class InternalObjectPattern extends InternalPattern { + /// The type specified as part of the object pattern syntax. + DartType requiredType; + + final List fields; + + /// If the type name in the object pattern refers to a typedef, the typedef in + /// question; otherwise `null`. + final Typedef? typedef; + + /// Indicates whether the object pattern included explicit type arguments; if + /// `true` this means that no further type inference needs to be performed. + final bool hasExplicitTypeArguments; + + InternalObjectPattern({ + required this.requiredType, + required this.fields, + required this.typedef, + required this.hasExplicitTypeArguments, + required int fileOffset, + }) { + setParents(fields, this); + this.fileOffset = fileOffset; + } + + @override + List get internalDeclaredVariables { + return [ + for (InternalNamedPattern field in fields) + ...field.internalDeclaredVariables, + ]; + } + + @override + shared.PatternResult acceptInference( + InferenceVisitorImpl visitor, + SharedMatchContext context, + ) { + return visitor.visitInternalObjectPattern(this, context); + } + + @override + // Coverage-ignore(suite): Not run. + void toTextInternal(AstPrinter printer) { + printer.writeType(requiredType); + printer.write('('); + String comma = ''; + for (Pattern field in fields) { + printer.write(comma); + field.toTextInternal(printer); + comma = ', '; + } + printer.write(')'); + } + + @override + String toString() { + return "$runtimeType(${toStringInternal()})"; + } +} + +class InternalRecordPattern extends InternalPattern { + final List patterns; + + @override + List get internalDeclaredVariables => [ + for (InternalPattern pattern in patterns) + ...pattern.internalDeclaredVariables, + ]; + + InternalRecordPattern({required this.patterns, required int fileOffset}) { + setParents(patterns, this); + this.fileOffset = fileOffset; + } + + @override + shared.PatternResult acceptInference( + InferenceVisitorImpl visitor, + SharedMatchContext context, + ) { + return visitor.visitInternalRecordPattern(this, context); + } + + @override + // Coverage-ignore(suite): Not run. + void toTextInternal(AstPrinter printer) { + printer.write('('); + String comma = ''; + for (Pattern pattern in patterns) { + printer.write(comma); + pattern.toTextInternal(printer); + comma = ', '; + } + printer.write(')'); + } + + @override + String toString() { + return '$runtimeType(${toStringInternal()})'; + } +} + +/// An [InternalPattern] for `operator expression` where `operator is either +/// ==, !=, <, <=, >, or >=. +class InternalRelationalPattern extends InternalPattern { + final RelationalPatternKind kind; + final Expression expression; + + InternalRelationalPattern({ + required this.kind, + required this.expression, + required int fileOffset, + }) { + expression.parent = this; + this.fileOffset = fileOffset; + } + + @override + List get internalDeclaredVariables => const []; + + @override + shared.PatternResult acceptInference( + InferenceVisitorImpl visitor, + SharedMatchContext context, + ) { + return visitor.visitInternalRelationalPattern(this, context); + } + + @override + // Coverage-ignore(suite): Not run. + void toTextInternal(AstPrinter printer) { + switch (kind) { + case RelationalPatternKind.equals: + printer.write('== '); + break; + case RelationalPatternKind.notEquals: + printer.write('!= '); + break; + case RelationalPatternKind.lessThan: + printer.write('< '); + break; + case RelationalPatternKind.lessThanEqual: + printer.write('<= '); + break; + case RelationalPatternKind.greaterThan: + printer.write('> '); + break; + case RelationalPatternKind.greaterThanEqual: + printer.write('>= '); + break; + } + printer.writeExpression(expression); + } + + @override + String toString() { + return "$runtimeType(${toStringInternal()})"; + } +} + +class InternalRestPattern extends InternalPattern { + InternalPattern? subPattern; + + InternalRestPattern({required this.subPattern, required int fileOffset}) { + subPattern?.parent = this; + this.fileOffset = fileOffset; + } + + @override + List get internalDeclaredVariables => + subPattern?.internalDeclaredVariables ?? const []; + + @override + shared.PatternResult acceptInference( + InferenceVisitorImpl visitor, + SharedMatchContext context, + ) { + // InternalRestPattern isn't a real pattern; this code should never be + // reached. + throw new StateError( + '$runtimeType.acceptInference should never be reached', + ); + } + + @override + // Coverage-ignore(suite): Not run. + void toTextInternal(AstPrinter printer) { + printer.write('...'); + if (subPattern != null) { + subPattern!.toTextInternal(printer); + } + } + + @override + String toString() { + return "$runtimeType(${toStringInternal()})"; + } +} + +class InternalVariablePattern extends InternalPattern { + // TODO(johnniwinther): Should this be accessed through [variable] instead? + final DartType? type; + final InternalVariable variable; + + @override + List get internalDeclaredVariables => [variable]; + + InternalVariablePattern({ + required this.type, + required this.variable, + required int fileOffset, + }) { + variable.parent = this; + this.fileOffset = fileOffset; + } + + @override + String get variableName => variable.cosmeticName!; + + @override + shared.PatternResult acceptInference( + InferenceVisitorImpl visitor, + SharedMatchContext context, + ) { + return visitor.visitInternalVariablePattern(this, context); + } + + @override + // Coverage-ignore(suite): Not run. + void toTextInternal(AstPrinter printer) { + if (type != null) { + type!.toTextInternal(printer); + printer.write(" "); + } else { + printer.write("var "); + } + printer.write(variable.cosmeticName!); + } + + @override + String toString() { + return "$runtimeType(${toStringInternal()})"; + } +} + +class InternalWildcardPattern extends InternalPattern { + final DartType? type; + + InternalWildcardPattern({required this.type, required int fileOffset}) { + this.fileOffset = fileOffset; + } + @override + List get internalDeclaredVariables => const []; + + @override + shared.PatternResult acceptInference( + InferenceVisitorImpl visitor, + SharedMatchContext context, + ) { + return visitor.visitInternalWildcardPattern(this, context); + } + + @override + // Coverage-ignore(suite): Not run. + void toTextInternal(AstPrinter printer) { + if (type != null) { + type!.toTextInternal(printer); + printer.write(" "); + } + printer.write("_"); + } + + @override + String toString() { + return "$runtimeType(${toStringInternal()})"; + } +} diff --git a/pkg/front_end/lib/src/kernel/internal_ast_helper.dart b/pkg/front_end/lib/src/kernel/internal_ast_helper.dart index cdebf0b9d97..393d7c37fbe 100644 --- a/pkg/front_end/lib/src/kernel/internal_ast_helper.dart +++ b/pkg/front_end/lib/src/kernel/internal_ast_helper.dart @@ -30,8 +30,12 @@ Expression checkLibraryIsLoaded(int fileOffset, LibraryDependency dependency) { return new CheckLibraryIsLoaded(dependency)..fileOffset = fileOffset; } -AndPattern createAndPattern(int fileOffset, Pattern left, Pattern right) { - return new AndPattern(left, right)..fileOffset = fileOffset; +Pattern createAndPattern( + int fileOffset, + InternalPattern left, + InternalPattern right, +) { + return new InternalAndPattern(left, right, fileOffset: fileOffset); } ActualArguments createArguments( @@ -92,12 +96,11 @@ AssertStatement createAssertStatement( )..fileOffset = fileOffset; } -AssignedVariablePattern createAssignedVariablePattern( +Pattern createAssignedVariablePattern( int fileOffset, InternalVariable variable, ) { - return new AssignedVariablePattern(variable.asVariableDeclaration) - ..fileOffset = fileOffset; + return new InternalAssignedVariablePattern(variable, fileOffset: fileOffset); } Expression createAwaitExpression(int fileOffset, Expression operand) { @@ -159,8 +162,12 @@ Statement createBreakStatement(int fileOffset, Object? label) { ..target = label is LabeledStatement ? label : dummyLabeledStatement; } -CastPattern createCastPattern(int fileOffset, Pattern pattern, DartType type) { - return new CastPattern(pattern, type)..fileOffset = fileOffset; +Pattern createCastPattern( + int fileOffset, + InternalPattern pattern, + DartType type, +) { + return new InternalCastPattern(pattern, type, fileOffset: fileOffset); } /// Return a representation of a catch clause. @@ -231,8 +238,11 @@ ConditionalExpression createConditionalExpression( )..fileOffset = fileOffset; } -ConstantPattern createConstantPattern(Expression expression) { - return new ConstantPattern(expression)..fileOffset = expression.fileOffset; +InternalPattern createConstantPattern(Expression expression) { + return new InternalConstantPattern( + expression: expression, + fileOffset: expression.fileOffset, + ); } ConstructorTearOff createConstructorTearOff(int fileOffset, Member target) { @@ -593,12 +603,15 @@ Expression createIntLiteralLarge( return new LargeIntLiteral(strippedLiteral, literal, fileOffset: fileOffset); } -InvalidPattern createInvalidPattern( +Pattern createInvalidPattern( Expression expression, { - required List declaredVariables, + required List declaredVariables, }) { - return new InvalidPattern(expression, declaredVariables: declaredVariables) - ..fileOffset = expression.fileOffset; + return new InternalInvalidPattern( + invalidExpression: expression, + internalDeclaredVariables: declaredVariables, + fileOffset: expression.fileOffset, + ); } /// Return a representation of an `is` expression at the given [fileOffset]. @@ -712,12 +725,16 @@ ListLiteral createListLiteral( )..fileOffset = fileOffset; } -ListPattern createListPattern( +Pattern createListPattern( int fileOffset, DartType? typeArgument, - List patterns, + List patterns, ) { - return new ListPattern(typeArgument, patterns)..fileOffset = fileOffset; + return new InternalListPattern( + typeArgument: typeArgument, + patterns: patterns, + fileOffset: fileOffset, + ); } LoadLibrary createLoadLibrary( @@ -846,25 +863,34 @@ MapLiteralEntry createMapLiteralEntry( return new MapLiteralEntry(key, value)..fileOffset = fileOffset; } -MapPattern createMapPattern( +Pattern createMapPattern( int fileOffset, DartType? keyType, DartType? valueType, - List entries, + List entries, ) { - return new MapPattern(keyType, valueType, entries)..fileOffset = fileOffset; + return new InternalMapPattern( + keyType: keyType, + valueType: valueType, + entries: entries, + fileOffset: fileOffset, + ); } -MapPatternEntry createMapPatternEntry( +InternalMapPatternEntry createMapPatternEntry( int fileOffset, Expression key, - Pattern value, + InternalPattern value, ) { - return new MapPatternEntry(key, value)..fileOffset = fileOffset; + return new InternalMapPatternEntry( + key: key, + value: value, + fileOffset: fileOffset, + ); } -MapPatternRestEntry createMapPatternRestEntry(int fileOffset) { - return new MapPatternRestEntry()..fileOffset = fileOffset; +InternalMapPatternRestEntry createMapPatternRestEntry(int fileOffset) { + return new InternalMapPatternRestEntry(fileOffset: fileOffset); } Expression createMethodInvocation( @@ -950,16 +976,27 @@ InternalVariable createNamedParameter({ } } -NamedPattern createNamedPattern(int fileOffset, String name, Pattern pattern) { - return new NamedPattern(name, pattern)..fileOffset = fileOffset; +Pattern createNamedPattern( + int fileOffset, + String name, + InternalPattern pattern, +) { + return new InternalNamedPattern( + name: name, + pattern: pattern, + fileOffset: fileOffset, + ); } Expression createNot(int fileOffset, Expression operand) { return new Not(operand)..fileOffset = fileOffset; } -NullAssertPattern createNullAssertPattern(int fileOffset, Pattern pattern) { - return new NullAssertPattern(pattern)..fileOffset = fileOffset; +Pattern createNullAssertPattern(int fileOffset, InternalPattern pattern) { + return new InternalNullAssertPattern( + pattern: pattern, + fileOffset: fileOffset, + ); } Expression createNullAwareElement(int fileOffset, Expression expression) { @@ -990,8 +1027,8 @@ NullCheck createNullCheck(int fileOffset, Expression expression) { return new NullCheck(expression)..fileOffset = fileOffset; } -NullCheckPattern createNullCheckPattern(int fileOffset, Pattern pattern) { - return new NullCheckPattern(pattern)..fileOffset = fileOffset; +Pattern createNullCheckPattern(int fileOffset, InternalPattern pattern) { + return new InternalNullCheckPattern(pattern: pattern, fileOffset: fileOffset); } /// Return a representation of a null literal at the given [fileOffset]. @@ -999,17 +1036,34 @@ NullLiteral createNullLiteral(int fileOffset) { return new NullLiteral()..fileOffset = fileOffset; } -OrPattern createOrPattern( +Pattern createOrPattern( int fileOffset, - Pattern left, - Pattern right, { - required List orPatternJointVariables, + InternalPattern left, + InternalPattern right, { + required List orPatternJointVariables, }) { - return new OrPattern( + return new InternalOrPattern( left, right, orPatternJointVariables: orPatternJointVariables, - )..fileOffset = fileOffset; + fileOffset: fileOffset, + ); +} + +Pattern createObjectPattern({ + required DartType requiredType, + required List fields, + required Typedef? typedef, + required bool hasExplicitTypeArguments, + required int fileOffset, +}) { + return new InternalObjectPattern( + requiredType: requiredType, + fields: fields, + typedef: typedef, + hasExplicitTypeArguments: hasExplicitTypeArguments, + fileOffset: fileOffset, + ); } ParenthesizedExpression createParenthesized( @@ -1200,8 +1254,8 @@ Expression createPropertySet( )..fileOffset = fileOffset; } -RecordPattern createRecordPattern(int fileOffset, List patterns) { - return new RecordPattern(patterns)..fileOffset = fileOffset; +Pattern createRecordPattern(int fileOffset, List patterns) { + return new InternalRecordPattern(patterns: patterns, fileOffset: fileOffset); } RedirectingFactoryTearOff createRedirectingFactoryTearOff( @@ -1212,16 +1266,23 @@ RedirectingFactoryTearOff createRedirectingFactoryTearOff( return new RedirectingFactoryTearOff(procedure)..fileOffset = fileOffset; } -RelationalPattern createRelationalPattern( +Pattern createRelationalPattern( int fileOffset, RelationalPatternKind kind, Expression expression, ) { - return new RelationalPattern(kind, expression)..fileOffset = fileOffset; + return new InternalRelationalPattern( + kind: kind, + expression: expression, + fileOffset: fileOffset, + ); } -RestPattern createRestPattern(int fileOffset, Pattern? subPattern) { - return new RestPattern(subPattern)..fileOffset = fileOffset; +Pattern createRestPattern(int fileOffset, InternalPattern? subPattern) { + return new InternalRestPattern( + subPattern: subPattern, + fileOffset: fileOffset, + ); } /// Return a representation of a rethrow statement consisting of the @@ -1512,13 +1573,16 @@ InternalVariableGet createVariableGet( return new InternalVariableGet(variable)..fileOffset = fileOffset; } -VariablePattern createVariablePattern( +Pattern createVariablePattern( int fileOffset, DartType? type, InternalVariable variable, ) { - return new VariablePattern(type, variable.asVariableDeclaration) - ..fileOffset = fileOffset; + return new InternalVariablePattern( + type: type, + variable: variable, + fileOffset: fileOffset, + ); } InternalVariableSet createVariableSet( @@ -1547,8 +1611,8 @@ Statement createWhileStatement( return new WhileStatement(condition, body)..fileOffset = fileOffset; } -WildcardPattern createWildcardPattern(int fileOffset, DartType? type) { - return new WildcardPattern(type)..fileOffset = fileOffset; +Pattern createWildcardPattern(int fileOffset, DartType? type) { + return new InternalWildcardPattern(type: type, fileOffset: fileOffset); } /// Return a representation of a yield statement at the given [fileOffset] diff --git a/pkg/front_end/lib/src/source/value_kinds.dart b/pkg/front_end/lib/src/source/value_kinds.dart index 9e0d5a20bf1..76bfa0d749d 100644 --- a/pkg/front_end/lib/src/source/value_kinds.dart +++ b/pkg/front_end/lib/src/source/value_kinds.dart @@ -135,17 +135,21 @@ class ValueKinds { static const ValueKind MapLiteralEntry = const SingleValueKind(); static const ValueKind MapPatternEntry = - const SingleValueKind(); + const SingleValueKind(); static const ValueKind ParameterList = const SingleValueKind>(); - static const ValueKind Pattern = const SingleValueKind(); + static const ValueKind Pattern = + const SingleValueKind(); static const ValueKind PatternGuard = const SingleValueKind(); - static const ValueKind PatternOrNull = const SingleValueKind( - NullValues.Pattern, - ); + static const ValueKind PatternOrNull = + const SingleValueKind(NullValues.Pattern); static const ValueKind PatternListOrNull = - const SingleValueKind>(NullValues.PatternList); + const SingleValueKind>(NullValues.PatternList); + static const ValueKind NamedPatternListOrNull = + const SingleValueKind>( + NullValues.PatternList, + ); static const ValueKind PrefixOrNull = const SingleValueKind( NullValues.Prefix, ); diff --git a/pkg/front_end/lib/src/type_inference/context_allocation_strategy.dart b/pkg/front_end/lib/src/type_inference/context_allocation_strategy.dart index 333aa3719b3..dbe31818f3e 100644 --- a/pkg/front_end/lib/src/type_inference/context_allocation_strategy.dart +++ b/pkg/front_end/lib/src/type_inference/context_allocation_strategy.dart @@ -236,7 +236,6 @@ class LoopDepthAllocationStrategy case ScopeProviderInfoKind.FunctionNode: case ScopeProviderInfoKind.FunctionNodeWithThis: case ScopeProviderInfoKind.InstanceField: - // Coverage-ignore(suite): Not run. case ScopeProviderInfoKind.StaticField: return true; } diff --git a/pkg/front_end/lib/src/type_inference/inference_visitor.dart b/pkg/front_end/lib/src/type_inference/inference_visitor.dart index 5cd969bf6f0..a56e967a3ec 100644 --- a/pkg/front_end/lib/src/type_inference/inference_visitor.dart +++ b/pkg/front_end/lib/src/type_inference/inference_visitor.dart @@ -146,7 +146,6 @@ class InferenceVisitorImpl extends InferenceVisitorBase ExpressionVisitor1, StatementVisitor, InitializerVisitor, - PatternVisitor1, InferenceVisitor { /// Debug-only: if `true`, manipulations of [_rewriteStack] performed by /// [popRewrite] and [pushRewrite] will be printed. @@ -922,17 +921,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase "${node.runtimeType}", "InferenceVisitor", node.fileOffset, - node.location!.file, - ); - } - - // Coverage-ignore(suite): Not run. - Never _unhandledPattern(Pattern node) { - problems.unhandled( - "${node.runtimeType}", - "InferenceVisitor", - node.fileOffset, - node.location!.file, + fileUri, ); } @@ -3504,7 +3493,6 @@ class InferenceVisitorImpl extends InferenceVisitorBase }); StatementInferenceResult bodyResult = inferStatement(node.body); if (bodyResult.hasChanged) { - // Coverage-ignore-block(suite): Not run. node.body = bodyResult.statement..parent = node; } flowAnalysis.for_updaterBegin(); @@ -3866,9 +3854,10 @@ class InferenceVisitorImpl extends InferenceVisitorBase node.then, node.otherwise, { - for (Variable variable - in node.patternGuard.pattern.declaredVariables) - variable.name!: variable, + for (InternalVariable variable + in (node.patternGuard.pattern as InternalPattern) + .internalDeclaredVariables) + variable.cosmeticName!: variable.astVariable, }, ); @@ -4286,9 +4275,10 @@ class InferenceVisitorImpl extends InferenceVisitorBase expression: element.expression, pattern: element.patternGuard.pattern, variables: { - for (Variable variable - in element.patternGuard.pattern.declaredVariables) - variable.name!: variable, + for (InternalVariable variable + in (element.patternGuard.pattern as InternalPattern) + .internalDeclaredVariables) + variable.cosmeticName!: variable.astVariable, }, guard: element.patternGuard.guard, ifTrue: element.then, @@ -4340,7 +4330,6 @@ class InferenceVisitorImpl extends InferenceVisitorBase rewrite = popRewrite(); if (!identical(patternGuard.pattern, rewrite)) { - // Coverage-ignore-block(suite): Not run. patternGuard.pattern = (rewrite as Pattern)..parent = patternGuard; } @@ -4394,7 +4383,6 @@ class InferenceVisitorImpl extends InferenceVisitorBase Object? rewrite = popRewrite(NullValues.Expression); if (!identical(patternVariableDeclaration.pattern, rewrite)) { - // Coverage-ignore-block(suite): Not run. patternVariableDeclaration.pattern = (rewrite as Pattern) ..parent = patternVariableDeclaration; } @@ -7413,9 +7401,10 @@ class InferenceVisitorImpl extends InferenceVisitorBase expression: entry.expression, pattern: entry.patternGuard.pattern, variables: { - for (Variable variable - in entry.patternGuard.pattern.declaredVariables) - variable.name!: variable, + for (InternalVariable variable + in (entry.patternGuard.pattern as InternalPattern) + .internalDeclaredVariables) + variable.cosmeticName!: variable.astVariable, }, guard: entry.patternGuard.guard, ifTrue: entry.then, @@ -7495,7 +7484,6 @@ class InferenceVisitorImpl extends InferenceVisitorBase rewrite = popRewrite(); if (!identical(patternGuard.pattern, rewrite)) { - // Coverage-ignore-block(suite): Not run. patternGuard.pattern = (rewrite as Pattern)..parent = patternGuard; } @@ -7543,7 +7531,6 @@ class InferenceVisitorImpl extends InferenceVisitorBase Object? rewrite = popRewrite(NullValues.Expression); if (!identical(patternVariableDeclaration.pattern, rewrite)) { - // Coverage-ignore-block(suite): Not run. patternVariableDeclaration.pattern = (rewrite as Pattern) ..parent = patternVariableDeclaration; } @@ -14280,7 +14267,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase // performed. needsCoercion = needsCoercion || - parent is RelationalPattern && parent.expression == node; + parent is InternalRelationalPattern && parent.expression == node; ExpressionInferenceResult expressionResult = inferExpression( node, @@ -14323,8 +14310,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase @override PatternResult dispatchPattern(SharedMatchContext context, TreeNode node) { - if (node is Pattern) { - return node.accept1(this, context); + if (node is InternalPattern) { + return node.acceptInference(this, context); } else { return analyzeConstantPattern(context, node, node as Expression); } @@ -14332,87 +14319,94 @@ class InferenceVisitorImpl extends InferenceVisitorBase @override SharedTypeSchemaView dispatchPatternSchema(Node node) { - if (node is AndPattern) { - return analyzeLogicalAndPatternSchema(node.left, node.right); - } else if (node is AssignedVariablePattern) { - return analyzeAssignedVariablePatternSchema(node.variable); - } else if (node is CastPattern) { - return analyzeCastPatternSchema(); - } else if (node is ConstantPattern) { - return analyzeConstantPatternSchema(); - } else if (node is ListPattern) { - return analyzeListPatternSchema( - elementType: node.typeArgument?.wrapSharedTypeView(), - elements: node.patterns, - ); - } else if (node is MapPattern) { - return analyzeMapPatternSchema( - typeArguments: - node.keyType != null && - // Coverage-ignore(suite): Not run. - node.valueType != null - ? - // Coverage-ignore(suite): Not run. - ( - keyType: new SharedTypeView(node.keyType!), - valueType: new SharedTypeView(node.valueType!), - ) - : null, - elements: node.entries, - ); - } else if (node is NamedPattern) { - // Coverage-ignore-block(suite): Not run. - return dispatchPatternSchema(node.pattern); - } else if (node is NullAssertPattern) { - return analyzeNullCheckOrAssertPatternSchema( - node.pattern, - isAssert: true, - ); - } else if (node is NullCheckPattern) { - return analyzeNullCheckOrAssertPatternSchema( - node.pattern, - isAssert: false, - ); - } else if (node is ObjectPattern) { - return analyzeObjectPatternSchema(new SharedTypeView(node.requiredType)); - } else if (node is OrPattern) { - // Coverage-ignore-block(suite): Not run. - return analyzeLogicalOrPatternSchema(node.left, node.right); - } else if (node is RecordPattern) { - return analyzeRecordPatternSchema( - fields: >[ - for (Pattern element in node.patterns) - if (element is NamedPattern) - new RecordPatternField( - node: element, - name: element.name, - pattern: element.pattern, - ) - else - new RecordPatternField( - node: element, - name: null, - pattern: element, - ), - ], - ); - } else if (node is RelationalPattern) { - // Coverage-ignore-block(suite): Not run. - return analyzeRelationalPatternSchema(); - } else if (node is RestPattern) { - // Coverage-ignore-block(suite): Not run. - // This pattern can't appear on it's own. - return new SharedTypeSchemaView(const InvalidType()); - } else if (node is VariablePattern) { - return analyzeDeclaredVariablePatternSchema( - node.type?.wrapSharedTypeView(), - ); - } else if (node is WildcardPattern) { - return analyzeDeclaredVariablePatternSchema( - node.type?.wrapSharedTypeView(), - ); - } else if (node is InvalidPattern) { - return new SharedTypeSchemaView(const InvalidType()); + if (node is InternalPattern) { + switch (node) { + case InternalAndPattern(): + return analyzeLogicalAndPatternSchema(node.left, node.right); + case InternalAssignedVariablePattern(): + return analyzeAssignedVariablePatternSchema( + node.variable.astVariable, + ); + case InternalCastPattern(): + return analyzeCastPatternSchema(); + case InternalConstantPattern(): + return analyzeConstantPatternSchema(); + case InternalListPattern(): + return analyzeListPatternSchema( + elementType: node.typeArgument?.wrapSharedTypeView(), + elements: node.patterns, + ); + case InternalMapPattern(): + return analyzeMapPatternSchema( + typeArguments: + node.keyType != null && + // Coverage-ignore(suite): Not run. + node.valueType != null + ? + // Coverage-ignore(suite): Not run. + ( + keyType: new SharedTypeView(node.keyType!), + valueType: new SharedTypeView(node.valueType!), + ) + : null, + elements: node.entries, + ); + case InternalNamedPattern(): + // Coverage-ignore(suite): Not run. + return dispatchPatternSchema(node.pattern); + case InternalNullAssertPattern(): + return analyzeNullCheckOrAssertPatternSchema( + node.pattern, + isAssert: true, + ); + case InternalNullCheckPattern(): + return analyzeNullCheckOrAssertPatternSchema( + node.pattern, + isAssert: false, + ); + case InternalObjectPattern(): + return analyzeObjectPatternSchema( + new SharedTypeView(node.requiredType), + ); + case InternalOrPattern(): + // Coverage-ignore(suite): Not run. + return analyzeLogicalOrPatternSchema(node.left, node.right); + case InternalRecordPattern(): + return analyzeRecordPatternSchema( + fields: >[ + for (InternalPattern element in node.patterns) + if (element is InternalNamedPattern) + new RecordPatternField( + node: element, + name: element.name, + pattern: element.pattern, + ) + else + new RecordPatternField( + node: element, + name: null, + pattern: element, + ), + ], + ); + case InternalRelationalPattern(): + // Coverage-ignore(suite): Not run. + return analyzeRelationalPatternSchema(); + case InternalRestPattern(): + // Coverage-ignore(suite): Not run. + // This pattern can't appear on it's own. + return new SharedTypeSchemaView(const InvalidType()); + case InternalVariablePattern(): + return analyzeDeclaredVariablePatternSchema( + node.type?.wrapSharedTypeView(), + ); + case InternalWildcardPattern(): + return analyzeDeclaredVariablePatternSchema( + node.type?.wrapSharedTypeView(), + ); + case InternalInvalidPattern(): + return new SharedTypeSchemaView(const InvalidType()); + } } else { // Coverage-ignore-block(suite): Not run. return problems.unhandled( @@ -14553,8 +14547,9 @@ class InferenceVisitorImpl extends InferenceVisitorBase (node as SwitchExpression).cases[index]; Pattern pattern = switchExpressionCase.patternGuard.pattern; Map variables = { - for (Variable declaredVariable in pattern.declaredVariables) - declaredVariable.name!: declaredVariable, + for (InternalVariable declaredVariable + in (pattern as InternalPattern).internalDeclaredVariables) + declaredVariable.cosmeticName!: declaredVariable.astVariable, }; return new SwitchExpressionMemberInfo( head: new CaseHeadOrDefaultInfo( @@ -14591,9 +14586,10 @@ class InferenceVisitorImpl extends InferenceVisitorBase pattern: patternGuard.pattern, guard: patternGuard.guard, variables: { - for (Variable variable - in patternGuard.pattern.declaredVariables) - variable.name!: variable, + for (InternalVariable variable + in (patternGuard.pattern as InternalPattern) + .internalDeclaredVariables) + variable.cosmeticName!: variable.astVariable, }, ), if (case_.isDefault) @@ -14822,9 +14818,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase assert(_rewriteStack.isEmpty); } - @override - PatternResult visitVariablePattern( - VariablePattern node, + PatternResult visitInternalVariablePattern( + InternalVariablePattern node, SharedMatchContext context, ) { int? stackBase; @@ -14834,12 +14829,13 @@ class InferenceVisitorImpl extends InferenceVisitorBase analyzeDeclaredVariablePattern( context, node, - node.variable, - node.variable.name!, + node.variable.astVariable, + node.variableName, node.type?.wrapSharedTypeView(), ); - node.matchedValueType = analysisResult.matchedValueType.unwrapTypeView(); + DartType matchedValueType = analysisResult.matchedValueType + .unwrapTypeView(); Pattern? replacement; @@ -14847,10 +14843,10 @@ class InferenceVisitorImpl extends InferenceVisitorBase analysisResult.patternTypeMismatchInIrrefutableContextError; if (error != null) { // Coverage-ignore-block(suite): Not run. - replacement = new InvalidPattern( - error, - declaredVariables: node.declaredVariables, - )..fileOffset = error.fileOffset; + replacement = extern.createInvalidPattern( + error: error, + declaredVariables: node.internalDeclaredVariables, + ); } DartType inferredType = analysisResult.staticType.unwrapTypeView(); @@ -14858,15 +14854,22 @@ class InferenceVisitorImpl extends InferenceVisitorBase node.variable.type = inferredType; } - pushRewrite(replacement ?? node); + pushRewrite( + replacement ?? + extern.createVariablePattern( + type: node.type, + variable: node.variable.astVariable, + matchedValueType: matchedValueType, + fileOffset: node.fileOffset, + ), + ); assert(checkStack(node, stackBase, [/* pattern = */ ValueKinds.Pattern])); return analysisResult; } - @override - PatternResult visitWildcardPattern( - WildcardPattern node, + PatternResult visitInternalWildcardPattern( + InternalWildcardPattern node, SharedMatchContext context, ) { int? stackBase; @@ -14885,21 +14888,26 @@ class InferenceVisitorImpl extends InferenceVisitorBase analysisResult.patternTypeMismatchInIrrefutableContextError; if (error != null) { // Coverage-ignore-block(suite): Not run. - replacement = new InvalidPattern( - error, - declaredVariables: node.declaredVariables, - )..fileOffset = error.fileOffset; + replacement = extern.createInvalidPattern( + error: error, + declaredVariables: node.internalDeclaredVariables, + ); } - pushRewrite(replacement ?? node); + pushRewrite( + replacement ?? + extern.createWildcardPattern( + type: node.type, + fileOffset: node.fileOffset, + ), + ); assert(checkStack(node, stackBase, [/* pattern = */ ValueKinds.Pattern])); return analysisResult; } - @override - PatternResult visitConstantPattern( - ConstantPattern node, + PatternResult visitInternalConstantPattern( + InternalConstantPattern node, SharedMatchContext context, ) { int? stackBase; @@ -14913,15 +14921,13 @@ class InferenceVisitorImpl extends InferenceVisitorBase InvalidExpression? error = analysisResult.refutablePatternInIrrefutableContextError; if (error != null) { - replacement = new InvalidPattern( - error, - declaredVariables: node.declaredVariables, - )..fileOffset = error.fileOffset; + replacement = extern.createInvalidPattern( + error: error, + declaredVariables: node.internalDeclaredVariables, + ); } - DartType expressionType = node.expressionType = analysisResult - .expressionType - .unwrapTypeView(); + DartType expressionType = analysisResult.expressionType.unwrapTypeView(); ObjectAccessTarget equalsInvokeTarget = findInterfaceMember( expressionType, @@ -14936,8 +14942,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase equalsInvokeTarget.isNever, ); - node.equalsTarget = equalsInvokeTarget.classMember as Procedure; - node.equalsType = equalsInvokeTarget + Procedure equalsTarget = equalsInvokeTarget.classMember as Procedure; + FunctionType equalsType = equalsInvokeTarget .getFunctionType(this) .equalsFunctionType; @@ -14946,18 +14952,30 @@ class InferenceVisitorImpl extends InferenceVisitorBase ); Object? rewrite = popRewrite(); + Expression expression = node.expression; if (!identical(node.expression, rewrite)) { - node.expression = (rewrite as Expression)..parent = node; + expression = rewrite as Expression; } - pushRewrite(replacement ?? node); + pushRewrite( + replacement ?? + extern.createConstantPattern( + expression: expression, + expressionType: expressionType, + equalsTarget: equalsTarget, + equalsType: equalsType, + fileOffset: node.fileOffset, + ), + ); assert(checkStack(node, stackBase, [/* pattern = */ ValueKinds.Pattern])); return analysisResult; } - @override - PatternResult visitAndPattern(AndPattern node, SharedMatchContext context) { + PatternResult visitInternalAndPattern( + InternalAndPattern node, + SharedMatchContext context, + ) { int? stackBase; assert(checkStackBase(node, stackBase = stackHeight)); @@ -14976,25 +14994,33 @@ class InferenceVisitorImpl extends InferenceVisitorBase ); Object? rewrite = popRewrite(); + Pattern right = node.right; if (!identical(rewrite, node.right)) { - // Coverage-ignore-block(suite): Not run. - node.right = (rewrite as Pattern)..parent = node; + right = rewrite as Pattern; } rewrite = popRewrite(); + Pattern left = node.left; if (!identical(rewrite, node.left)) { - // Coverage-ignore-block(suite): Not run. - node.left = (rewrite as Pattern)..parent = node; + left = rewrite as Pattern; } - pushRewrite(node); + pushRewrite( + extern.createAndPattern( + left: left, + right: right, + fileOffset: node.fileOffset, + ), + ); assert(checkStack(node, stackBase, [/* pattern = */ ValueKinds.Pattern])); return analysisResult; } - @override - PatternResult visitOrPattern(OrPattern node, SharedMatchContext context) { + PatternResult visitInternalOrPattern( + InternalOrPattern node, + SharedMatchContext context, + ) { int? stackBase; assert(checkStackBase(node, stackBase = stackHeight)); @@ -15014,34 +15040,35 @@ class InferenceVisitorImpl extends InferenceVisitorBase analysisResult.refutablePatternInIrrefutableContextError; if (error != null) { // Coverage-ignore-block(suite): Not run. - replacement = new InvalidPattern( - error, - declaredVariables: node.declaredVariables, - )..fileOffset = error.fileOffset; + replacement = extern.createInvalidPattern( + error: error, + declaredVariables: node.internalDeclaredVariables, + ); } Object? rewrite = popRewrite(); + Pattern right = node.right; if (!identical(rewrite, node.right)) { - // Coverage-ignore-block(suite): Not run. - node.right = (rewrite as Pattern)..parent = node; + right = rewrite as Pattern; } rewrite = popRewrite(); + Pattern left = node.left; if (!identical(rewrite, node.left)) { - // Coverage-ignore-block(suite): Not run. - node.left = (rewrite as Pattern)..parent = node; + left = rewrite as Pattern; } Map leftDeclaredVariablesByName = { - for (Variable variable in node.left.declaredVariables) - variable.name!: variable, + for (InternalVariable variable in node.left.internalDeclaredVariables) + variable.cosmeticName!: variable.astVariable, }; Map jointVariableNames = { - for (Variable variable in node.orPatternJointVariables) - variable.name!: variable, + for (InternalVariable variable in node.orPatternJointVariables) + variable.cosmeticName!: variable.astVariable, }; - for (Variable rightVariable in node.right.declaredVariables) { - String rightVariableName = rightVariable.name!; + for (InternalVariable rightVariable + in node.right.internalDeclaredVariables) { + String rightVariableName = rightVariable.cosmeticName!; Variable? leftVariable = leftDeclaredVariablesByName[rightVariableName]; Variable? jointVariable = jointVariableNames[rightVariableName]; if (leftVariable != null && jointVariable != null) { @@ -15062,14 +15089,23 @@ class InferenceVisitorImpl extends InferenceVisitorBase } } - pushRewrite(replacement ?? node); + replacement ??= extern.createOrPattern( + left: left, + right: right, + orPatternJointVariables: jointVariableNames.values.toList(), + fileOffset: node.fileOffset, + ); + + pushRewrite(replacement); assert(checkStack(node, stackBase, [/* pattern = */ ValueKinds.Pattern])); return analysisResult; } - @override - PatternResult visitCastPattern(CastPattern node, SharedMatchContext context) { + PatternResult visitInternalCastPattern( + InternalCastPattern node, + SharedMatchContext context, + ) { int? stackBase; assert(checkStackBase(node, stackBase = stackHeight)); @@ -15085,20 +15121,25 @@ class InferenceVisitorImpl extends InferenceVisitorBase ); Object? rewrite = popRewrite(); + Pattern pattern = node.pattern; if (!identical(rewrite, node.pattern)) { - // Coverage-ignore-block(suite): Not run. - node.pattern = (rewrite as Pattern)..parent = node; + pattern = rewrite as Pattern; } - pushRewrite(node); + pushRewrite( + extern.createCastPattern( + pattern: pattern, + type: node.type, + fileOffset: node.fileOffset, + ), + ); assert(checkStack(node, stackBase, [/* pattern = */ ValueKinds.Pattern])); return analysisResult; } - @override - PatternResult visitNullAssertPattern( - NullAssertPattern node, + PatternResult visitInternalNullAssertPattern( + InternalNullAssertPattern node, SharedMatchContext context, ) { int? stackBase; @@ -15122,27 +15163,28 @@ class InferenceVisitorImpl extends InferenceVisitorBase analysisResult.refutablePatternInIrrefutableContextError; if (error != null) { // Coverage-ignore-block(suite): Not run. - replacement = new InvalidPattern( - error, - declaredVariables: node.declaredVariables, - )..fileOffset = error.fileOffset; + replacement = extern.createInvalidPattern( + error: error, + declaredVariables: node.internalDeclaredVariables, + ); } - Object? rewrite = popRewrite(); - if (!identical(rewrite, node.pattern)) { - // Coverage-ignore-block(suite): Not run. - node.pattern = (rewrite as Pattern)..parent = node; - } + Pattern pattern = popRewrite() as Pattern; - pushRewrite(replacement ?? node); + pushRewrite( + replacement ?? + extern.createNullAssertPattern( + pattern: pattern, + fileOffset: node.fileOffset, + ), + ); assert(checkStack(node, stackBase, [/* pattern = */ ValueKinds.Pattern])); return analysisResult; } - @override - PatternResult visitNullCheckPattern( - NullCheckPattern node, + PatternResult visitInternalNullCheckPattern( + InternalNullCheckPattern node, SharedMatchContext context, ) { int? stackBase; @@ -15160,20 +15202,23 @@ class InferenceVisitorImpl extends InferenceVisitorBase checkStack(node, stackBase, [/* subpattern = */ ValueKinds.Pattern]), ); - Object? rewrite = popRewrite(); - if (!identical(rewrite, node.pattern)) { - // Coverage-ignore-block(suite): Not run. - node.pattern = (rewrite as Pattern)..parent = node; - } + Pattern pattern = popRewrite() as Pattern; - pushRewrite(node); + pushRewrite( + extern.createNullCheckPattern( + pattern: pattern, + fileOffset: node.fileOffset, + ), + ); assert(checkStack(node, stackBase, [/* pattern = */ ValueKinds.Pattern])); return analysisResult; } - @override - PatternResult visitListPattern(ListPattern node, SharedMatchContext context) { + PatternResult visitInternalListPattern( + InternalListPattern node, + SharedMatchContext context, + ) { int? stackBase; assert(checkStackBase(node, stackBase = stackHeight)); @@ -15184,8 +15229,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase elementType: node.typeArgument?.wrapSharedTypeView(), ); - DartType matchedValueType = node.matchedValueType = analysisResult - .matchedValueType + DartType matchedValueType = analysisResult.matchedValueType .unwrapTypeView(); assert( @@ -15202,43 +15246,44 @@ class InferenceVisitorImpl extends InferenceVisitorBase InvalidExpression? error = analysisResult.patternTypeMismatchInIrrefutableContextError; if (error != null) { - replacement = new InvalidPattern( - error, - declaredVariables: node.declaredVariables, - )..fileOffset = error.fileOffset; + replacement = extern.createInvalidPattern( + error: error, + declaredVariables: node.internalDeclaredVariables, + ); } + List patterns = new List.filled( + node.patterns.length, + dummyPattern, + ); for (int i = node.patterns.length - 1; i >= 0; i--) { Object? rewrite = popRewrite(); InvalidExpression? error = analysisResult.duplicateRestPatternErrors?[i]; if (error != null) { - node.patterns[i] = - new InvalidPattern( - error, - declaredVariables: node.patterns[i].declaredVariables, - ) - ..fileOffset = error.fileOffset - ..parent = node; - } else if (!identical(rewrite, node.patterns[i])) { - node.patterns[i] = (rewrite as Pattern)..parent = node; + patterns[i] = extern.createInvalidPattern( + error: error, + declaredVariables: node.patterns[i].internalDeclaredVariables, + ); + } else { + patterns[i] = rewrite as Pattern; } } // TODO(johnniwinther): The required type computed by the type analyzer // isn't trivially `List` in all cases. Does that matter for the // lowering? - DartType requiredType = node.requiredType = analysisResult.requiredType - .unwrapTypeView(); + DartType requiredType = analysisResult.requiredType.unwrapTypeView(); - node.needsCheck = _needsCheck( + bool needsCheck = _needsCheck( matchedType: matchedValueType, requiredType: requiredType, ); - if (node.needsCheck) { - node.lookupType = requiredType; + DartType lookupType; + if (needsCheck) { + lookupType = requiredType; } else { - node.lookupType = matchedValueType; + lookupType = matchedValueType; } ObjectAccessTarget lengthTarget = findInterfaceMember( @@ -15250,8 +15295,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase ); assert(lengthTarget.isInstanceMember); - DartType lengthType = node.lengthType = lengthTarget.getGetterType(this); - node.lengthTarget = lengthTarget.classMember!; + DartType lengthType = lengthTarget.getGetterType(this); + Member lengthMember = lengthTarget.classMember!; ObjectAccessTarget sublistInvokeTarget = findInterfaceMember( requiredType, @@ -15262,8 +15307,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase ); assert(sublistInvokeTarget.isInstanceMember); - node.sublistTarget = sublistInvokeTarget.classMember as Procedure; - node.sublistType = sublistInvokeTarget + Procedure sublistTarget = sublistInvokeTarget.classMember as Procedure; + FunctionType sublistType = sublistInvokeTarget .getFunctionType(this) .sublistFunctionType; @@ -15277,8 +15322,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase assert(minusTarget.isInstanceMember); assert(minusTarget.isSpecialCasedBinaryOperator(this)); - node.minusTarget = minusTarget.classMember as Procedure; - node.minusType = replaceReturnType( + Procedure minusProcedure = minusTarget.classMember as Procedure; + FunctionType minusType = replaceReturnType( minusTarget.getFunctionType(this).minusFunctionType, typeSchemaEnvironment.getTypeOfSpecialCasedBinaryOperator( lengthType, @@ -15295,19 +15340,22 @@ class InferenceVisitorImpl extends InferenceVisitorBase ); assert(indexGetTarget.isInstanceMember); - node.indexGetTarget = indexGetTarget.classMember as Procedure; - node.indexGetType = indexGetTarget + Procedure indexGet = indexGetTarget.classMember as Procedure; + FunctionType indexGetType = indexGetTarget .getFunctionType(this) .indexGetFunctionType; - for (Pattern pattern in node.patterns) { + bool hasRestPattern = false; + for (Pattern pattern in patterns) { if (pattern is RestPattern) { - node.hasRestPattern = true; + hasRestPattern = true; break; } } - if (node.hasRestPattern) { + Procedure lengthCheckTarget; + FunctionType lengthCheckType; + if (hasRestPattern) { ObjectAccessTarget greaterThanOrEqualTarget = findInterfaceMember( lengthType, greaterThanOrEqualsName, @@ -15317,9 +15365,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase ); assert(greaterThanOrEqualTarget.isInstanceMember); - node.lengthCheckTarget = - greaterThanOrEqualTarget.classMember as Procedure; - node.lengthCheckType = greaterThanOrEqualTarget + lengthCheckTarget = greaterThanOrEqualTarget.classMember as Procedure; + lengthCheckType = greaterThanOrEqualTarget .getFunctionType(this) .greaterThanOrEqualsFunctionType; } else if (node.patterns.isEmpty) { @@ -15332,9 +15379,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase ); assert(lessThanOrEqualsInvokeTarget.isInstanceMember); - node.lengthCheckTarget = - lessThanOrEqualsInvokeTarget.classMember as Procedure; - node.lengthCheckType = lessThanOrEqualsInvokeTarget + lengthCheckTarget = lessThanOrEqualsInvokeTarget.classMember as Procedure; + lengthCheckType = lessThanOrEqualsInvokeTarget .getFunctionType(this) .lessThanOrEqualsFunctionType; } else { @@ -15347,13 +15393,35 @@ class InferenceVisitorImpl extends InferenceVisitorBase ); assert(equalsInvokeTarget.isInstanceMember); - node.lengthCheckTarget = equalsInvokeTarget.classMember as Procedure; - node.lengthCheckType = equalsInvokeTarget + lengthCheckTarget = equalsInvokeTarget.classMember as Procedure; + lengthCheckType = equalsInvokeTarget .getFunctionType(this) .equalsFunctionType; } - pushRewrite(replacement ?? node); + pushRewrite( + replacement ?? + extern.createListPattern( + typeArgument: node.typeArgument, + patterns: patterns, + requiredType: requiredType, + matchedValueType: matchedValueType, + needsCheck: needsCheck, + lookupType: lookupType, + hasRestPattern: hasRestPattern, + lengthTarget: lengthMember, + lengthType: lengthType, + lengthCheckTarget: lengthCheckTarget, + lengthCheckType: lengthCheckType, + sublistTarget: sublistTarget, + sublistType: sublistType, + minusTarget: minusProcedure, + minusType: minusType, + indexGetTarget: indexGet, + indexGetType: indexGetType, + fileOffset: node.fileOffset, + ), + ); assert(checkStack(node, stackBase, [/* pattern = */ ValueKinds.Pattern])); return analysisResult; @@ -15376,9 +15444,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase matchedType is DynamicType; } - @override - PatternResult visitObjectPattern( - ObjectPattern node, + PatternResult visitInternalObjectPattern( + InternalObjectPattern node, SharedMatchContext context, ) { int? stackBase; @@ -15389,7 +15456,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase context, node, fields: >[ - for (NamedPattern field in node.fields) + for (InternalNamedPattern field in node.fields) new RecordPatternField( node: field, name: field.name, @@ -15398,8 +15465,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase ], ); - DartType matchedValueType = node.matchedValueType = analysisResult - .matchedValueType + DartType matchedValueType = analysisResult.matchedValueType .unwrapTypeView(); assert( @@ -15419,44 +15485,54 @@ class InferenceVisitorImpl extends InferenceVisitorBase analysisResult.patternTypeMismatchInIrrefutableContextError; if (error != null) { // Coverage-ignore-block(suite): Not run. - replacement = new InvalidPattern( - error, - declaredVariables: node.declaredVariables, - )..fileOffset = error.fileOffset; + replacement = extern.createInvalidPattern( + error: error, + declaredVariables: node.internalDeclaredVariables, + ); } + List fields = new List.filled( + node.fields.length, + dummyNamedPattern, + ); for (int i = node.fields.length - 1; i >= 0; i--) { - NamedPattern field = node.fields[i]; + InternalNamedPattern field = node.fields[i]; Object? rewrite = popRewrite(); InvalidExpression? error = analysisResult.duplicateRecordPatternFieldErrors?[i]; if (error != null) { - field.pattern = - new InvalidPattern( - error, - declaredVariables: field.pattern.declaredVariables, - ) - ..fileOffset = error.fileOffset - ..parent = field; - } else if (!identical(rewrite, field.pattern)) { - field.pattern = (rewrite as Pattern)..parent = field; + fields[i] = extern.createNamedPattern( + name: field.name, + fieldName: new Name(field.name, libraryBuilder.library), + pattern: extern.createInvalidPattern( + error: error, + declaredVariables: field.pattern.internalDeclaredVariables, + ), + fileOffset: field.fileOffset, + ); + } else { + fields[i] = extern.createNamedPattern( + name: field.name, + fieldName: new Name(field.name, libraryBuilder.library), + pattern: rewrite as Pattern, + fileOffset: field.fileOffset, + ); } } - node.needsCheck = _needsCheck( + bool needsCheck = _needsCheck( matchedType: matchedValueType, requiredType: node.requiredType, ); - if (node.needsCheck) { - node.lookupType = node.requiredType; + DartType lookupType; + if (needsCheck) { + lookupType = node.requiredType; } else { - node.lookupType = matchedValueType; + lookupType = matchedValueType; } - for (NamedPattern field in node.fields) { - field.fieldName = new Name(field.name, libraryBuilder.library); - + for (NamedPattern field in fields) { ObjectAccessTarget fieldTarget = findInterfaceMember( node.requiredType, field.fieldName, @@ -15568,27 +15644,35 @@ class InferenceVisitorImpl extends InferenceVisitorBase } } - pushRewrite(replacement ?? node); + pushRewrite( + replacement ?? + extern.createObjectPattern( + requiredType: node.requiredType, + fields: fields, + matchedValueType: matchedValueType, + needsCheck: needsCheck, + lookupType: lookupType, + fileOffset: node.fileOffset, + ), + ); assert(checkStack(node, stackBase, [/* pattern = */ ValueKinds.Pattern])); return analysisResult; } - @override - PatternResult visitRestPattern(RestPattern node, SharedMatchContext context) { - // A rest pattern isn't a real pattern; this code should never be reached. - throw new StateError('visitRestPattern should never be reached'); - } - - @override - PatternResult visitInvalidPattern( - InvalidPattern node, + PatternResult visitInternalInvalidPattern( + InternalInvalidPattern node, SharedMatchContext context, ) { int? stackBase; assert(checkStackBase(node, stackBase = stackHeight)); - pushRewrite(node); + pushRewrite( + extern.createInvalidPattern( + error: node.invalidExpression, + declaredVariables: node.internalDeclaredVariables, + ), + ); assert(checkStack(node, stackBase, [/* pattern = */ ValueKinds.Pattern])); @@ -15597,9 +15681,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase ); } - @override - PatternResult visitRelationalPattern( - RelationalPattern node, + PatternResult visitInternalRelationalPattern( + InternalRelationalPattern node, SharedMatchContext context, ) { int? stackBase; @@ -15608,8 +15691,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase RelationalPatternResult analysisResult = analyzeRelationalPattern(context, node, node.expression); - DartType matchedValueType = node.matchedValueType = analysisResult - .matchedValueType + DartType matchedValueType = analysisResult.matchedValueType .unwrapTypeView(); assert( @@ -15623,37 +15705,37 @@ class InferenceVisitorImpl extends InferenceVisitorBase analysisResult.operatorReturnTypeNotAssignableToBoolError ?? analysisResult.argumentTypeNotAssignableError; if (error != null) { - replacement = new InvalidPattern( - error, - declaredVariables: node.declaredVariables, - )..fileOffset = error.fileOffset; + replacement = extern.createInvalidPattern( + error: error, + declaredVariables: node.internalDeclaredVariables, + ); } Object? rewrite = popRewrite(); + Expression expression = node.expression; if (!identical(rewrite, node.expression)) { - node.expression = (rewrite as Expression)..parent = node; + expression = rewrite as Expression; } DartType expressionType = analysisResult.operandType.unwrapTypeView(); - node.expressionType = expressionType; Name name; switch (node.kind) { case RelationalPatternKind.equals: case RelationalPatternKind.notEquals: - name = node.name = equalsName; + name = equalsName; break; case RelationalPatternKind.lessThan: - name = node.name = lessThanName; + name = lessThanName; break; case RelationalPatternKind.lessThanEqual: - name = node.name = lessThanOrEqualsName; + name = lessThanOrEqualsName; break; case RelationalPatternKind.greaterThan: - name = node.name = greaterThanName; + name = greaterThanName; break; case RelationalPatternKind.greaterThanEqual: - name = node.name = greaterThanOrEqualsName; + name = greaterThanOrEqualsName; break; } ObjectAccessTarget invokeTarget = findInterfaceMember( @@ -15663,6 +15745,10 @@ class InferenceVisitorImpl extends InferenceVisitorBase includeExtensionMethods: true, isSetter: false, ); + FunctionType? functionType; + RelationalAccessKind? accessKind; + Procedure? target; + List? typeArguments; switch (node.kind) { case RelationalPatternKind.equals: case RelationalPatternKind.notEquals: @@ -15672,11 +15758,9 @@ class InferenceVisitorImpl extends InferenceVisitorBase invokeTarget.isNever, ); - node.functionType = invokeTarget - .getFunctionType(this) - .equalsFunctionType; - node.accessKind = RelationalAccessKind.Instance; - node.target = invokeTarget.classMember as Procedure; + functionType = invokeTarget.getFunctionType(this).equalsFunctionType; + accessKind = RelationalAccessKind.Instance; + target = invokeTarget.classMember as Procedure; break; case RelationalPatternKind.lessThan: case RelationalPatternKind.lessThanEqual: @@ -15684,26 +15768,27 @@ class InferenceVisitorImpl extends InferenceVisitorBase case RelationalPatternKind.greaterThanEqual: switch (invokeTarget.kind) { case ObjectAccessTargetKind.instanceMember: - node.functionType = invokeTarget + functionType = invokeTarget .getFunctionType(this) .lessThanOrEqualsFunctionType; - node.target = invokeTarget.classMember as Procedure; - node.accessKind = RelationalAccessKind.Instance; + target = invokeTarget.classMember as Procedure; + accessKind = RelationalAccessKind.Instance; break; case ObjectAccessTargetKind.nullableInstanceMember: case ObjectAccessTargetKind.nullableExtensionMember: case ObjectAccessTargetKind.nullableExtensionTypeMember: case ObjectAccessTargetKind.missing: case ObjectAccessTargetKind.ambiguous: - replacement ??= new InvalidPattern( - createMissingMethodInvocation( + accessKind = RelationalAccessKind.Invalid; + replacement ??= extern.createInvalidPattern( + error: createMissingMethodInvocation( node.fileOffset, matchedValueType, name, isExpressionInvocation: false, ), - declaredVariables: node.declaredVariables, - )..fileOffset = node.fileOffset; + declaredVariables: node.internalDeclaredVariables, + ); break; case ObjectAccessTargetKind.objectMember: case ObjectAccessTargetKind.superMember: @@ -15723,34 +15808,50 @@ class InferenceVisitorImpl extends InferenceVisitorBase ); case ObjectAccessTargetKind.extensionMember: case ObjectAccessTargetKind.extensionTypeMember: - node.functionType = invokeTarget + functionType = invokeTarget .getFunctionType(this) .relationalFunctionType; - node.typeArguments = invokeTarget.receiverTypeArguments; - node.target = invokeTarget.member as Procedure; - node.accessKind = RelationalAccessKind.Static; + typeArguments = invokeTarget.receiverTypeArguments; + target = invokeTarget.member as Procedure; + accessKind = RelationalAccessKind.Static; break; case ObjectAccessTargetKind.dynamic: - node.accessKind = RelationalAccessKind.Dynamic; + accessKind = RelationalAccessKind.Dynamic; break; case ObjectAccessTargetKind.never: - node.accessKind = RelationalAccessKind.Never; + accessKind = RelationalAccessKind.Never; break; case ObjectAccessTargetKind.invalid: - node.accessKind = RelationalAccessKind.Invalid; + accessKind = RelationalAccessKind.Invalid; break; } break; } - pushRewrite(replacement ?? node); + pushRewrite( + replacement ?? + extern.createRelationalPattern( + kind: node.kind, + expression: expression, + expressionType: expressionType, + matchedValueType: matchedValueType, + accessKind: accessKind, + name: name, + target: target, + typeArguments: typeArguments, + functionType: functionType, + fileOffset: node.fileOffset, + ), + ); assert(checkStack(node, stackBase, [/* pattern = */ ValueKinds.Pattern])); return analysisResult; } - @override - PatternResult visitMapPattern(MapPattern node, SharedMatchContext context) { + PatternResult visitInternalMapPattern( + InternalMapPattern node, + SharedMatchContext context, + ) { int? stackBase; assert(checkStackBase(node, stackBase = stackHeight)); @@ -15770,8 +15871,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase elements: node.entries, ); - DartType matchedValueType = node.matchedValueType = analysisResult - .matchedValueType + DartType matchedValueType = analysisResult.matchedValueType .unwrapTypeView(); Pattern? replacement; @@ -15780,35 +15880,35 @@ class InferenceVisitorImpl extends InferenceVisitorBase analysisResult.patternTypeMismatchInIrrefutableContextError; if (error != null) { // Coverage-ignore-block(suite): Not run. - replacement = new InvalidPattern( - error, - declaredVariables: node.declaredVariables, - )..fileOffset = error.fileOffset; + replacement = extern.createInvalidPattern( + error: error, + declaredVariables: node.internalDeclaredVariables, + ); } error = analysisResult.emptyMapPatternError; if (error != null) { - replacement = new InvalidPattern( - error, - declaredVariables: node.declaredVariables, - )..fileOffset = error.fileOffset; + replacement = extern.createInvalidPattern( + error: error, + declaredVariables: node.internalDeclaredVariables, + ); } // TODO(johnniwinther): The required type computed by the type analyzer // isn't trivially `Map` in all cases. Does that matter // for the lowering? - DartType requiredType = node.requiredType = analysisResult.requiredType - .unwrapTypeView(); + DartType requiredType = analysisResult.requiredType.unwrapTypeView(); - node.needsCheck = _needsCheck( + bool needsCheck = _needsCheck( matchedType: matchedValueType, requiredType: requiredType, ); - if (node.needsCheck) { - node.lookupType = requiredType; + DartType lookupType; + if (needsCheck) { + lookupType = requiredType; } else { - node.lookupType = matchedValueType; + lookupType = matchedValueType; } ObjectAccessTarget containsKeyTarget = findInterfaceMember( @@ -15821,8 +15921,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase assert(containsKeyTarget.isInstanceMember); - node.containsKeyTarget = containsKeyTarget.classMember as Procedure; - node.containsKeyType = containsKeyTarget + Procedure containsKeyProcedure = containsKeyTarget.classMember as Procedure; + FunctionType containsKeyType = containsKeyTarget .getFunctionType(this) .containsKeyFunctionType; @@ -15835,8 +15935,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase ); assert(indexGetTarget.isInstanceMember); - node.indexGetTarget = indexGetTarget.classMember as Procedure; - node.indexGetType = indexGetTarget + Procedure indexGetProcedure = indexGetTarget.classMember as Procedure; + FunctionType indexGetType = indexGetTarget .getFunctionType(this) .indexGetFunctionType; @@ -15849,12 +15949,13 @@ class InferenceVisitorImpl extends InferenceVisitorBase ]), ); + List entries = new List.filled( + node.entries.length, + dummyMapPatternEntry, + growable: true, + ); for (int i = node.entries.length - 1; i >= 0; i--) { - Object? rewrite = popRewrite(); - if (!identical(node.entries[i], rewrite)) { - // Coverage-ignore-block(suite): Not run. - node.entries[i] = (rewrite as MapPatternEntry)..parent = node; - } + entries[i] = popRewrite() as MapPatternEntry; } Map? restPatternErrors = @@ -15862,61 +15963,67 @@ class InferenceVisitorImpl extends InferenceVisitorBase if (restPatternErrors != null) { InvalidExpression? firstError; int insertionIndex = 0; - for (int readIndex = 0; readIndex < node.entries.length; readIndex++) { + for (int readIndex = 0; readIndex < entries.length; readIndex++) { InvalidExpression? error = restPatternErrors[readIndex]; if (error != null) { firstError ??= error; } else { - node.entries[insertionIndex++] = node.entries[readIndex]; + entries[insertionIndex++] = entries[readIndex]; } } - node.entries.length = insertionIndex; + entries.length = insertionIndex; if (insertionIndex == 0) { - replacement ??= new InvalidPattern( - firstError!, - declaredVariables: node.declaredVariables, - )..fileOffset = node.fileOffset; + replacement ??= extern.createInvalidPattern( + error: firstError!, + declaredVariables: node.internalDeclaredVariables, + fileOffset: node.fileOffset, + ); } } - pushRewrite(replacement ?? node); + pushRewrite( + replacement ?? + extern.createMapPattern( + keyType: node.keyType, + valueType: node.valueType, + entries: entries, + requiredType: requiredType, + matchedValueType: matchedValueType, + needsCheck: needsCheck, + lookupType: lookupType, + containsKeyTarget: containsKeyProcedure, + containsKeyType: containsKeyType, + indexGetTarget: indexGetProcedure, + indexGetType: indexGetType, + fileOffset: node.fileOffset, + ), + ); assert(checkStack(node, stackBase, [/* pattern = */ ValueKinds.Pattern])); return analysisResult; } - @override - PatternResult visitNamedPattern( - NamedPattern node, - SharedMatchContext context, - ) { - // NamedPattern isn't a real pattern; this code should never be reached. - throw new StateError('visitNamedPattern should never be reached'); - } - - @override - PatternResult visitRecordPattern( - RecordPattern node, + PatternResult visitInternalRecordPattern( + InternalRecordPattern node, SharedMatchContext context, ) { int? stackBase; assert(checkStackBase(node, stackBase = stackHeight)); List> fields = [ - for (Pattern fieldPattern in node.patterns) + for (InternalPattern fieldPattern in node.patterns) new RecordPatternField( node: fieldPattern, - pattern: fieldPattern is NamedPattern + pattern: fieldPattern is InternalNamedPattern ? fieldPattern.pattern : fieldPattern, - name: fieldPattern is NamedPattern ? fieldPattern.name : null, + name: fieldPattern is InternalNamedPattern ? fieldPattern.name : null, ), ]; RecordPatternResult analysisResult = analyzeRecordPattern(context, node, fields: fields); - DartType matchedValueType = node.matchedValueType = analysisResult - .matchedValueType + DartType matchedValueType = analysisResult.matchedValueType .unwrapTypeView(); assert( @@ -15934,50 +16041,62 @@ class InferenceVisitorImpl extends InferenceVisitorBase analysisResult.patternTypeMismatchInIrrefutableContextError ?? analysisResult.duplicateRecordPatternFieldErrors?.values.first; if (error != null) { - replacement = new InvalidPattern( - error, - declaredVariables: node.declaredVariables, - )..fileOffset = error.fileOffset; + replacement = extern.createInvalidPattern( + error: error, + declaredVariables: node.internalDeclaredVariables, + ); } - RecordType requiredType = node.requiredType = - analysisResult.requiredType as RecordType; + RecordType requiredType = analysisResult.requiredType as RecordType; // TODO(johnniwinther): How does `recordType` relate to `node.recordType`? - node.needsCheck = _needsCheck( + bool needsCheck = _needsCheck( matchedType: matchedValueType, requiredType: requiredType, ); - if (node.needsCheck) { - node.lookupType = requiredType; + RecordType lookupType; + if (needsCheck) { + lookupType = requiredType; } else { DartType resolvedType = matchedValueType.nonTypeParameterBound; if (resolvedType is RecordType) { - node.lookupType = resolvedType; + lookupType = resolvedType; } else { - // Coverage-ignore-block(suite): Not run. // In case of the matched type being an invalid type we use the // required type instead. - node.lookupType = requiredType; + lookupType = requiredType; } } + List patterns = new List.filled( + node.patterns.length, + dummyPattern, + ); for (int i = node.patterns.length - 1; i >= 0; i--) { - Pattern subPattern = node.patterns[i]; + InternalPattern subPattern = node.patterns[i]; Object? rewrite = popRewrite(); - if (subPattern is NamedPattern) { - if (!identical(rewrite, subPattern.pattern)) { - // Coverage-ignore-block(suite): Not run. - subPattern.pattern = (rewrite as Pattern)..parent = subPattern; - } + if (subPattern is InternalNamedPattern) { + patterns[i] = extern.createNamedPattern( + name: subPattern.name, + pattern: rewrite as Pattern, + fileOffset: subPattern.fileOffset, + ); } else { - if (!identical(rewrite, subPattern)) { - node.patterns[i] = (rewrite as Pattern)..parent = node; - } + patterns[i] = rewrite as Pattern; } } - pushRewrite(replacement ?? node); + pushRewrite( + replacement ?? + extern.createRecordPattern( + patterns: patterns, + requiredType: requiredType, + matchedValueType: matchedValueType, + needsCheck: needsCheck, + lookupType: lookupType, + fileOffset: node.fileOffset, + ), + ); assert(checkStack(node, stackBase, [/* pattern = */ ValueKinds.Pattern])); return analysisResult; @@ -16027,9 +16146,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase ); } - @override - PatternResult visitAssignedVariablePattern( - AssignedVariablePattern node, + PatternResult visitInternalAssignedVariablePattern( + InternalAssignedVariablePattern node, SharedMatchContext context, ) { int? stackBase; @@ -16037,7 +16155,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase // TODO(johnniwinther): Share this through the type analyzer. Pattern? replacement; - InternalVariable variable = node.variable as InternalVariable; + InternalVariable variable = node.variable; bool isDefinitelyAssigned = flowAnalysis.isAssigned(variable.astVariable); bool isDefinitelyUnassigned = flowAnalysis.isUnassigned( variable.astVariable, @@ -16045,75 +16163,87 @@ class InferenceVisitorImpl extends InferenceVisitorBase if ((variable.isLate && variable.isFinal) || variable.isLateFinalWithoutInitializer) { if (isDefinitelyAssigned) { - replacement = new InvalidPattern( - problemReporting.buildProblem( + replacement = extern.createInvalidPattern( + error: problemReporting.buildProblem( compilerContext: compilerContext, message: diag.lateDefinitelyAssignedError.withArguments( - variableName: node.variable.name!, + variableName: node.variableName, ), fileUri: fileUri, fileOffset: node.fileOffset, - length: node.variable.name!.length, + length: node.variableName.length, ), - declaredVariables: node.declaredVariables, - )..fileOffset = node.fileOffset; + declaredVariables: node.internalDeclaredVariables, + ); } } else if (variable.isStaticLate) { if (!isDefinitelyUnassigned) { - replacement = new InvalidPattern( - problemReporting.buildProblem( + replacement = extern.createInvalidPattern( + error: problemReporting.buildProblem( compilerContext: compilerContext, message: diag.finalPossiblyAssignedError.withArguments( - variableName: node.variable.name!, + variableName: node.variableName, ), fileUri: fileUri, fileOffset: node.fileOffset, - length: node.variable.name!.length, + length: node.variableName.length, ), - declaredVariables: node.declaredVariables, - )..fileOffset = node.fileOffset; + declaredVariables: node.internalDeclaredVariables, + ); } } else if (variable.isFinal && // Coverage-ignore(suite): Not run. variable.hasDeclaredInitializer) { // Coverage-ignore-block(suite): Not run. - replacement = new InvalidPattern( - problemReporting.buildProblem( + replacement = extern.createInvalidPattern( + error: problemReporting.buildProblem( compilerContext: compilerContext, message: diag.cannotAssignToFinalVariable.withArguments( - variableName: node.variable.name!, + variableName: node.variableName, ), fileUri: fileUri, fileOffset: node.fileOffset, - length: node.variable.name!.length, + length: node.variableName.length, ), - declaredVariables: node.declaredVariables, - )..fileOffset = node.fileOffset; + declaredVariables: node.internalDeclaredVariables, + ); } AssignedVariablePatternResult analysisResult = - analyzeAssignedVariablePattern(context, node, node.variable); + analyzeAssignedVariablePattern( + context, + node, + node.variable.astVariable, + ); - DartType matchedValueType = node.matchedValueType = analysisResult - .matchedValueType + DartType matchedValueType = analysisResult.matchedValueType .unwrapTypeView(); - node.needsCast = _needsCast( + bool needsCast = _needsCast( matchedType: matchedValueType, requiredType: node.variable.type, ); - node.hasObservableEffect = _inTryOrLocalFunction; + bool hasObservableEffect = _inTryOrLocalFunction; InvalidExpression? error = analysisResult.duplicateAssignmentPatternVariableError ?? analysisResult.patternTypeMismatchInIrrefutableContextError; if (error != null) { - replacement ??= new InvalidPattern( - error, - declaredVariables: node.declaredVariables, - )..fileOffset = error.fileOffset; + replacement ??= extern.createInvalidPattern( + error: error, + declaredVariables: node.internalDeclaredVariables, + ); } - pushRewrite(replacement ?? node); + pushRewrite( + replacement ?? + extern.createAssignedVariablePattern( + variable: node.variable.astVariable, + matchedValueType: matchedValueType, + needsCast: needsCast, + hasObservableEffect: hasObservableEffect, + fileOffset: node.fileOffset, + ), + ); assert(checkStack(node, stackBase, [/* pattern = */ ValueKinds.Pattern])); return analysisResult; @@ -16160,7 +16290,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase @override SharedTypeView downwardInferObjectPatternRequiredType({ required SharedTypeView matchedType, - required covariant ObjectPatternInternal pattern, + required covariant InternalObjectPattern pattern, }) { DartType requiredType = pattern.requiredType; if (!pattern.hasExplicitTypeArguments) { @@ -16339,22 +16469,23 @@ class InferenceVisitorImpl extends InferenceVisitorBase @override bool isRestPatternElement(Node node) { - return node is RestPattern || node is MapPatternRestEntry; + return node is InternalRestPattern || node is InternalMapPatternRestEntry; } @override Pattern? getRestPatternElementPattern(TreeNode node) { - if (node is MapPatternRestEntry) { + if (node is InternalMapPatternRestEntry) { return null; } else { - return (node as RestPattern).subPattern; + return (node as InternalRestPattern).subPattern; } } @override void handleListPatternRestElement(Pattern container, TreeNode restElement) { - RestPattern restPattern = restElement as RestPattern; + InternalRestPattern restPattern = restElement as InternalRestPattern; int? stackBase; + Pattern? subPattern; if (restPattern.subPattern != null) { assert(checkStackBase(restPattern, stackBase = stackHeight - 1)); @@ -16364,18 +16495,19 @@ class InferenceVisitorImpl extends InferenceVisitorBase ]), ); - Object? rewrite = popRewrite(); - if (!identical(rewrite, restPattern.subPattern)) { - // Coverage-ignore-block(suite): Not run. - restPattern.subPattern = (rewrite as Pattern)..parent = restPattern; - } + subPattern = popRewrite() as Pattern; } else { assert(checkStackBase(restPattern, stackBase = stackHeight)); } assert(checkStack(restPattern, stackBase, [/*empty*/])); - pushRewrite(restElement); + pushRewrite( + extern.createRestPattern( + subPattern: subPattern, + fileOffset: restPattern.fileOffset, + ), + ); assert( checkStack(restPattern, stackBase, [ @@ -16386,15 +16518,17 @@ class InferenceVisitorImpl extends InferenceVisitorBase @override void handleMapPatternRestElement(Pattern container, TreeNode restElement) { - pushRewrite(restElement); + pushRewrite( + extern.createMapPatternRestEntry(fileOffset: container.fileOffset), + ); } @override shared.MapPatternEntry? getMapPatternEntry( TreeNode element, ) { - element as MapPatternEntry; - if (element is MapPatternRestEntry) { + element as InternalMapPatternEntry; + if (element is InternalMapPatternRestEntry) { return null; } else { return new shared.MapPatternEntry( @@ -16407,32 +16541,33 @@ class InferenceVisitorImpl extends InferenceVisitorBase @override void handleMapPatternEntry( Pattern container, - covariant MapPatternEntry entryElement, + covariant InternalMapPatternEntry entryElement, SharedTypeView keyType, ) { + Pattern value = popRewrite() as Pattern; + Expression key = entryElement.key; Object? rewrite = popRewrite(); - if (!identical(rewrite, entryElement.value)) { - // Coverage-ignore-block(suite): Not run. - entryElement.value = rewrite as Pattern..parent = entryElement; - } - - rewrite = popRewrite(); if (!identical(rewrite, entryElement.key)) { - entryElement.key = (rewrite as Expression)..parent = entryElement; + key = rewrite as Expression; } - entryElement.keyType = keyType.unwrapTypeView(); - - pushRewrite(entryElement); + pushRewrite( + extern.createMapPatternEntry( + key: key, + keyType: keyType.unwrapTypeView(), + value: value, + fileOffset: entryElement.fileOffset, + ), + ); } @override RelationalOperatorResolution? resolveRelationalPatternOperator( - covariant RelationalPattern node, + covariant InternalRelationalPattern node, SharedTypeView matchedValueType, ) { // TODO(johnniwinther): Reuse computed values between here and - // visitRelationalPattern. + // visitInternalRelationalPattern. Name operatorName; RelationalOperatorKind kind = RelationalOperatorKind.other; switch (node.kind) { @@ -16496,15 +16631,6 @@ class InferenceVisitorImpl extends InferenceVisitorBase return _unhandledInitializer(node); } - @override - // Coverage-ignore(suite): Not run. - PatternResult visitAuxiliaryPattern( - AuxiliaryPattern node, - SharedMatchContext context, - ) { - return _unhandledPattern(node); - } - @override // Coverage-ignore(suite): Not run. StatementInferenceResult visitAuxiliaryStatement(AuxiliaryStatement node) { diff --git a/pkg/front_end/lib/src/type_inference/shared_type_analyzer.dart b/pkg/front_end/lib/src/type_inference/shared_type_analyzer.dart index 0b36de6e755..8c02ab93251 100644 --- a/pkg/front_end/lib/src/type_inference/shared_type_analyzer.dart +++ b/pkg/front_end/lib/src/type_inference/shared_type_analyzer.dart @@ -11,6 +11,7 @@ import 'package:kernel/core_types.dart'; import '../base/compiler_context.dart'; import '../base/messages.dart'; +import '../kernel/internal_ast.dart'; import '../source/check_helper.dart'; import 'inference_visitor.dart'; @@ -249,7 +250,7 @@ class SharedTypeAnalyzerErrors @override InvalidExpression relationalPatternOperandTypeNotAssignable({ - required covariant RelationalPattern pattern, + required covariant InternalRelationalPattern pattern, required SharedTypeView operandType, required SharedTypeView parameterType, }) {