[cfe][InternalNodes] Separate Variable from InternalVariable

This adds an InternalLegacyVariable the doesn't derive from LegacyVariable. This fully separates InternalVariable from Variable and assigned variable tracking and flow analysis is now changed to used InternalVariable instead.

TEST=existing

Change-Id: Ida9dc78d4f0e3fab3baf7a965273e1ddf68a80b8
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/510341
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Johnni Winther
2026-06-11 02:43:16 -07:00
committed by dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent 680f6e24d7
commit c390eb0931
39 changed files with 1518 additions and 526 deletions
@@ -91,6 +91,7 @@ import '../dill/dill_loader.dart' show DillLoader;
import '../dill/dill_target.dart' show DillTarget;
import '../kernel/benchmarker.dart' show BenchmarkPhases, Benchmarker;
import '../kernel/dart_scope_calculator.dart' show DartScope, DartScopeBuilder2;
import '../kernel/external_ast_helper.dart' as extern;
import '../kernel/hierarchy/hierarchy_builder.dart' show ClassHierarchyBuilder;
import '../kernel/internal_ast.dart'
show InternalVariableGet, InternalVariableSet, InternalVariable;
@@ -2228,7 +2229,7 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
MemoryFileSystem fs = hfs.memory;
fs.entityForUri(debugExprUri).writeAsStringSync(expression);
InternalVariable? extensionThis;
Variable? extensionThis;
// TODO: pass variable declarations instead of
// parameter names for proper location detection.
@@ -2239,13 +2240,18 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
positionalParameters: usedDefinitions.entries.map<Variable>((
MapEntry<String, DartType> def,
) {
InternalVariable variable = intern.createPositionalParameter(
isClosureContextLoweringEnabled:
lastGoodKernelTarget.loader.isClosureContextLoweringEnabled,
cosmeticName: def.key,
type: def.value,
fileOffset: offsetToUse ?? libraryBuilder.library.fileOffset,
);
Variable variable =
lastGoodKernelTarget.loader.isClosureContextLoweringEnabled
? extern.createPositionalParameter(
cosmeticName: def.key,
type: def.value,
fileOffset: offsetToUse ?? libraryBuilder.library.fileOffset,
)
: extern.createLegacyVariable(
name: def.key,
type: def.value,
fileOffset: offsetToUse ?? libraryBuilder.library.fileOffset,
);
if (isExtensionOrExtensionTypeInstanceMember &&
isExtensionThisName(def.key) &&
@@ -2253,7 +2259,7 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
// The `#this` variable is special.
extensionThis = variable..isLowered = true;
}
return variable.astVariable;
return variable;
}).toList(),
);
@@ -422,7 +422,7 @@ class FormalParameterBuilder extends NamedBuilderImpl
declaredType: variable.type,
hasDeclaredInitializer: hasDeclaredInitializer,
);
variable.initializer = initializer..parent = variable;
variable.initializer = initializer..parent = variable.astVariable;
if (initializer is InvalidExpression) {
variable.isErroneouslyInitialized = true;
}
@@ -430,7 +430,7 @@ class FormalParameterBuilder extends NamedBuilderImpl
} else if (kind.isOptional) {
// As done by BodyBuilder.endFormalParameter.
variable.initializer = extern.createNullLiteral(fileOffset: fileOffset)
..parent = variable;
..parent = variable.astVariable;
}
}
}
@@ -24,6 +24,7 @@ import '../../kernel/body_builder_context.dart';
import '../../kernel/hierarchy/class_member.dart';
import '../../kernel/hierarchy/members_builder.dart';
import '../../kernel/implicit_field_type.dart';
import '../../kernel/internal_ast.dart';
import '../../kernel/late_lowering.dart' as late_lowering;
import '../../kernel/macro/metadata.dart';
import '../../kernel/type_algorithms.dart';
@@ -947,7 +948,7 @@ abstract class FieldFragmentDeclaration {
required CoreTypes coreTypes,
required Uri fileUri,
Expression? initializer,
required ThisVariable? internalThisVariable,
required InternalThisVariable? internalThisVariable,
});
BodyBuilderContext createBodyBuilderContext();
@@ -1003,7 +1004,7 @@ mixin FieldFragmentDeclarationMixin implements FieldFragmentDeclaration {
required CoreTypes coreTypes,
required Uri fileUri,
Expression? initializer,
required ThisVariable? internalThisVariable,
required InternalThisVariable? internalThisVariable,
}) {
if (_fieldInitializerCache != null) {
if (!hasBodyBeenBuilt) {
@@ -6,10 +6,13 @@ import 'package:_fe_analyzer_shared/src/type_inference/assigned_variables.dart';
import 'package:_fe_analyzer_shared/src/type_inference/promotion_key_store.dart';
import 'package:kernel/ast.dart';
class AssignedVariablesImpl implements AssignedVariables<TreeNode, Variable> {
final AssignedVariables<TreeNode, Variable> _delegate;
final AssignedVariables<TreeNode, Variable>? _insideAsserts;
final AssignedVariables<TreeNode, Variable>? _outsideAsserts;
import 'internal_ast.dart';
class AssignedVariablesImpl
implements AssignedVariables<TreeNode, InternalVariable> {
final AssignedVariables<TreeNode, InternalVariable> _delegate;
final AssignedVariables<TreeNode, InternalVariable>? _insideAsserts;
final AssignedVariables<TreeNode, InternalVariable>? _outsideAsserts;
int _assertDepth = 0;
final Map<AssignedVariablesNodeInfo, AssignedVariablesNodeInfo>?
_deferredInsideAssertsByDeferredDelegate;
@@ -18,10 +21,10 @@ class AssignedVariablesImpl implements AssignedVariables<TreeNode, Variable> {
new(this._delegate, {required bool isClosureContextLoweringEnabled})
: _insideAsserts = isClosureContextLoweringEnabled
? new AssignedVariables<TreeNode, Variable>()
? new AssignedVariables<TreeNode, InternalVariable>()
: null,
_outsideAsserts = isClosureContextLoweringEnabled
? new AssignedVariables<TreeNode, Variable>()
? new AssignedVariables<TreeNode, InternalVariable>()
: null,
_deferredInsideAssertsByDeferredDelegate = isClosureContextLoweringEnabled
? new Map<
@@ -68,7 +71,7 @@ class AssignedVariablesImpl implements AssignedVariables<TreeNode, Variable> {
}
@override
void declare(Variable variable, {bool ignoreDuplicates = false}) {
void declare(InternalVariable variable, {bool ignoreDuplicates = false}) {
_delegate.declare(variable, ignoreDuplicates: ignoreDuplicates);
_insideAsserts?.declare(variable, ignoreDuplicates: ignoreDuplicates);
_outsideAsserts?.declare(variable, ignoreDuplicates: ignoreDuplicates);
@@ -149,7 +152,7 @@ class AssignedVariablesImpl implements AssignedVariables<TreeNode, Variable> {
}
@override
PromotionKeyStore<Variable> get promotionKeyStore {
PromotionKeyStore<InternalVariable> get promotionKeyStore {
return _delegate.promotionKeyStore;
}
@@ -161,7 +164,7 @@ class AssignedVariablesImpl implements AssignedVariables<TreeNode, Variable> {
}
@override
void read(Variable variable) {
void read(InternalVariable variable) {
_delegate.read(variable);
if (_isInsideAssert) {
_insideAsserts?.read(variable);
@@ -199,7 +202,7 @@ class AssignedVariablesImpl implements AssignedVariables<TreeNode, Variable> {
}
@override
void write(Variable variable) {
void write(InternalVariable variable) {
_delegate.write(variable);
if (_isInsideAssert) {
// Coverage-ignore-block(suite): Not run.
+18 -24
View File
@@ -337,7 +337,7 @@ class BodyBuilderImpl extends StackListenerImpl
/// If the current member is an instance member of a non-extension
/// declaration, and the closure context lowering experiment is enabled, this
/// field contains the variable representing `this`.
ThisVariable? _internalThisVariable;
InternalThisVariable? _internalThisVariable;
final List<TypeParameter>? thisTypeParameters;
@@ -370,7 +370,7 @@ class BodyBuilderImpl extends StackListenerImpl
required this.typeEnvironment,
required ConstantContext constantContext,
required this.extensionScope,
required ThisVariable? internalThisVariable,
required InternalThisVariable? internalThisVariable,
}) : _context = context,
benchmarker = libraryBuilder.loader.target.benchmarker,
_localScopes = new LocalStack([enclosingScope]),
@@ -380,13 +380,13 @@ class BodyBuilderImpl extends StackListenerImpl
this.constantContext = constantContext;
if (formalParameterScope != null) {
for (VariableBuilder builder in formalParameterScope!.localVariables) {
assignedVariables.declare(builder.variable.astVariable);
assignedVariables.declare(builder.variable);
}
}
if (thisVariable != null && context.isConstructor) {
// The this variable is not part of the [formalParameterScope] in
// constructors.
assignedVariables.declare(thisVariable.astVariable);
assignedVariables.declare(thisVariable);
}
if (isClosureContextLoweringEnabled && _internalThisVariable != null) {
assignedVariables.declare(_internalThisVariable!);
@@ -623,7 +623,7 @@ class BodyBuilderImpl extends StackListenerImpl
// when [InferenceVisitorBase.flowAnalysis] will use
// [InternalExpressionVariable] instead of [ExpressionVariable] (that is,
// pass it for the `VariableDeclaration` type parameter of [FlowAnalysis]).
assignedVariables.write(variable.astVariable);
assignedVariables.write(variable);
}
@override
@@ -632,7 +632,7 @@ class BodyBuilderImpl extends StackListenerImpl
expression,
isClosureContextLoweringEnabled: isClosureContextLoweringEnabled,
);
assignedVariables.declare(variable.astVariable);
assignedVariables.declare(variable);
return variable;
}
@@ -1990,7 +1990,7 @@ class BodyBuilderImpl extends StackListenerImpl
];
for (InternalVariable variable in jointVariables) {
declareVariable(variable, _localScope);
assignedVariables.declare(variable.astVariable);
assignedVariables.declare(variable);
}
push(
intern.createOrPattern(
@@ -2495,7 +2495,7 @@ class BodyBuilderImpl extends StackListenerImpl
@override
void registerVariableRead(InternalVariable variable) {
if (!variable.isLocalFunction && !variable.isWildcard) {
assignedVariables.read(variable.astVariable);
assignedVariables.read(variable);
}
}
@@ -3424,7 +3424,7 @@ class BodyBuilderImpl extends StackListenerImpl
internalVariable,
fileOffset: offsetForToken(equalsToken),
);
assignedVariables.declare(internalVariable.astVariable);
assignedVariables.declare(internalVariable);
push(variableDeclaration);
}
@@ -3441,7 +3441,7 @@ class BodyBuilderImpl extends StackListenerImpl
if (parameters != null) {
Map<String, VariableBuilder> local = {};
for (FormalParameterBuilder formal in parameters) {
assignedVariables.declare(formal.variable.astVariable);
assignedVariables.declare(formal.variable);
local[formal.name] = formal;
}
_localScopes.push(
@@ -3869,7 +3869,7 @@ class BodyBuilderImpl extends StackListenerImpl
internalVariables.add(internalVariable);
declareVariable(internalVariable, _localScope);
assignedVariables.declare(internalVariable.astVariable);
assignedVariables.declare(internalVariable);
}
push(intermediateVariables);
push(internalVariables);
@@ -5550,10 +5550,7 @@ class BodyBuilderImpl extends StackListenerImpl
// previously passed to `declare` in the `BodyBuilder` constructor.
// TODO(62401): Remove the cast when the flow analysis uses
// [InternalExpressionVariable]s.
assignedVariables.declare(
functionParameter.astVariable,
ignoreDuplicates: true,
);
assignedVariables.declare(functionParameter, ignoreDuplicates: true);
}
@override
@@ -8071,7 +8068,7 @@ class BodyBuilderImpl extends StackListenerImpl
_thisVariables.push(variable);
_parameterlessAnonymousMethodDepth++;
assignedVariables.declare(variable.astVariable);
assignedVariables.declare(variable);
push(NullValues.FormalParameters);
}
@@ -9032,7 +9029,7 @@ class BodyBuilderImpl extends StackListenerImpl
for (InternalVariable jointVariable in jointPatternVariables) {
assert(_localScope.kind == LocalScopeKind.jointVariables);
declareVariable(jointVariable, _localScope);
assignedVariables.declare(jointVariable.astVariable);
assignedVariables.declare(jointVariable);
}
}
}
@@ -11104,7 +11101,7 @@ class BodyBuilderImpl extends StackListenerImpl
declaredVariable,
);
declareVariable(declaredVariable, _localScope);
assignedVariables.declare(declaredVariable.astVariable);
assignedVariables.declare(declaredVariable);
}
push(pattern);
}
@@ -11496,10 +11493,7 @@ class BodyBuilderImpl extends StackListenerImpl
for (FormalParameterBuilder formal in formals) {
// We pass `ignoreDuplicates: true` because the variable might have been
// previously passed to `declare` in the `BodyBuilder` constructor.
assignedVariables.declare(
formal.variable.astVariable,
ignoreDuplicates: true,
);
assignedVariables.declare(formal.variable, ignoreDuplicates: true);
}
}
token = parser.parseInitializersOpt(token);
@@ -11648,7 +11642,7 @@ class BodyBuilderImpl extends StackListenerImpl
if (formals != null) {
for (FormalParameterBuilder formalParameterBuilder in formals) {
assignedVariables.declare(formalParameterBuilder.variable.astVariable);
assignedVariables.declare(formalParameterBuilder.variable);
}
}
@@ -11674,7 +11668,7 @@ class BodyBuilderImpl extends StackListenerImpl
enterLocalScope(extraKnownVariablesScope);
for (InternalVariable extraVariable in extraKnownVariables) {
declareVariable(extraVariable, _localScope);
assignedVariables.declare(extraVariable.astVariable);
assignedVariables.declare(extraVariable);
}
}
@@ -401,7 +401,7 @@ abstract class BodyBuilderContext {
/// Declarations with synthesized `this`, such as extensions and extension
/// types, don't have an internal [ThisVariable] because `this` is desugared
/// as a parameter in that case.
ThisVariable? createInternalThisVariable() {
InternalThisVariable? createInternalThisVariable() {
return thisType != null && isDeclarationInstanceContext
? intern.createThisVariable(
type: thisType!,
@@ -109,12 +109,14 @@ AssertStatement createAssertStatement(
AssignedVariablePattern createAssignedVariablePattern({
required Variable variable,
required Variable? setter,
required DartType matchedValueType,
required bool needsCast,
required bool hasObservableEffect,
required int fileOffset,
}) {
return new AssignedVariablePattern(variable)
..setter = setter
..matchedValueType = matchedValueType
..needsCast = needsCast
..hasObservableEffect = hasObservableEffect
@@ -601,6 +603,44 @@ LateVariable createLateVariable({
)..fileOffset = fileOffset;
}
LegacyVariable createLegacyVariable({
required String? name,
required DartType type,
bool isFinal = false,
bool isConst = false,
bool isWildcard = false,
bool isLate = false,
bool isInitializingFormal = false,
bool isSuperInitializingFormal = false,
bool isCovariantByDeclaration = false,
bool isRequired = false,
bool isLowered = false,
bool isSynthesized = false,
required int fileOffset,
int fileEqualsOffset = TreeNode.noOffset,
Expression? initializer,
bool hasDeclaredInitializer = false,
}) {
return new LegacyVariable(
name,
type: type,
isFinal: isFinal,
isConst: isConst,
isLate: isLate,
isWildcard: isWildcard,
isInitializingFormal: isInitializingFormal,
isSuperInitializingFormal: isSuperInitializingFormal,
isCovariantByDeclaration: isCovariantByDeclaration,
isRequired: isRequired,
isLowered: isLowered,
isSynthesized: isSynthesized,
initializer: initializer,
hasDeclaredInitializer: hasDeclaredInitializer,
)
..fileOffset = fileOffset
..fileEqualsOffset = fileEqualsOffset;
}
/// 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, {int? fileOffset}) {
@@ -1326,9 +1366,10 @@ Expression createVariableSet(
bool allowFinalAssignment = false,
required int fileOffset,
}) {
if (variable is VariableDeclarationImpl && variable.lateSetter != null) {
// TODO(johnniwinther):
if (variable.parent is FunctionDeclaration) {
return createLocalFunctionInvocation(
variable.lateSetter!,
variable,
arguments: createArguments([value], fileOffset: fileOffset),
fileOffset: fileOffset,
);
+73 -79
View File
@@ -21,7 +21,6 @@ library;
import 'package:_fe_analyzer_shared/src/type_inference/type_analysis_result.dart'
as shared;
import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/names.dart';
import 'package:kernel/src/printer.dart';
@@ -41,7 +40,12 @@ import 'external_ast_helper.dart' as extern;
/// @docImport 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart';
typedef SharedMatchContext =
shared.MatchContext<TreeNode, Expression, InternalPattern, Variable>;
shared.MatchContext<
TreeNode,
Expression,
InternalPattern,
InternalVariable
>;
mixin InternalTreeNode implements TreeNode {
@override
@@ -1150,11 +1154,11 @@ class ReturnStatementImpl extends ReturnStatement {
}
/// Front end specific implementation of [Variable].
class VariableDeclarationImpl extends LegacyVariable
with InternalVariableMixin
implements InternalVariable {
class InternalLegacyVariable extends TreeNode
with InternalVariableMixin, DelegatingVariableMixin
implements LegacyVariable, InternalVariable {
@override
Variable get astVariable => this;
final Variable astVariable;
@override
final bool forSyntheticToken;
@@ -1165,69 +1169,22 @@ class VariableDeclarationImpl extends LegacyVariable
@override
final bool isLocalFunction;
new(
String? name, {
new({
required this.astVariable,
this.forSyntheticToken = false,
bool hasDeclaredInitializer = false,
Expression? initializer,
DartType? type,
bool isFinal = false,
bool isConst = false,
bool isInitializingFormal = false,
bool isSuperInitializingFormal = false,
bool isCovariantByDeclaration = false,
this.isImplicitlyTyped = false,
bool isLocalFunction = false,
bool isLate = false,
bool isRequired = false,
bool isLowered = false,
bool isSynthesized = false,
bool isStaticLate = false,
bool isWildcard = false,
bool isLateFinalWithoutInitializer = false,
required int fileOffset,
int fileEqualsOffset = TreeNode.noOffset,
}) : isImplicitlyTyped = type == null,
isLocalFunction = isLocalFunction,
super(
name,
initializer: initializer,
type: type ?? const DynamicType(),
isFinal: isFinal,
isConst: isConst,
isInitializingFormal: isInitializingFormal,
isSuperInitializingFormal: isSuperInitializingFormal,
isCovariantByDeclaration: isCovariantByDeclaration,
isLate: isLate,
isRequired: isRequired,
isLowered: isLowered,
isSynthesized: isSynthesized,
hasDeclaredInitializer: hasDeclaredInitializer,
isWildcard: isWildcard,
) {
}) : isLocalFunction = isLocalFunction {
this.isStaticLate = isStaticLate;
this.isLateFinalWithoutInitializer = isLateFinalWithoutInitializer;
this.fileOffset = fileOffset;
this.fileEqualsOffset = fileEqualsOffset;
}
// Coverage-ignore(suite): Not run.
new forEffect(Expression initializer)
: forSyntheticToken = false,
isImplicitlyTyped = false,
isLocalFunction = false,
super.forValue(initializer) {
isStaticLate = false;
}
// Coverage-ignore(suite): Not run.
new forValue(Expression initializer)
: forSyntheticToken = false,
isImplicitlyTyped = true,
isLocalFunction = false,
super.forValue(initializer) {
isStaticLate = false;
}
@override
bool get isAssignable {
if (isStaticLate) return true;
@@ -1240,13 +1197,14 @@ class VariableDeclarationImpl extends LegacyVariable
printer.writeVariableInitialization(
this,
isLate: isLate || lateGetter != null,
isImplicitlyTyped: isImplicitlyTyped,
type: lateType ?? type,
);
}
@override
String toString() {
return "VariableDeclarationImpl(${toStringInternal()})";
return "$runtimeType(${toStringInternal()})";
}
}
@@ -1775,7 +1733,6 @@ mixin DelegatingVariableMixin on InternalVariableMixin
String? get cosmeticName => astVariable.cosmeticName;
@override
// Coverage-ignore(suite): Not run.
TreeNode? get parent => astVariable.parent;
@override
@@ -1793,13 +1750,11 @@ mixin DelegatingVariableMixin on InternalVariableMixin
}
@override
// Coverage-ignore(suite): Not run.
void addAnnotation(Expression node) {
astVariable.addAnnotation(node);
}
@override
// Coverage-ignore(suite): Not run.
void set cosmeticName(String? value) {
astVariable.cosmeticName = value;
}
@@ -1824,7 +1779,6 @@ mixin DelegatingVariableMixin on InternalVariableMixin
bool get isConst => astVariable.isConst;
@override
// Coverage-ignore(suite): Not run.
void set isConst(bool value) {
astVariable.isConst = value;
}
@@ -1850,11 +1804,9 @@ mixin DelegatingVariableMixin on InternalVariableMixin
}
@override
// Coverage-ignore(suite): Not run.
bool get isErroneouslyInitialized => astVariable.isErroneouslyInitialized;
@override
// Coverage-ignore(suite): Not run.
void set isErroneouslyInitialized(bool value) {
astVariable.isErroneouslyInitialized = value;
}
@@ -1863,7 +1815,6 @@ mixin DelegatingVariableMixin on InternalVariableMixin
bool get isFinal => astVariable.isFinal;
@override
// Coverage-ignore(suite): Not run.
void set isFinal(bool value) {
astVariable.isFinal = value;
}
@@ -1901,7 +1852,6 @@ mixin DelegatingVariableMixin on InternalVariableMixin
bool get isLowered => astVariable.isLowered;
@override
// Coverage-ignore(suite): Not run.
void set isLowered(bool value) {
astVariable.isLowered = value;
}
@@ -1926,7 +1876,6 @@ mixin DelegatingVariableMixin on InternalVariableMixin
}
@override
// Coverage-ignore(suite): Not run.
bool get isSynthesized => astVariable.isSynthesized;
@override
@@ -2158,13 +2107,11 @@ mixin DelegatingVariableMixin on InternalVariableMixin
int get fileEqualsOffset => astVariable.fileEqualsOffset;
@override
// Coverage-ignore(suite): Not run.
void set fileEqualsOffset(int value) {
astVariable.fileEqualsOffset = value;
}
@override
// Coverage-ignore(suite): Not run.
Variable get variable => astVariable.variable;
@override
@@ -2174,7 +2121,6 @@ mixin DelegatingVariableMixin on InternalVariableMixin
}
@override
// Coverage-ignore(suite): Not run.
void clearAnnotations() {
astVariable.clearAnnotations();
}
@@ -5938,6 +5884,8 @@ sealed class InternalForInElement {
/// Base implementation for non-pattern for-in elements.
sealed class _BaseForInElement extends InternalForInElement {
InternalVariable? get _declaredVariable => null;
/// Computes the type context from the element. This is type context used for
/// inferring the for-in iterable.
DartType _computeElementTypeContext(InferenceVisitorBase visitor);
@@ -6004,6 +5952,7 @@ sealed class _BaseForInElement extends InternalForInElement {
);
return new ForInHeaderResult(
declaredVariable: _declaredVariable,
loopVariable: variable,
iterable: iterableResult.expression,
computeEncoding: () => _computeEncoding(visitor, loopVariable: variable),
@@ -6028,6 +5977,9 @@ class SingleVariableDeclarationForInElement extends _BaseForInElement {
new({required this.variableDeclaration, required this.error});
@override
InternalVariable get _declaredVariable => variableDeclaration.variable;
@override
Variable _computeLoopVariable(
InferenceVisitorBase visitor,
@@ -6035,6 +5987,7 @@ class SingleVariableDeclarationForInElement extends _BaseForInElement {
required int forOffset,
required bool isClosureContextLoweringEnabled,
}) {
//InternalVariable internalLoopVariable = variableDeclaration.variable;
Variable loopVariable = variableDeclaration.variable.astVariable;
DartType loopVariableType;
bool checkAssignment = true;
@@ -6070,11 +6023,11 @@ class SingleVariableDeclarationForInElement extends _BaseForInElement {
// and assign to the declared variable in the loop.
loopVariable.initializer = assignmentResult.expression
..parent = loopVariable;
visitor.flowAnalysis.declare(
loopVariable,
new SharedTypeView(loopVariableType),
initialized: true,
);
// visitor.flowAnalysis.declare(
// internalLoopVariable,
// new SharedTypeView(loopVariableType),
// initialized: true,
// );
_variableForSideEffect = extern.createVariableDeclaration(loopVariable);
loopVariable = tempVariable;
}
@@ -6267,6 +6220,7 @@ class PatternForInElement extends InternalForInElement {
inOffset: inOffset,
);
return new ForInHeaderResult(
declaredVariable: null,
loopVariable: data.loopVariable,
iterable: data.iterable,
computeEncoding: () => new ForInEncoding(
@@ -6362,7 +6316,7 @@ class ExistingVariableForInElement extends _BaseForInElement {
@override
DartType _computeElementTypeContext(InferenceVisitorBase visitor) {
DartType? promotedType = visitor.flowAnalysis
.promotedType(variable.astVariable)
.promotedType(variable)
?.unwrapTypeView();
return promotedType ?? variable.type;
}
@@ -6668,6 +6622,9 @@ class ForInEncoding {
/// The result of inferring a for-in loop element and iterable.
class ForInHeaderResult {
/// The [InternalVariable] declared in the for-in statement, if any.
final InternalVariable? declaredVariable;
/// The [Variable] that should be used as the variable in the
/// emitted [ForInStatement].
final Variable loopVariable;
@@ -6684,6 +6641,7 @@ class ForInHeaderResult {
final ForInEncoding Function() computeEncoding;
new({
required this.declaredVariable,
required this.loopVariable,
required this.iterable,
required this.computeEncoding,
@@ -8459,6 +8417,43 @@ class InternalLet extends InternalExpression {
}
}
class InternalThisVariable extends TreeNode
with InternalVariableMixin, DelegatingVariableMixin
implements ThisVariable, InternalVariable {
@override
final ThisVariable astVariable;
new({required this.astVariable, required int fileOffset}) {
this.fileOffset = fileOffset;
}
@override
// Coverage-ignore(suite): Not run.
String get cosmeticName => astVariable.cosmeticName;
@override
// Coverage-ignore(suite): Not run.
bool get forSyntheticToken => false;
@override
// Coverage-ignore(suite): Not run.
bool get isImplicitlyTyped => false;
@override
// Coverage-ignore(suite): Not run.
bool get isLocalFunction => false;
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
printer.write('this');
}
@override
String toString() {
return "$runtimeType(${toStringInternal()})";
}
}
final InternalPattern dummyInternalPattern = new InternalConstantPattern(
expression: dummyExpression,
fileOffset: TreeNode.noOffset,
@@ -8495,10 +8490,9 @@ final InternalCatch dummyInternalCatch = new InternalCatch(
fileOffset: TreeNode.noOffset,
);
final InternalVariable dummyInternalVariable = new VariableDeclarationImpl(
null,
final InternalVariable dummyInternalVariable = new InternalLegacyVariable(
astVariable: dummyVariable,
fileOffset: TreeNode.noOffset,
isSynthesized: true,
);
final InternalVariableDeclaration dummyInternalVariableDeclaration =
@@ -211,13 +211,16 @@ InternalVariable createCatchVariable({
fileOffset: fileOffset,
);
} else {
return new VariableDeclarationImpl(
name,
return new InternalLegacyVariable(
astVariable: extern.createLegacyVariable(
name: name,
type: type,
isWildcard: isWildcard,
isFinal: isFinal,
fileOffset: fileOffset,
),
fileOffset: fileOffset,
// [VariableDeclarationImpl] uses `null` to signal an omitted type.
type: isImplicitlyTyped ? null : type,
isWildcard: isWildcard,
isFinal: isFinal,
isImplicitlyTyped: isImplicitlyTyped,
);
}
}
@@ -677,19 +680,24 @@ InternalVariable createLateVariable({
fileOffset: fileOffset,
);
} else {
return new VariableDeclarationImpl(
name,
return new InternalLegacyVariable(
astVariable: extern.createLegacyVariable(
name: name,
fileOffset: fileOffset,
hasDeclaredInitializer: hasDeclaredInitializer,
initializer: initializer,
type: type ?? const DynamicType(),
isFinal: isFinal,
isConst: isConst,
isLate: true,
isWildcard: isWildcard,
fileEqualsOffset: fileEqualsOffset,
),
fileOffset: fileOffset,
forSyntheticToken: forSyntheticToken,
hasDeclaredInitializer: hasDeclaredInitializer,
initializer: initializer,
type: type,
isFinal: isFinal,
isConst: isConst,
isLate: true,
isStaticLate: isStaticLate,
isWildcard: isWildcard,
fileEqualsOffset: fileEqualsOffset,
isImplicitlyTyped: isImplicitlyTyped,
);
}
}
@@ -785,19 +793,24 @@ InternalVariable createLocalVariable({
fileEqualsOffset: fileEqualsOffset,
);
} else {
return new VariableDeclarationImpl(
name,
return new InternalLegacyVariable(
astVariable: extern.createLegacyVariable(
name: name,
fileOffset: fileOffset,
hasDeclaredInitializer: hasDeclaredInitializer,
initializer: initializer,
type: type ?? const DynamicType(),
isFinal: isFinal,
isConst: isConst,
isWildcard: isWildcard,
fileEqualsOffset: fileEqualsOffset,
),
fileOffset: fileOffset,
forSyntheticToken: forSyntheticToken,
hasDeclaredInitializer: hasDeclaredInitializer,
initializer: initializer,
type: type,
isFinal: isFinal,
isConst: isConst,
isLocalFunction: isLocalFunction,
isStaticLate: isStaticLate,
isWildcard: isWildcard,
fileEqualsOffset: fileEqualsOffset,
isImplicitlyTyped: isImplicitlyTyped,
);
}
}
@@ -961,22 +974,25 @@ InternalVariable createNamedParameter({
fileOffset: fileOffset,
);
} else {
return new VariableDeclarationImpl(
parameterName,
return new InternalLegacyVariable(
astVariable: extern.createLegacyVariable(
name: parameterName,
fileOffset: fileOffset,
hasDeclaredInitializer: hasDeclaredDefaultValue,
initializer: defaultValue,
type: type,
isFinal: isFinal,
isInitializingFormal: isInitializingFormal,
isSuperInitializingFormal: isSuperInitializingFormal,
isCovariantByDeclaration: isCovariantByDeclaration,
isRequired: isRequired,
isLowered: isLowered,
isSynthesized: isSynthesized,
isWildcard: isWildcard,
),
fileOffset: fileOffset,
forSyntheticToken: forSyntheticToken,
hasDeclaredInitializer: hasDeclaredDefaultValue,
initializer: defaultValue,
// [VariableDeclarationImpl] uses `null` to signal an omitted type.
type: isImplicitlyTyped ? null : type,
isFinal: isFinal,
isInitializingFormal: isInitializingFormal,
isSuperInitializingFormal: isSuperInitializingFormal,
isCovariantByDeclaration: isCovariantByDeclaration,
isRequired: isRequired,
isLowered: isLowered,
isSynthesized: isSynthesized,
isWildcard: isWildcard,
isImplicitlyTyped: isImplicitlyTyped,
);
}
}
@@ -1232,23 +1248,25 @@ InternalVariable createPositionalParameter({
fileOffset: fileOffset,
);
} else {
return new VariableDeclarationImpl(
cosmeticName,
return new InternalLegacyVariable(
astVariable: extern.createLegacyVariable(
name: cosmeticName,
fileOffset: fileOffset,
hasDeclaredInitializer: hasDeclaredDefaultValue,
initializer: defaultValue,
type: type,
isFinal: isFinal,
isInitializingFormal: isInitializingFormal,
isSuperInitializingFormal: isSuperInitializingFormal,
isCovariantByDeclaration: isCovariantByDeclaration,
isRequired: isRequired,
isLowered: isLowered,
isSynthesized: isSynthesized,
isWildcard: isWildcard,
),
fileOffset: fileOffset,
forSyntheticToken: forSyntheticToken,
hasDeclaredInitializer: hasDeclaredDefaultValue,
initializer: defaultValue,
// [VariableDeclarationImpl] uses `null` to signal an omitted
// type.
type: isImplicitlyTyped ? null : type,
isFinal: isFinal,
isInitializingFormal: isInitializingFormal,
isSuperInitializingFormal: isSuperInitializingFormal,
isCovariantByDeclaration: isCovariantByDeclaration,
isRequired: isRequired,
isLowered: isLowered,
isSynthesized: isSynthesized,
isWildcard: isWildcard,
isImplicitlyTyped: isImplicitlyTyped,
);
}
}
@@ -1524,14 +1542,18 @@ InternalVariable createSyntheticVariable({
fileOffset: fileOffset,
);
} else {
return new VariableDeclarationImpl(
name,
type: type,
initializer: initializer,
isFinal: isFinal,
isSynthesized: isSynthesized,
hasDeclaredInitializer: initializer != null,
return new InternalLegacyVariable(
astVariable: extern.createLegacyVariable(
name: name,
type: type ?? const DynamicType(),
initializer: initializer,
isFinal: isFinal,
isSynthesized: isSynthesized,
hasDeclaredInitializer: initializer != null,
fileOffset: fileOffset,
),
fileOffset: fileOffset,
isImplicitlyTyped: type == null,
);
}
}
@@ -1569,11 +1591,14 @@ Expression createThisExpression({required int fileOffset}) {
return new ThisExpression()..fileOffset = fileOffset;
}
ThisVariable createThisVariable({
InternalThisVariable createThisVariable({
required DartType type,
required int fileOffset,
}) {
return new ThisVariable(type: type)..fileOffset = fileOffset;
return new InternalThisVariable(
astVariable: new ThisVariable(type: type)..fileOffset = fileOffset,
fileOffset: fileOffset,
);
}
/// Return a representation of a throw expression at the given [fileOffset].
+58 -44
View File
@@ -5,7 +5,6 @@
import 'package:_fe_analyzer_shared/src/parser/parser.dart'
show FormalParameterKind;
import 'package:_fe_analyzer_shared/src/scanner/token.dart' show Token;
import 'package:_fe_analyzer_shared/src/type_inference/assigned_variables.dart';
import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
import 'package:front_end/src/codes/diagnostic.dart' as diag;
import 'package:kernel/ast.dart';
@@ -275,7 +274,7 @@ class Resolver {
ConstantContext constantContext = bodyBuilderContext.constantContext;
List<FormalParameterBuilder>? primaryConstructorInitializerScopeParameters =
bodyBuilderContext.primaryConstructorInitializerScopeParameters;
ThisVariable? internalThisVariable = bodyBuilderContext
InternalThisVariable? internalThisVariable = bodyBuilderContext
.createInternalThisVariable();
BodyBuilder bodyBuilder = _createBodyBuilder(
context: context,
@@ -404,7 +403,7 @@ class Resolver {
functionBodyBuildingContext.inferenceDataForTesting,
);
ConstantContext constantContext = bodyBuilderContext.constantContext;
ThisVariable? internalThisVariable = bodyBuilderContext
InternalThisVariable? internalThisVariable = bodyBuilderContext
.createInternalThisVariable();
BodyBuilder bodyBuilder = _createBodyBuilder(
context: context,
@@ -476,7 +475,7 @@ class Resolver {
ProblemReporting problemReporting = libraryBuilder;
LibraryFeatures libraryFeatures = libraryBuilder.libraryFeatures;
ConstantContext constantContext = bodyBuilderContext.constantContext;
ThisVariable? internalThisVariable = bodyBuilderContext
InternalThisVariable? internalThisVariable = bodyBuilderContext
.createInternalThisVariable();
BodyBuilder bodyBuilder = _createBodyBuilder(
context: context,
@@ -689,7 +688,7 @@ class Resolver {
functionBodyBuildingContext.inferenceDataForTesting,
);
ConstantContext constantContext = bodyBuilderContext.constantContext;
ThisVariable? internalThisVariable = bodyBuilderContext
InternalThisVariable? internalThisVariable = bodyBuilderContext
.createInternalThisVariable();
BodyBuilder bodyBuilder = _createBodyBuilder(
context: context,
@@ -768,7 +767,7 @@ class Resolver {
ProblemReporting problemReporting = libraryBuilder;
LibraryFeatures libraryFeatures = libraryBuilder.libraryFeatures;
ConstantContext constantContext = bodyBuilderContext.constantContext;
ThisVariable? internalThisVariable = bodyBuilderContext
InternalThisVariable? internalThisVariable = bodyBuilderContext
.createInternalThisVariable();
BodyBuilder bodyBuilder = _createBodyBuilder(
context: context,
@@ -874,7 +873,7 @@ class Resolver {
required Procedure procedure,
required List<InternalVariable> extraKnownVariables,
required ExpressionEvaluationHelper expressionEvaluationHelper,
required InternalVariable? extensionThis,
required Variable? extensionThis,
}) {
_ResolverContext context = new _ResolverContext(
typeInferenceEngine: _typeInferenceEngine,
@@ -886,42 +885,30 @@ class Resolver {
LibraryFeatures libraryFeatures = libraryBuilder.libraryFeatures;
ConstantContext constantContext = bodyBuilderContext.constantContext;
ThisVariable? internalThisVariable = bodyBuilderContext
InternalThisVariable? internalThisVariable = bodyBuilderContext
.createInternalThisVariable();
BodyBuilder bodyBuilder = _createBodyBuilder(
context: context,
bodyBuilderContext: bodyBuilderContext,
scope: scope,
thisVariable: extensionThis,
constantContext: constantContext,
// TODO(johnniwinther): Should we provide these?
thisTypeParameters: null,
formalParameterScope: null,
internalThisVariable: internalThisVariable,
);
int fileOffset = token.charOffset;
FunctionNode parameters = procedure.function;
List<NominalParameterBuilder>? typeParameterBuilders;
for (TypeParameter typeParameter in parameters.typeParameters) {
typeParameterBuilders ??= <NominalParameterBuilder>[];
typeParameterBuilders.add(
new DillNominalParameterBuilder(
typeParameter,
loader: libraryBuilder.loader,
),
);
}
int wildcardVariableIndex = 0;
InternalVariable? internalExtensionThis;
List<FormalParameterBuilder>? formals =
parameters.positionalParameters.length == 0
? null
: new List<FormalParameterBuilder>.generate(
parameters.positionalParameters.length,
(int i) {
Variable parameter = parameters.positionalParameters[i];
InternalVariable formal =
parameters.positionalParameters[i] as InternalVariable;
libraryBuilder.loader.isClosureContextLoweringEnabled
? new InternalPositionalParameter(
astVariable: parameter as PositionalParameter,
isImplicitlyTyped: false,
fileOffset: parameter.fileOffset,
)
: new InternalLegacyVariable(
astVariable: parameter,
fileOffset: parameter.fileOffset,
);
String formalName = formal.cosmeticName!;
bool isWildcard =
libraryFeatures.wildcardVariables.isEnabled &&
@@ -930,6 +917,9 @@ class Resolver {
if (isWildcard) {
wildcardIndex = wildcardVariableIndex++;
}
if (parameter == extensionThis) {
internalExtensionThis = formal;
}
return new FormalParameterBuilder(
kind: FormalParameterKind.requiredPositional,
modifiers: Modifiers.empty,
@@ -948,6 +938,30 @@ class Resolver {
growable: false,
);
BodyBuilder bodyBuilder = _createBodyBuilder(
context: context,
bodyBuilderContext: bodyBuilderContext,
scope: scope,
thisVariable: internalExtensionThis,
constantContext: constantContext,
// TODO(johnniwinther): Should we provide these?
thisTypeParameters: null,
formalParameterScope: null,
internalThisVariable: internalThisVariable,
);
int fileOffset = token.charOffset;
List<NominalParameterBuilder>? typeParameterBuilders;
for (TypeParameter typeParameter in parameters.typeParameters) {
typeParameterBuilders ??= <NominalParameterBuilder>[];
typeParameterBuilders.add(
new DillNominalParameterBuilder(
typeParameter,
loader: libraryBuilder.loader,
),
);
}
BuildSingleExpressionResult result = bodyBuilder.buildSingleExpression(
token: token,
extraKnownVariables: extraKnownVariables,
@@ -960,7 +974,7 @@ class Resolver {
for (int i = 0; i < formals.length; i++) {
InternalVariable variable = formals[i].variable;
context.typeInferrer.flowAnalysis.declare(
variable.astVariable,
variable,
new SharedTypeView(variable.type),
initialized: true,
);
@@ -968,7 +982,7 @@ class Resolver {
}
for (InternalVariable extraVariable in extraKnownVariables) {
context.typeInferrer.flowAnalysis.declare(
extraVariable.astVariable,
extraVariable,
new SharedTypeView(extraVariable.type),
initialized: true,
);
@@ -1129,7 +1143,7 @@ class Resolver {
required InternalVariable? thisVariable,
required List<TypeParameter>? thisTypeParameters,
required LocalScope? formalParameterScope,
required ThisVariable? internalThisVariable,
required InternalThisVariable? internalThisVariable,
}) {
_benchmarker
// Coverage-ignore(suite): Not run.
@@ -1158,7 +1172,7 @@ class Resolver {
required InternalVariable? thisVariable,
required List<TypeParameter>? thisTypeParameters,
required ConstantContext constantContext,
required ThisVariable? internalThisVariable,
required InternalThisVariable? internalThisVariable,
}) {
return new BodyBuilderImpl(
libraryBuilder: context.libraryBuilder,
@@ -1179,7 +1193,7 @@ class Resolver {
}
_SuperParameterArguments? _createSuperParameterArguments({
required AssignedVariables assignedVariables,
required AssignedVariablesImpl assignedVariables,
required List<FormalParameterBuilder>? formals,
}) {
if (formals == null) {
@@ -1232,12 +1246,12 @@ class Resolver {
/// Helper method to create a [VariableGet] of the [variable] using
/// [fileOffset] as the file offset.
Expression _createVariableGet({
required AssignedVariables assignedVariables,
required AssignedVariablesImpl assignedVariables,
required InternalVariable variable,
required int fileOffset,
}) {
if (!variable.isLocalFunction && !variable.isWildcard) {
assignedVariables.read(variable.astVariable);
assignedVariables.read(variable);
}
return intern.createVariableGet(variable, fileOffset: fileOffset);
}
@@ -1252,7 +1266,7 @@ class Resolver {
// `thisVariable` usually appears in `_context.formals`, but for a
// constructor, it doesn't. So declare it separately.
typeInferrer.flowAnalysis.declare(
thisVariable.astVariable,
thisVariable,
new SharedTypeView(thisVariable.type),
initialized: true,
);
@@ -1264,7 +1278,7 @@ class Resolver {
// TODO(62401): Remove the cast when the flow analysis uses
// [InternalExpressionVariable]s.
typeInferrer.flowAnalysis.declare(
variable.astVariable,
variable,
new SharedTypeView(variable.type),
initialized: true,
);
@@ -1287,7 +1301,7 @@ class Resolver {
required List<Initializer> initializers,
required bool forPrimaryConstructor,
required List<InternalVariable> parameters,
required ThisVariable? internalThisVariable,
required InternalThisVariable? internalThisVariable,
required ContextAllocationStrategy contextAllocationStrategy,
}) {
_InitializerBuilder initializerBuilder = new _InitializerBuilder(
@@ -1354,10 +1368,10 @@ class Resolver {
required InternalVariable? thisVariable,
required List<Initializer> initializers,
required ConstantContext constantContext,
required ThisVariable? internalThisVariable,
required InternalThisVariable? internalThisVariable,
required bool forPrimaryConstructor,
}) {
AssignedVariables assignedVariables = context.assignedVariables;
AssignedVariablesImpl assignedVariables = context.assignedVariables;
// Create variable get expressions for super parameters before finishing
// the analysis of the assigned variables. Creating the expressions later
@@ -42,7 +42,7 @@ class ResolverForTesting extends Resolver {
required InternalVariable? thisVariable,
required List<TypeParameter>? thisTypeParameters,
required ConstantContext constantContext,
required ThisVariable? internalThisVariable,
required InternalThisVariable? internalThisVariable,
}) {
return bodyBuilderCreator(
libraryBuilder: context.libraryBuilder,
@@ -218,7 +218,7 @@ class _InitializerBuilder {
ScopeProviderInfo? _inferInitializers(
List<Initializer> initializers, {
required List<InternalVariable> parameters,
required ThisVariable? internalThisVariable,
required InternalThisVariable? internalThisVariable,
required ContextAllocationStrategy contextAllocationStrategy,
required bool isConstructorWithoutBody,
}) {
@@ -248,7 +248,7 @@ class _InitializerBuilder {
required AsyncModifier asyncModifier,
required bool forPrimaryConstructor,
required List<InternalVariable> parameters,
required ThisVariable? internalThisVariable,
required InternalThisVariable? internalThisVariable,
required ContextAllocationStrategy contextAllocationStrategy,
required bool isConstructorWithoutBody,
}) {
@@ -603,7 +603,7 @@ class _InitializerBuilder {
required TypeInferrer typeInferrer,
required _SuperParameterArguments? superParameterArguments,
required List<InternalVariable> parameters,
required ThisVariable? internalThisVariable,
required InternalThisVariable? internalThisVariable,
required ScopeProviderInfo? scopeProviderInfo,
required ContextAllocationStrategy contextAllocationStrategy,
required bool isFirstInitializer,
@@ -1490,7 +1490,7 @@ severity: $severity
String? enclosingClassOrExtension,
bool isClassInstanceMember,
Procedure procedure,
InternalVariable? extensionThis,
Variable? extensionThis,
List<InternalVariable> extraKnownVariables,
ExpressionEvaluationHelper expressionEvaluationHelper,
) async {
@@ -130,13 +130,13 @@ class InferenceVisitorImpl extends InferenceVisitorBase
TreeNode,
Statement,
Expression,
Variable,
InternalVariable,
InternalPattern,
InvalidExpression,
TypeDeclarationType,
TypeDeclaration
>,
NullShortingMixin<NullAwareGuard, Expression, Variable>,
NullShortingMixin<NullAwareGuard, Expression, InternalVariable>,
StackChecker,
ExpressionVisitor1ExperimentExclusionMixin<
ExpressionInferenceResult,
@@ -354,7 +354,6 @@ class InferenceVisitorImpl extends InferenceVisitorBase
new NullAwareGuard(variable, variable.fileOffset, this),
flowAnalysis.getExpressionInfo(variable.initializer!),
new SharedTypeView(variable.type),
guardVariable: variable,
),
);
}
@@ -1364,7 +1363,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
flowAnalysis.getExpressionInfo(result.expression),
new SharedTypeView(result.inferredType),
isNullAware: node.isNullAware,
guardVariable: node.variable.astVariable,
guardVariable: node.variable,
);
Cascade? previousEnclosingCascade = _enclosingCascade;
@@ -3402,17 +3401,29 @@ class InferenceVisitorImpl extends InferenceVisitorBase
flowAnalysis.forEach_bodyBegin(node);
flowAnalysis.declare(
variable,
new SharedTypeView(variable.type),
initialized: true,
);
if (isClosureContextLoweringEnabled) {
_contextAllocationStrategy.handleDeclarationOfVariable(
variable,
captureKind: _captureKindForVariable(variable),
InternalVariable? declaredVariable = headerResult.declaredVariable;
if (declaredVariable != null) {
flowAnalysis.declare(
declaredVariable,
new SharedTypeView(declaredVariable.type),
initialized: true,
);
if (isClosureContextLoweringEnabled) {
_contextAllocationStrategy.handleDeclarationOfVariable(
declaredVariable.astVariable,
captureKind: _captureKindForVariable(declaredVariable),
);
}
}
if (isClosureContextLoweringEnabled) {
if (declaredVariable?.astVariable != variable) {
// [variable] is synthesized.
_contextAllocationStrategy.handleDeclarationOfVariable(
variable,
captureKind: CaptureKind.notCaptured,
);
}
}
ForInEncoding encoding = headerResult.computeEncoding();
@@ -3590,7 +3601,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
if (isClosureContextLoweringEnabled) {
_contextAllocationStrategy.handleDeclarationOfVariable(
node.variable.astVariable,
captureKind: _captureKindForVariable(node.variable.astVariable),
captureKind: _captureKindForVariable(node.variable),
);
capturedContexts = _contextAllocationStrategy
.computeCapturedVariableContexts(_capturedVariablesForNode(node));
@@ -3627,7 +3638,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
}
variable.type = inferredType;
flowAnalysis.declare(
variable.astVariable,
variable,
new SharedTypeView(variable.type),
initialized: true,
);
@@ -3650,6 +3661,9 @@ class InferenceVisitorImpl extends InferenceVisitorBase
);
libraryBuilder.loader.dataForTesting
// Coverage-ignore(suite): Not run.
?.registerAlias(variable, variable.astVariable);
libraryBuilder.loader.dataForTesting
// Coverage-ignore(suite): Not run.
?.registerAlias(node, replacement);
return new StatementInferenceResult.single(replacement);
}
@@ -3657,7 +3671,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
@override
ScopeProviderInfo beginClosureContextAllocation(
List<InternalVariable> parameters, {
required ThisVariable? internalThisVariable,
required InternalThisVariable? internalThisVariable,
required ScopeProviderInfo? scopeProviderInfo,
}) {
scopeProviderInfo ??= _contextAllocationStrategy.enterScopeProvider(
@@ -3667,7 +3681,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
);
if (internalThisVariable != null) {
_contextAllocationStrategy.handleDeclarationOfVariable(
internalThisVariable,
internalThisVariable.astVariable,
captureKind: _captureKindForVariable(internalThisVariable),
);
}
@@ -3682,10 +3696,9 @@ class InferenceVisitorImpl extends InferenceVisitorBase
void _handleDeclarationsOfParameters(List<InternalVariable> parameters) {
for (InternalVariable parameter in parameters) {
Variable parameterAstVariable = parameter.astVariable;
_contextAllocationStrategy.handleDeclarationOfVariable(
parameterAstVariable,
captureKind: _captureKindForVariable(parameterAstVariable),
parameter.astVariable,
captureKind: _captureKindForVariable(parameter),
);
}
}
@@ -3911,7 +3924,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
{
for (InternalVariable variable
in node.patternGuard.pattern.declaredVariables)
variable.cosmeticName!: variable.astVariable,
variable.cosmeticName!: variable,
},
);
@@ -4334,7 +4347,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
variables: {
for (InternalVariable variable
in element.internalPatternGuard.pattern.declaredVariables)
variable.cosmeticName!: variable.astVariable,
variable.cosmeticName!: variable,
},
guard: element.internalPatternGuard.guard,
ifTrue: element.then,
@@ -4601,16 +4614,29 @@ class InferenceVisitorImpl extends InferenceVisitorBase
flowAnalysis.forEach_bodyBegin(node);
flowAnalysis.declare(
variable,
new SharedTypeView(variable.type),
initialized: true,
);
if (isClosureContextLoweringEnabled) {
_contextAllocationStrategy.handleDeclarationOfVariable(
variable,
captureKind: _captureKindForVariable(variable),
InternalVariable? declaredVariable = result.declaredVariable;
if (declaredVariable != null) {
flowAnalysis.declare(
declaredVariable,
new SharedTypeView(declaredVariable.type),
initialized: true,
);
if (isClosureContextLoweringEnabled) {
_contextAllocationStrategy.handleDeclarationOfVariable(
declaredVariable.astVariable,
captureKind: _captureKindForVariable(declaredVariable),
);
}
}
if (isClosureContextLoweringEnabled) {
if (declaredVariable?.astVariable != variable) {
// Coverage-ignore-block(suite): Not run.
// [variable] is synthesized.
_contextAllocationStrategy.handleDeclarationOfVariable(
variable,
captureKind: CaptureKind.notCaptured,
);
}
}
node.encoding = result.computeEncoding();
@@ -7486,7 +7512,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
variables: {
for (InternalVariable variable
in entry.internalPatternGuard.pattern.declaredVariables)
variable.cosmeticName!: variable.astVariable,
variable.cosmeticName!: variable,
},
guard: entry.internalPatternGuard.guard,
ifTrue: entry.then,
@@ -7807,18 +7833,30 @@ class InferenceVisitorImpl extends InferenceVisitorBase
flowAnalysis.forEach_bodyBegin(node);
flowAnalysis.declare(
variable,
new SharedTypeView(variable.type),
initialized: true,
);
if (isClosureContextLoweringEnabled) {
_contextAllocationStrategy.handleDeclarationOfVariable(
variable,
captureKind: _captureKindForVariable(variable),
InternalVariable? declaredVariable = result.declaredVariable;
if (declaredVariable != null) {
flowAnalysis.declare(
declaredVariable,
new SharedTypeView(declaredVariable.type),
initialized: true,
);
if (isClosureContextLoweringEnabled) {
_contextAllocationStrategy.handleDeclarationOfVariable(
declaredVariable.astVariable,
captureKind: _captureKindForVariable(declaredVariable),
);
}
}
if (isClosureContextLoweringEnabled) {
if (declaredVariable?.astVariable != variable) {
// Coverage-ignore-block(suite): Not run.
// [variable] is synthesized.
_contextAllocationStrategy.handleDeclarationOfVariable(
variable,
captureKind: CaptureKind.notCaptured,
);
}
}
node.encoding = result.computeEncoding();
// Actual types are added by the recursive call.
@@ -11975,12 +12013,12 @@ class InferenceVisitorImpl extends InferenceVisitorBase
node.variable.initializer = initializer..parent = node.variable;
flowAnalysis.declare(
node.variable.astVariable,
node.variable,
new SharedTypeView(node.variable.type),
initialized: false,
);
flowAnalysis.initialize(
node.variable.astVariable,
node.variable,
new SharedTypeView(node.variable.type),
flowAnalysis.getExpressionInfo(node.variable.initializer!),
isFinal: false,
@@ -11992,7 +12030,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
flow.nullAwareAccess_rightBegin(
flowAnalysis.getExpressionInfo(node.variable.initializer!),
new SharedTypeView(initializerType),
guardVariable: node.variable.astVariable,
guardVariable: node.variable,
);
}
@@ -12168,12 +12206,12 @@ class InferenceVisitorImpl extends InferenceVisitorBase
node.variable.initializer = initializer..parent = node.variable;
flowAnalysis.declare(
node.variable.astVariable,
node.variable,
new SharedTypeView(node.variable.type),
initialized: false,
);
flowAnalysis.initialize(
node.variable.astVariable,
node.variable,
new SharedTypeView(node.variable.type),
flowAnalysis.getExpressionInfo(node.variable.initializer!),
isFinal: false,
@@ -12204,7 +12242,6 @@ class InferenceVisitorImpl extends InferenceVisitorBase
new NullAwareGuard(tempVar!, node.variable.fileOffset, this),
flowAnalysis.getExpressionInfo(tempVar.initializer!),
new SharedTypeView(tempVar.type),
guardVariable: tempVar,
);
}
}
@@ -13624,8 +13661,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase
Catch visitCatch(InternalCatch node) {
ScopeProviderInfo? scopeProviderInfo;
Variable? exception = node.exception?.astVariable;
Variable? stackTrace = node.stackTrace?.astVariable;
InternalVariable? exception = node.exception;
InternalVariable? stackTrace = node.stackTrace;
if (isClosureContextLoweringEnabled) {
scopeProviderInfo = _contextAllocationStrategy.enterScopeProvider(
scopeProviderInfoKind: ScopeProviderInfoKind.Catch,
@@ -13634,7 +13671,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
// TODO(62401): Remove the casts when the flow analysis uses
// [InternalExpressionVariable]s.
_contextAllocationStrategy.handleDeclarationOfVariable(
exception,
exception.astVariable,
captureKind: _captureKindForVariable(exception),
);
}
@@ -13642,7 +13679,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
// TODO(62401): Remove the casts when the flow analysis uses
// [InternalExpressionVariable]s.
_contextAllocationStrategy.handleDeclarationOfVariable(
stackTrace,
stackTrace.astVariable,
captureKind: _captureKindForVariable(stackTrace),
);
}
@@ -13656,8 +13693,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase
}
return extern.createCatch(
guard: node.guard,
exception: exception,
stackTrace: stackTrace,
exception: exception?.astVariable,
stackTrace: stackTrace?.astVariable,
body: body,
scope: scope,
fileOffset: node.fileOffset,
@@ -13685,8 +13722,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase
// TODO(62401): Remove the casts when the flow analysis uses
// [InternalExpressionVariable]s.
flowAnalysis.tryCatchStatement_catchBegin(
catchBlock.exception?.astVariable,
catchBlock.stackTrace?.astVariable,
catchBlock.exception,
catchBlock.stackTrace,
);
catchBlocks.add(visitCatch(catchBlock));
flowAnalysis.tryCatchStatement_catchEnd();
@@ -13791,7 +13828,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
if (isClosureContextLoweringEnabled) {
_contextAllocationStrategy.handleDeclarationOfVariable(
node.variable.astVariable,
captureKind: _captureKindForVariable(node.variable.astVariable),
captureKind: _captureKindForVariable(node.variable),
);
}
return variableDeclarationInferenceResult;
@@ -14506,9 +14543,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
case InternalAndPattern():
return analyzeLogicalAndPatternSchema(node.left, node.right);
case InternalAssignedVariablePattern():
return analyzeAssignedVariablePatternSchema(
node.variable.astVariable,
);
return analyzeAssignedVariablePatternSchema(node.variable);
case InternalCastPattern():
return analyzeCastPatternSchema();
case InternalConstantPattern():
@@ -14818,21 +14853,25 @@ class InferenceVisitorImpl extends InferenceVisitorBase
}
@override
FlowAnalysis<TreeNode, Statement, Expression, Variable> get flow =>
FlowAnalysis<TreeNode, Statement, Expression, InternalVariable> get flow =>
flowAnalysis;
@override
SwitchExpressionMemberInfo<TreeNode, Expression, Variable>
SwitchExpressionMemberInfo<TreeNode, Expression, InternalVariable>
getSwitchExpressionMemberInfo(Expression node, int index) {
InternalSwitchExpressionCase switchExpressionCase =
(node as InternalSwitchExpression).cases[index];
InternalPattern pattern = switchExpressionCase.patternGuard.pattern;
Map<String, Variable> variables = {
Map<String, InternalVariable> variables = {
for (InternalVariable declaredVariable in pattern.declaredVariables)
declaredVariable.cosmeticName!: declaredVariable.astVariable,
declaredVariable.cosmeticName!: declaredVariable,
};
return new SwitchExpressionMemberInfo<TreeNode, Expression, Variable>(
head: new CaseHeadOrDefaultInfo<TreeNode, Expression, Variable>(
return new SwitchExpressionMemberInfo<
TreeNode,
Expression,
InternalVariable
>(
head: new CaseHeadOrDefaultInfo<TreeNode, Expression, InternalVariable>(
pattern: pattern,
guard: switchExpressionCase.patternGuard.guard,
variables: variables,
@@ -14842,7 +14881,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
}
@override
SwitchStatementMemberInfo<TreeNode, Statement, Expression, Variable>
SwitchStatementMemberInfo<TreeNode, Statement, Expression, InternalVariable>
getSwitchStatementMemberInfo(
covariant InternalSwitchStatement node,
int caseIndex,
@@ -14872,7 +14911,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
variables: {
for (InternalVariable variable
in patternGuard.pattern.declaredVariables)
variable.cosmeticName!: variable.astVariable,
variable.cosmeticName!: variable,
},
),
if (case_.isDefault)
@@ -14881,7 +14920,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
body: [case_.body],
variables: {
for (InternalVariable jointVariable in case_.jointVariables)
jointVariable.cosmeticName!: jointVariable.astVariable,
jointVariable.cosmeticName!: jointVariable,
},
hasLabels: case_.hasLabel,
);
@@ -15003,7 +15042,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
void handleCase_afterCaseHeads(
Statement node,
int caseIndex,
Iterable<Variable> variables,
Iterable<InternalVariable> variables,
) {}
@override
@@ -15079,7 +15118,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
}
@override
void setVariableType(Variable variable, SharedTypeView type) {
void setVariableType(InternalVariable variable, SharedTypeView type) {
variable.type = type.unwrapTypeView();
}
@@ -15111,7 +15150,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
analyzeDeclaredVariablePattern(
context,
node,
node.variable.astVariable,
node.variable,
node.variableName,
node.type?.wrapSharedTypeView(),
);
@@ -16425,10 +16464,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase
// TODO(johnniwinther): Share this through the type analyzer.
Pattern? replacement;
InternalVariable variable = node.variable;
bool isDefinitelyAssigned = flowAnalysis.isAssigned(variable.astVariable);
bool isDefinitelyUnassigned = flowAnalysis.isUnassigned(
variable.astVariable,
);
bool isDefinitelyAssigned = flowAnalysis.isAssigned(variable);
bool isDefinitelyUnassigned = flowAnalysis.isUnassigned(variable);
if ((variable.isLate && variable.isFinal) ||
variable.isLateFinalWithoutInitializer) {
if (isDefinitelyAssigned) {
@@ -16479,11 +16516,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
}
AssignedVariablePatternResult<InvalidExpression> analysisResult =
analyzeAssignedVariablePattern(
context,
node,
node.variable.astVariable,
);
analyzeAssignedVariablePattern(context, node, node.variable);
DartType matchedValueType = analysisResult.matchedValueType
.unwrapTypeView();
@@ -16507,6 +16540,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
replacement ??
extern.createAssignedVariablePattern(
variable: node.variable.astVariable,
setter: node.variable.lateSetter,
matchedValueType: matchedValueType,
needsCast: needsCast,
hasObservableEffect: hasObservableEffect,
@@ -16725,7 +16759,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
@override
void finishJoinedPatternVariable(
Variable variable, {
InternalVariable variable, {
required JoinedPatternVariableLocation location,
required JoinedPatternVariableInconsistency inconsistency,
required bool isFinal,
@@ -17363,7 +17397,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
return node is DotShorthand;
}
CaptureKind _captureKindForVariable(Variable variable) {
CaptureKind _captureKindForVariable(InternalVariable variable) {
int variableKey = assignedVariables.promotionKeyStore.keyForVariable(
variable,
);
@@ -17384,12 +17418,16 @@ class InferenceVisitorImpl extends InferenceVisitorBase
AssignedVariablesNodeInfo nodeInfo = assignedVariables.getInfoForNode(node);
for (int variableKey in nodeInfo.read) {
capturedVariables.add(
assignedVariables.promotionKeyStore.variableForKey(variableKey)!,
assignedVariables.promotionKeyStore
.variableForKey(variableKey)!
.astVariable,
);
}
for (int variableKey in nodeInfo.written) {
capturedVariables.add(
assignedVariables.promotionKeyStore.variableForKey(variableKey)!,
assignedVariables.promotionKeyStore
.variableForKey(variableKey)!
.astVariable,
);
}
return capturedVariables;
@@ -17466,14 +17504,14 @@ class InferenceVisitorImpl extends InferenceVisitorBase
internalVariable.type = inferredType;
}
flowAnalysis.declare(
internalVariable.astVariable,
internalVariable,
new SharedTypeView(internalVariable.type),
initialized: internalVariable.hasDeclaredInitializer,
);
if (initializerResult != null) {
DartType initializerType = initializerResult.inferredType;
flowAnalysis.initialize(
internalVariable.astVariable,
internalVariable,
new SharedTypeView(initializerType),
flowAnalysis.getExpressionInfo(initializerResult.expression),
isFinal: internalVariable.isFinal,
@@ -17682,6 +17720,9 @@ class InferenceVisitorImpl extends InferenceVisitorBase
fileOffset: internalVariable.fileOffset,
);
}
libraryBuilder.loader.dataForTesting
// Coverage-ignore(suite): Not run.
?.registerAlias(internalVariable, internalVariable.astVariable);
return new VariableDeclarationInferenceResult.direct(
extern.createVariableDeclaration(
internalVariable.astVariable,
@@ -17693,7 +17734,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
@override
ScopeProviderInfo beginFieldInference({
required ThisVariable? internalThisVariable,
required InternalThisVariable? internalThisVariable,
}) {
ScopeProviderInfo scopeProviderInfo = _contextAllocationStrategy
.enterScopeProvider(
@@ -17703,7 +17744,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
);
if (internalThisVariable != null) {
_contextAllocationStrategy.handleDeclarationOfVariable(
internalThisVariable,
internalThisVariable.astVariable,
captureKind: _captureKindForVariable(internalThisVariable),
);
}
@@ -159,8 +159,8 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
InferenceDataForTesting? get dataForTesting => _inferrer.dataForTesting;
FlowAnalysis<TreeNode, Statement, Expression, Variable> get flowAnalysis =>
_inferrer.flowAnalysis;
FlowAnalysis<TreeNode, Statement, Expression, InternalVariable>
get flowAnalysis => _inferrer.flowAnalysis;
/// Provides access to the [OperationsCfe] object. This is needed by
/// [isAssignable] and for caching types.
@@ -2302,7 +2302,7 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
for (InternalVariable parameter in function.positionalParameters) {
flowAnalysis.declare(
parameter.astVariable,
parameter,
new SharedTypeView(parameter.type),
initialized: true,
);
@@ -2318,7 +2318,7 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
}
for (InternalVariable parameter in function.namedParameters) {
flowAnalysis.declare(
parameter.astVariable,
parameter,
new SharedTypeView(parameter.type),
initialized: true,
);
@@ -2398,6 +2398,22 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
for (InternalVariable parameter in function.namedParameters)
parameter.astVariable,
];
if (libraryBuilder.loader.dataForTesting != null) {
// Coverage-ignore-block(suite): Not run.
for (InternalVariable parameter in function.positionalParameters) {
libraryBuilder.loader.dataForTesting?.registerAlias(
parameter,
parameter.astVariable,
);
}
for (InternalVariable parameter in function.namedParameters) {
libraryBuilder.loader.dataForTesting?.registerAlias(
parameter,
parameter.astVariable,
);
}
}
return new LocalFunctionResult(
returnType: returnType,
positionalParameters: positionalParameters,
@@ -4164,7 +4180,7 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
// Don't promote local functions.
SharedTypeView? wrappedPromotedType;
(wrappedPromotedType, expressionInfo) = flowAnalysis.variableRead(
variable.astVariable,
variable,
);
promotedType = wrappedPromotedType?.unwrapTypeView();
}
@@ -4191,7 +4207,7 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
resultExpression = result..variable = variable.astVariable;
}
bool isUnassigned = !flowAnalysis.isAssigned(variable.astVariable);
bool isUnassigned = !flowAnalysis.isAssigned(variable);
if (isUnassigned) {
dataForTesting
// Coverage-ignore(suite): Not run.
@@ -4199,9 +4215,7 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
.potentiallyUnassignedNodes // Coverage-ignore(suite): Not run.
.add(result);
}
bool isDefinitelyUnassigned = flowAnalysis.isUnassigned(
variable.astVariable,
);
bool isDefinitelyUnassigned = flowAnalysis.isUnassigned(variable);
if (isDefinitelyUnassigned) {
dataForTesting
// Coverage-ignore(suite): Not run.
@@ -4275,7 +4289,7 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
computeVariableSetTypeAndWriteContext(InternalVariable variable) {
DartType declaredOrInferredType = variable.lateType ?? variable.type;
DartType? promotedType = flowAnalysis
.promotedType(variable.astVariable)
.promotedType(variable)
?.unwrapTypeView();
return (declaredOrInferredType, promotedType ?? declaredOrInferredType);
}
@@ -4292,10 +4306,8 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
required int assignOffset,
required int nameOffset,
}) {
bool isDefinitelyAssigned = flowAnalysis.isAssigned(variable.astVariable);
bool isDefinitelyUnassigned = flowAnalysis.isUnassigned(
variable.astVariable,
);
bool isDefinitelyAssigned = flowAnalysis.isAssigned(variable);
bool isDefinitelyUnassigned = flowAnalysis.isUnassigned(variable);
rhsResult = ensureAssignableResult(
variableType,
rhsResult,
@@ -4309,7 +4321,7 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
result,
flowAnalysis.write(
result,
variable.astVariable,
variable,
new SharedTypeView(rhsResult.inferredType),
flowAnalysis.getExpressionInfo(rhsResult.expression),
),
@@ -5576,7 +5588,7 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
/// [parameters] are those of the function being inferred.
ScopeProviderInfo beginClosureContextAllocation(
List<InternalVariable> parameters, {
required ThisVariable? internalThisVariable,
required InternalThisVariable? internalThisVariable,
required ScopeProviderInfo? scopeProviderInfo,
});
@@ -5585,7 +5597,7 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
/// Performs preliminary computations before inferring the field initializer.
ScopeProviderInfo beginFieldInference({
required ThisVariable? internalThisVariable,
required InternalThisVariable? internalThisVariable,
});
/// Finishes computations after inferring the field initializer.
@@ -5653,7 +5665,12 @@ FunctionType replaceReturnType(FunctionType functionType, DartType returnType) {
}
class _WhyNotPromotedVisitor
implements NonPromotionReasonVisitor<List<LocatedMessage>, Node, Variable> {
implements
NonPromotionReasonVisitor<
List<LocatedMessage>,
Node,
InternalVariable
> {
final InferenceVisitorBase inferrer;
Member? propertyReference;
@@ -5662,7 +5679,7 @@ class _WhyNotPromotedVisitor
@override
List<LocatedMessage> visitDemoteViaExplicitWrite(
DemoteViaExplicitWrite<Variable> reason,
DemoteViaExplicitWrite<InternalVariable> reason,
) {
TreeNode node = reason.node as TreeNode;
if (inferrer.dataForTesting != null) {
@@ -57,7 +57,7 @@ class MatchingExpressionVisitor
}
return new DelayedAssignment(
matchingCache,
node.variable,
node.setter ?? node.variable,
node.variable.type,
valueExpression,
fileOffset: node.fileOffset,
@@ -23,7 +23,7 @@ class SharedTypeAnalyzerErrors
TreeNode,
Statement,
Expression,
Variable,
InternalVariable,
InternalPattern,
InvalidExpression
> {
@@ -75,14 +75,14 @@ class SharedTypeAnalyzerErrors
@override
InvalidExpression duplicateAssignmentPatternVariable({
required Variable variable,
required InternalVariable variable,
required InternalPattern original,
required InternalPattern duplicate,
}) {
return problemReporting.buildProblem(
compilerContext: compilerContext,
message: diag.duplicatePatternAssignmentVariable.withArguments(
variableName: variable.name!,
variableName: variable.cosmeticName!,
),
fileUri: uri,
fileOffset: duplicate.fileOffset,
@@ -155,8 +155,8 @@ class SharedTypeAnalyzerErrors
@override
void inconsistentJoinedPatternVariable({
required Variable variable,
required Variable component,
required InternalVariable variable,
required InternalVariable component,
}) {
// TODO(johnniwinther): How should we handle errors that are not report
// here? Should we have a sentinel error node, allow a nullable result, or ?
@@ -12,6 +12,7 @@ import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/type_algebra.dart';
import '../kernel/internal_ast.dart';
import 'type_inference_engine.dart';
import 'type_schema.dart';
import 'type_schema_environment.dart';
@@ -21,14 +22,14 @@ import 'type_schema_environment.dart';
class TypeConstraintGatherer
extends
shared.TypeConstraintGenerator<
Variable,
InternalVariable,
TypeDeclarationType,
TypeDeclaration,
TreeNode
>
with
shared.TypeConstraintGeneratorMixin<
Variable,
InternalVariable,
TypeDeclarationType,
TypeDeclaration,
TreeNode
@@ -379,14 +379,14 @@ class TypeInferenceEngineImpl extends TypeInferenceEngine {
if (dataForTesting != null) {
// Coverage-ignore-block(suite): Not run.
dataForTesting.flowAnalysisResult.assignedVariables =
new AssignedVariablesForTesting<TreeNode, Variable>();
new AssignedVariablesForTesting<TreeNode, InternalVariable>();
assignedVariables = new AssignedVariablesImpl(
dataForTesting.flowAnalysisResult.assignedVariables!,
isClosureContextLoweringEnabled: isClosureContextLoweringEnabled,
);
} else {
assignedVariables = new AssignedVariablesImpl(
new AssignedVariables<TreeNode, Variable>(),
new AssignedVariables<TreeNode, InternalVariable>(),
isClosureContextLoweringEnabled: isClosureContextLoweringEnabled,
);
}
@@ -415,7 +415,11 @@ class TypeInferenceEngineImpl extends TypeInferenceEngine {
// TODO(cstefantsova): Merge with [TypeInferenceResultForTesting].
class InferenceDataForTesting
extends shared.TypeConstraintGenerationDataForTesting<Variable, TreeNode> {
extends
shared.TypeConstraintGenerationDataForTesting<
InternalVariable,
TreeNode
> {
final FlowAnalysisResult flowAnalysisResult = new FlowAnalysisResult();
final TypeInferenceResultForTesting typeInferenceResult =
@@ -446,7 +450,7 @@ class FlowAnalysisResult {
final List<TreeNode> definitelyUnassignedNodes = [];
/// The assigned variables information that computed for the member.
AssignedVariablesForTesting<TreeNode, Variable>? assignedVariables;
AssignedVariablesForTesting<TreeNode, InternalVariable>? assignedVariables;
/// For each expression that led to an error because it was not promoted, a
/// string describing the reason it was not promoted.
@@ -461,14 +465,14 @@ class FlowAnalysisResult {
class OperationsCfe
with
TypeAnalyzerOperationsMixin<
Variable,
InternalVariable,
TypeDeclarationType,
TypeDeclaration,
TreeNode
>
implements
TypeAnalyzerOperations<
Variable,
InternalVariable,
TypeDeclarationType,
TypeDeclaration,
TreeNode
@@ -595,7 +599,7 @@ class OperationsCfe
bool isExtensionTypeInternal(DartType type) => type is ExtensionType;
@override
bool isFinal(Variable variable) {
bool isFinal(InternalVariable variable) {
return variable.isFinal;
}
@@ -683,14 +687,11 @@ class OperationsCfe
}
@override
SharedTypeView variableType(Variable variable) {
SharedTypeView variableType(InternalVariable variable) {
// When late variables get lowered, their type is changed, but the
// original type is stored in `VariableDeclarationImpl.lateType`, so we
// use that if it exists.
DartType? lateType = variable is InternalVariable
? (variable as InternalVariable).lateType
: null;
return new SharedTypeView(lateType ?? variable.type);
return new SharedTypeView(variable.lateType ?? variable.type);
}
@override
@@ -772,7 +773,7 @@ class OperationsCfe
}
@override
bool isVariableFinal(Variable node) {
bool isVariableFinal(InternalVariable node) {
return node.isFinal;
}
@@ -1097,7 +1098,7 @@ class OperationsCfe
@override
TypeConstraintGenerator<
Variable,
InternalVariable,
TypeDeclarationType,
TypeDeclaration,
TreeNode
@@ -1184,7 +1185,11 @@ class OperationsCfe
/// Type inference results used for testing.
class TypeInferenceResultForTesting
extends shared.TypeConstraintGenerationDataForTesting<Variable, TreeNode> {
extends
shared.TypeConstraintGenerationDataForTesting<
InternalVariable,
TreeNode
> {
final Map<TreeNode, List<DartType>> inferredTypeArguments = {};
final Map<TreeNode, DartType> inferredVariableTypes = {};
}
@@ -41,7 +41,8 @@ abstract class TypeInferrer {
ExtensionScope get extensionScope;
/// Returns the [FlowAnalysis] used during inference.
FlowAnalysis<TreeNode, Statement, Expression, Variable> get flowAnalysis;
FlowAnalysis<TreeNode, Statement, Expression, InternalVariable>
get flowAnalysis;
AssignedVariablesImpl get assignedVariables;
@@ -55,7 +56,7 @@ abstract class TypeInferrer {
DartType? declaredType,
required Expression initializer,
required InferenceDefaultType inferenceDefaultType,
required ThisVariable? internalThisVariable,
required InternalThisVariable? internalThisVariable,
});
/// Performs type inference on the given function body.
@@ -66,7 +67,7 @@ abstract class TypeInferrer {
required AsyncModifier asyncModifier,
required Statement body,
required List<InternalVariable> parameters,
required ThisVariable? internalThisVariable,
required InternalThisVariable? internalThisVariable,
required ScopeProviderInfo? scopeProviderInfo,
required ContextAllocationStrategy contextAllocationStrategy,
required ConstructorContext? constructorContext,
@@ -79,7 +80,7 @@ abstract class TypeInferrer {
required ConstructorContext constructorContext,
required List<Initializer> initializers,
required List<InternalVariable> parameters,
required ThisVariable? internalThisVariable,
required InternalThisVariable? internalThisVariable,
required ContextAllocationStrategy contextAllocationStrategy,
required bool isConstructorWithoutBody,
});
@@ -124,7 +125,7 @@ class TypeInferrerImpl implements TypeInferrer {
TypeAnalyzerOptions typeAnalyzerOptions;
@override
late final FlowAnalysis<TreeNode, Statement, Expression, Variable>
late final FlowAnalysis<TreeNode, Statement, Expression, InternalVariable>
flowAnalysis = new FlowAnalysis(
operations,
assignedVariables,
@@ -210,7 +211,7 @@ class TypeInferrerImpl implements TypeInferrer {
DartType? declaredType,
required Expression initializer,
required InferenceDefaultType inferenceDefaultType,
required ThisVariable? internalThisVariable,
required InternalThisVariable? internalThisVariable,
}) {
InferenceVisitorBase visitor = _createInferenceVisitor(
fileUri: fileUri,
@@ -261,7 +262,7 @@ class TypeInferrerImpl implements TypeInferrer {
required AsyncModifier asyncModifier,
required Statement body,
required List<InternalVariable> parameters,
required ThisVariable? internalThisVariable,
required InternalThisVariable? internalThisVariable,
required ScopeProviderInfo? scopeProviderInfo,
required ContextAllocationStrategy contextAllocationStrategy,
required ConstructorContext? constructorContext,
@@ -331,25 +332,39 @@ class TypeInferrerImpl implements TypeInferrer {
InferenceVisitorBase.createContextAllocationStrategy(),
);
List<InternalVariable> positionalParameters = [
for (Variable positionalParameter
in redirectingFactoryFunction.positionalParameters)
isClosureContextLoweringEnabled
? new InternalPositionalParameter(
astVariable: positionalParameter as PositionalParameter,
isImplicitlyTyped: false,
fileOffset: positionalParameter.fileOffset,
)
: new InternalLegacyVariable(
astVariable: positionalParameter,
fileOffset: positionalParameter.fileOffset,
),
];
List<InternalVariable> namedParameters = [
for (Variable namedParameter
in redirectingFactoryFunction.namedParameters)
isClosureContextLoweringEnabled
? new InternalNamedParameter(
astVariable: namedParameter as NamedParameter,
isImplicitlyTyped: false,
fileOffset: namedParameter.fileOffset,
)
: new InternalLegacyVariable(
astVariable: namedParameter,
fileOffset: namedParameter.fileOffset,
),
];
ScopeProviderInfo? scopeProviderInfo;
if (isClosureContextLoweringEnabled) {
scopeProviderInfo = visitor.beginClosureContextAllocation(
[
for (Variable positionalParameter
in redirectingFactoryFunction.positionalParameters)
new InternalPositionalParameter(
astVariable: positionalParameter as PositionalParameter,
isImplicitlyTyped: false,
fileOffset: positionalParameter.fileOffset,
),
for (Variable namedParameter
in redirectingFactoryFunction.namedParameters)
new InternalNamedParameter(
astVariable: namedParameter as NamedParameter,
isImplicitlyTyped: false,
fileOffset: namedParameter.fileOffset,
),
],
[...positionalParameters, ...namedParameters],
internalThisVariable: null,
scopeProviderInfo: null,
);
@@ -357,60 +372,30 @@ class TypeInferrerImpl implements TypeInferrer {
List<Argument> arguments = [];
int positionalCount = 0;
for (Variable parameter
in redirectingFactoryFunction.positionalParameters) {
for (InternalVariable parameter in positionalParameters) {
flowAnalysis.declare(
parameter,
new SharedTypeView(parameter.type),
initialized: true,
);
Expression variableGet;
if (isClosureContextLoweringEnabled) {
variableGet = intern.createVariableGet(
new InternalPositionalParameter(
astVariable: parameter as PositionalParameter,
isImplicitlyTyped: false,
fileOffset: parameter.fileOffset,
),
fileOffset: parameter.fileOffset,
);
} else {
variableGet = intern.createVariableGet(
parameter as InternalVariable,
fileOffset: parameter.fileOffset,
);
}
Expression variableGet = intern.createVariableGet(
parameter,
fileOffset: parameter.fileOffset,
);
arguments.add(new PositionalArgument(variableGet));
positionalCount++;
}
for (Variable parameter in redirectingFactoryFunction.namedParameters) {
for (InternalVariable parameter in namedParameters) {
flowAnalysis.declare(
parameter,
new SharedTypeView(parameter.type),
initialized: true,
);
NamedExpression namedExpression;
if (isClosureContextLoweringEnabled) {
namedExpression = new NamedExpression(
parameter.name!,
intern.createVariableGet(
new InternalNamedParameter(
astVariable: parameter as NamedParameter,
isImplicitlyTyped: false,
fileOffset: parameter.fileOffset,
),
fileOffset: parameter.fileOffset,
),
);
} else {
namedExpression = new NamedExpression(
parameter.name!,
intern.createVariableGet(
parameter as InternalVariable,
fileOffset: parameter.fileOffset,
),
);
}
NamedExpression namedExpression = new NamedExpression(
parameter.cosmeticName!,
intern.createVariableGet(parameter, fileOffset: parameter.fileOffset),
);
arguments.add(new NamedArgument(namedExpression));
}
// If arguments are created using [ArgumentsImpl], and the
@@ -451,7 +436,7 @@ class TypeInferrerImpl implements TypeInferrer {
required ConstructorContext constructorContext,
required List<Initializer> initializers,
required List<InternalVariable> parameters,
required ThisVariable? internalThisVariable,
required InternalThisVariable? internalThisVariable,
required ContextAllocationStrategy contextAllocationStrategy,
required bool isConstructorWithoutBody,
}) {
@@ -554,8 +539,8 @@ class TypeInferrerImplBenchmarked implements TypeInferrer {
AssignedVariablesImpl get assignedVariables => impl.assignedVariables;
@override
FlowAnalysis<TreeNode, Statement, Expression, Variable> get flowAnalysis =>
impl.flowAnalysis;
FlowAnalysis<TreeNode, Statement, Expression, InternalVariable>
get flowAnalysis => impl.flowAnalysis;
@override
TypeSchemaEnvironment get typeSchemaEnvironment => impl.typeSchemaEnvironment;
@@ -566,7 +551,7 @@ class TypeInferrerImplBenchmarked implements TypeInferrer {
DartType? declaredType,
required Expression initializer,
required InferenceDefaultType inferenceDefaultType,
required ThisVariable? internalThisVariable,
required InternalThisVariable? internalThisVariable,
}) {
benchmarker.beginSubdivide(BenchmarkSubdivides.inferFieldInitializer);
InferredFieldInitializer result = impl.inferFieldInitializer(
@@ -588,7 +573,7 @@ class TypeInferrerImplBenchmarked implements TypeInferrer {
required AsyncModifier asyncModifier,
required Statement body,
required List<InternalVariable> parameters,
required ThisVariable? internalThisVariable,
required InternalThisVariable? internalThisVariable,
required ScopeProviderInfo? scopeProviderInfo,
required ContextAllocationStrategy contextAllocationStrategy,
required ConstructorContext? constructorContext,
@@ -618,7 +603,7 @@ class TypeInferrerImplBenchmarked implements TypeInferrer {
required ConstructorContext constructorContext,
required List<Initializer> initializers,
required List<InternalVariable> parameters,
required ThisVariable? internalThisVariable,
required InternalThisVariable? internalThisVariable,
required ContextAllocationStrategy<ScopeProviderInfo>
contextAllocationStrategy,
required bool isConstructorWithoutBody,
@@ -14,17 +14,19 @@ import 'package:kernel/src/hierarchy_based_type_environment.dart'
import 'package:kernel/type_algebra.dart';
import 'package:kernel/type_environment.dart';
import '../kernel/internal_ast.dart';
import 'standard_bounds.dart' show TypeSchemaStandardBounds;
import 'type_constraint_gatherer.dart' show TypeConstraintGatherer;
import 'type_inference_engine.dart';
import 'type_demotion.dart';
import 'type_schema.dart' show UnknownType;
typedef GeneratedTypeConstraint = shared.GeneratedTypeConstraint<Variable>;
typedef GeneratedTypeConstraint =
shared.GeneratedTypeConstraint<InternalVariable>;
typedef MergedTypeConstraint =
shared.MergedTypeConstraint<
Variable,
InternalVariable,
TypeDeclarationType,
TypeDeclaration,
TreeNode
@@ -32,7 +34,7 @@ typedef MergedTypeConstraint =
typedef UnknownTypeConstraintOrigin =
shared.UnknownTypeConstraintOrigin<
Variable,
InternalVariable,
TypeDeclarationType,
TypeDeclaration,
TreeNode
@@ -52,7 +52,8 @@ import 'package:kernel/ast.dart'
TypeParameter,
Variable,
VariableGet,
defaultLanguageVersion;
defaultLanguageVersion,
LegacyVariable;
import 'package:kernel/class_hierarchy.dart';
import 'package:kernel/core_types.dart';
import 'package:kernel/target/targets.dart' show NoneTarget, TargetFlags;
@@ -177,9 +178,8 @@ Future<void> main() async {
new TypeParameter("T", const DynamicType(), const DynamicType()),
loader: null,
);
InternalVariable variable = new VariableDeclarationImpl(
null,
isSynthesized: true,
InternalVariable variable = new InternalLegacyVariable(
astVariable: new LegacyVariable(null, isSynthesized: true),
fileOffset: -1,
);
@@ -9,6 +9,7 @@ import 'package:_fe_analyzer_shared/src/testing/id.dart'
import 'package:_fe_analyzer_shared/src/testing/id_testing.dart'
show DataInterpreter, runTests;
import 'package:_fe_analyzer_shared/src/type_inference/assigned_variables.dart';
import 'package:front_end/src/kernel/internal_ast.dart';
import 'package:front_end/src/source/source_loader.dart';
import 'package:front_end/src/source/source_member_builder.dart';
import 'package:front_end/src/testing/id_testing_helper.dart';
@@ -50,10 +51,11 @@ class AssignedVariablesDataComputer extends CfeDataComputer<_Data> {
Map<Id, ActualData<_Data>> actualMap, {
bool? verbose,
}) {
SourceMemberBuilder memberBuilder =
lookupMemberBuilder(testResultData.compilerResult, member)
as SourceMemberBuilder;
AssignedVariablesForTesting<TreeNode, Variable>? assignedVariables =
SourceMemberBuilder memberBuilder = lookupMemberBuilder(
testResultData.compilerResult,
member,
) as SourceMemberBuilder;
AssignedVariablesForTesting<TreeNode, InternalVariable>? assignedVariables =
memberBuilder
.dataForTesting!
.inferenceData
@@ -72,7 +74,8 @@ class AssignedVariablesDataComputer extends CfeDataComputer<_Data> {
class AssignedVariablesDataExtractor extends CfeDataExtractor<_Data> {
final SourceLoaderDataForTesting _sourceLoaderDataForTesting;
final AssignedVariablesForTesting<TreeNode, Variable> _assignedVariables;
final AssignedVariablesForTesting<TreeNode, InternalVariable>
_assignedVariables;
new(
InternalCompilerResult compilerResult,
@@ -226,10 +226,16 @@ void _testVariableDeclarations() {
testStatement(
forest.variablesDeclaration([
new InternalVariableDeclaration(
new VariableDeclarationImpl('a', fileOffset: TreeNode.noOffset),
new InternalLegacyVariable(
astVariable: new LegacyVariable('a'),
fileOffset: TreeNode.noOffset,
),
),
new InternalVariableDeclaration(
new VariableDeclarationImpl('b', fileOffset: TreeNode.noOffset),
new InternalLegacyVariable(
astVariable: new LegacyVariable('b'),
fileOffset: TreeNode.noOffset,
),
),
], dummyUri),
'''
@@ -238,16 +244,14 @@ dynamic a, b;''',
testStatement(
forest.variablesDeclaration([
new InternalVariableDeclaration(
new VariableDeclarationImpl(
'a',
type: const VoidType(),
new InternalLegacyVariable(
astVariable: new LegacyVariable('a', type: const VoidType()),
fileOffset: TreeNode.noOffset,
),
),
new InternalVariableDeclaration(
new VariableDeclarationImpl(
'b',
initializer: new NullLiteral(),
new InternalLegacyVariable(
astVariable: new LegacyVariable('b', initializer: new NullLiteral()),
fileOffset: TreeNode.noOffset,
),
),
@@ -263,23 +267,35 @@ void _testTryStatement() {
Block returnBlock1 = new Block([new ReturnStatement()]);
Block returnBlock2 = new Block([new ReturnStatement()]);
InternalCatch emptyCatchBlock = new InternalCatch(
exception: new VariableDeclarationImpl('e', fileOffset: TreeNode.noOffset),
exception: new InternalLegacyVariable(
astVariable: new LegacyVariable('e'),
fileOffset: TreeNode.noOffset,
),
body: new Block([]),
fileOffset: TreeNode.noOffset,
);
InternalCatch emptyCatchBlockOnVoid = new InternalCatch(
exception: new VariableDeclarationImpl('e', fileOffset: TreeNode.noOffset),
exception: new InternalLegacyVariable(
astVariable: new LegacyVariable('e'),
fileOffset: TreeNode.noOffset,
),
body: new Block([]),
guard: const VoidType(),
fileOffset: TreeNode.noOffset,
);
InternalCatch returnCatchBlock = new InternalCatch(
exception: new VariableDeclarationImpl('e', fileOffset: TreeNode.noOffset),
exception: new InternalLegacyVariable(
astVariable: new LegacyVariable('e'),
fileOffset: TreeNode.noOffset,
),
body: new Block([new ReturnStatement()]),
fileOffset: TreeNode.noOffset,
);
InternalCatch returnCatchBlockOnVoid = new InternalCatch(
exception: new VariableDeclarationImpl('e', fileOffset: TreeNode.noOffset),
exception: new InternalLegacyVariable(
astVariable: new LegacyVariable('e'),
fileOffset: TreeNode.noOffset,
),
body: new Block([new ReturnStatement()]),
guard: const VoidType(),
fileOffset: TreeNode.noOffset,
@@ -393,7 +409,11 @@ void _testInternalForInStatement() {
new InternalForInStatement(
new SingleVariableDeclarationForInElement(
variableDeclaration: new InternalVariableDeclaration(
new VariableDeclarationImpl('e', fileOffset: -1),
new InternalLegacyVariable(
astVariable: new LegacyVariable('e'),
isImplicitlyTyped: true,
fileOffset: -1,
),
),
error: null,
),
@@ -411,9 +431,8 @@ for (var e in null) {}''',
new InternalForInStatement(
new SingleVariableDeclarationForInElement(
variableDeclaration: new InternalVariableDeclaration(
new VariableDeclarationImpl(
'e',
type: const VoidType(),
new InternalLegacyVariable(
astVariable: new LegacyVariable('e', type: const VoidType()),
fileOffset: -1,
),
),
@@ -436,16 +455,16 @@ for (void e in null) {}''',
patterns: [
new InternalVariablePattern(
type: const VoidType(),
variable: new VariableDeclarationImpl(
'a',
variable: new InternalLegacyVariable(
astVariable: new LegacyVariable('a'),
fileOffset: TreeNode.noOffset,
),
fileOffset: TreeNode.noOffset,
),
new InternalVariablePattern(
type: null,
variable: new VariableDeclarationImpl(
'b',
variable: new InternalLegacyVariable(
astVariable: new LegacyVariable('b'),
fileOffset: TreeNode.noOffset,
),
fileOffset: TreeNode.noOffset,
@@ -468,7 +487,10 @@ for (var (void a, var b) in null) {}''',
testStatement(
new InternalForInStatement(
new ExistingVariableForInElement(
variable: new VariableDeclarationImpl('a', fileOffset: -1),
variable: new InternalLegacyVariable(
astVariable: new LegacyVariable('a'),
fileOffset: -1,
),
nameOffset: -1,
inOffset: -1,
),
@@ -557,10 +579,18 @@ for (null in null) {}''',
new MultiVariableDeclarationForInElement(
variableDeclarations: [
new InternalVariableDeclaration(
new VariableDeclarationImpl('a', fileOffset: -1),
new InternalLegacyVariable(
astVariable: new LegacyVariable('a'),
isImplicitlyTyped: true,
fileOffset: -1,
),
),
new InternalVariableDeclaration(
new VariableDeclarationImpl('b', fileOffset: -1),
new InternalLegacyVariable(
astVariable: new LegacyVariable('b'),
isImplicitlyTyped: true,
fileOffset: -1,
),
),
],
error: new InvalidExpression('error'),
@@ -580,14 +610,16 @@ for (var a, b in null) {}''',
new MultiVariableDeclarationForInElement(
variableDeclarations: [
new InternalVariableDeclaration(
new VariableDeclarationImpl(
'a',
type: const VoidType(),
new InternalLegacyVariable(
astVariable: new LegacyVariable('a', type: const VoidType()),
fileOffset: -1,
),
),
new InternalVariableDeclaration(
new VariableDeclarationImpl('b', fileOffset: -1),
new InternalLegacyVariable(
astVariable: new LegacyVariable('b'),
fileOffset: -1,
),
),
],
error: new InvalidExpression('error'),
@@ -882,9 +914,10 @@ continue label0;''',
void _testCascade() {
// TODO(johnniwinther): Add better text representation support for internal
// synthetic variables.
InternalVariable variable = new VariableDeclarationImpl.forValue(
new IntLiteral(0),
)..name = '#0';
InternalVariable variable = new InternalLegacyVariable(
astVariable: new LegacyVariable.forValue(new IntLiteral(0))..name = '#0',
fileOffset: TreeNode.noOffset,
);
Cascade cascade = new Cascade(variable, isNullAware: false);
testExpression(cascade, '''
let final dynamic #0 = 0 in cascade {} => #0''');
@@ -933,8 +966,11 @@ void _testDeferredCheck() {
library,
'pre',
);
InternalVariable check = new VariableDeclarationImpl.forValue(
new CheckLibraryIsLoaded(dependency),
InternalVariable check = new InternalLegacyVariable(
astVariable: new LegacyVariable.forValue(
new CheckLibraryIsLoaded(dependency),
),
fileOffset: TreeNode.noOffset,
);
testExpression(
new DeferredCheck(check, new IntLiteral(0), fileOffset: TreeNode.noOffset),
@@ -1267,8 +1303,8 @@ const library test:dummy::Typedef<void>.foo(0, bar: 1)''',
void _testFunctionDeclarationImpl() {
testStatement(
new InternalFunctionDeclaration(
variable: new VariableDeclarationImpl(
'foo',
variable: new InternalLegacyVariable(
astVariable: new LegacyVariable('foo'),
fileOffset: TreeNode.noOffset,
),
fileOffset: TreeNode.noOffset,
@@ -1504,65 +1540,75 @@ return 0;''');
void _testVariableDeclarationImpl() {
testVariableDeclaration(
new VariableDeclarationImpl('foo', fileOffset: TreeNode.noOffset),
new InternalLegacyVariable(
astVariable: new LegacyVariable('foo'),
fileOffset: TreeNode.noOffset,
),
'''
dynamic foo''',
);
testVariableDeclaration(
new VariableDeclarationImpl(
'foo',
initializer: new IntLiteral(0),
new InternalLegacyVariable(
astVariable: new LegacyVariable('foo', initializer: new IntLiteral(0)),
fileOffset: TreeNode.noOffset,
),
'''
dynamic foo = 0''',
);
testVariableDeclaration(
new VariableDeclarationImpl(
'foo',
type: const VoidType(),
initializer: new IntLiteral(0),
isFinal: true,
isRequired: true,
new InternalLegacyVariable(
astVariable: new LegacyVariable(
'foo',
type: const VoidType(),
initializer: new IntLiteral(0),
isFinal: true,
isRequired: true,
),
fileOffset: TreeNode.noOffset,
),
'''
required final void foo''',
);
testVariableDeclaration(
new VariableDeclarationImpl(
'foo',
type: const VoidType(),
initializer: new IntLiteral(0),
isLate: true,
new InternalLegacyVariable(
astVariable: new LegacyVariable(
'foo',
type: const VoidType(),
initializer: new IntLiteral(0),
isLate: true,
),
fileOffset: TreeNode.noOffset,
),
'''
late void foo = 0''',
);
testVariableDeclaration(
new VariableDeclarationImpl(
'foo',
type: const VoidType(),
initializer: new IntLiteral(0),
new InternalLegacyVariable(
astVariable: new LegacyVariable(
'foo',
type: const VoidType(),
initializer: new IntLiteral(0),
),
fileOffset: TreeNode.noOffset,
)
..lateGetter = new VariableDeclarationImpl(
'foo#getter',
..lateGetter = new InternalLegacyVariable(
astVariable: new LegacyVariable('foo#getter'),
fileOffset: TreeNode.noOffset,
),
'''
late void foo = 0''',
);
testVariableDeclaration(
new VariableDeclarationImpl(
'foo',
type: const VoidType(),
initializer: new IntLiteral(0),
new InternalLegacyVariable(
astVariable: new LegacyVariable(
'foo',
type: const VoidType(),
initializer: new IntLiteral(0),
),
fileOffset: TreeNode.noOffset,
)
..lateGetter = new VariableDeclarationImpl(
'foo#getter',
..lateGetter = new InternalLegacyVariable(
astVariable: new LegacyVariable('foo#getter'),
fileOffset: TreeNode.noOffset,
)
..lateType = const DynamicType(),
@@ -1981,8 +2027,8 @@ void _testPropertyIncDec() {
}
void _testLocalIncDec() {
VariableDeclarationImpl variable = new VariableDeclarationImpl(
'foo',
InternalLegacyVariable variable = new InternalLegacyVariable(
astVariable: new LegacyVariable('foo'),
fileOffset: TreeNode.noOffset,
);
@@ -0,0 +1,61 @@
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Derived from tests/language/why_not_promoted/assignment_error_test.dart
abstract class C {
C? operator +(int i);
int get cProperty => 0;
}
direct_assignment(int? i, int? j) {
if (i == null) return;
i = j;
i.isEven;
}
compound_assignment(C? c, int i) {
if (c == null) return;
c += i;
c.cProperty;
}
via_postfix_op(C? c) {
if (c == null) return;
c++;
c.cProperty;
}
via_prefix_op(C? c) {
if (c == null) return;
++c;
c.cProperty;
}
via_for_each_statement(int? i, List<int?> list) {
if (i == null) return;
for (i in list) {
i.isEven;
}
}
via_for_each_list_element(int? i, List<int?> list) {
if (i == null) return;
[for (i in list) i.isEven];
}
via_for_each_set_element(int? i, List<int?> list) {
if (i == null) return;
({for (i in list) i.isEven});
}
via_for_each_map_key(int? i, List<int?> list) {
if (i == null) return;
({for (i in list) i.isEven: null});
}
via_for_each_map_value(int? i, List<int?> list) {
if (i == null) return;
({for (i in list) null: i.isEven});
}
@@ -0,0 +1,206 @@
library;
//
// Problems in library:
//
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:15:5: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
// Try accessing using ?. instead.
// i.isEven;
// ^^^^^^
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:14:3: Context: Variable 'i' could not be promoted due to an assignment.
// Try null checking the variable after the assignment. See http://dart.dev/go/non-promo-write
// i = j;
// ^
//
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:21:5: Error: Property 'cProperty' cannot be accessed on 'C?' because it is potentially null.
// - 'C' is from 'pkg/front_end/testcases/nnbd/why_not_promoted.dart'.
// Try accessing using ?. instead.
// c.cProperty;
// ^^^^^^^^^
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:20:3: Context: Variable 'c' could not be promoted due to an assignment.
// Try null checking the variable after the assignment. See http://dart.dev/go/non-promo-write
// c += i;
// ^
//
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:27:5: Error: Property 'cProperty' cannot be accessed on 'C?' because it is potentially null.
// - 'C' is from 'pkg/front_end/testcases/nnbd/why_not_promoted.dart'.
// Try accessing using ?. instead.
// c.cProperty;
// ^^^^^^^^^
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:26:3: Context: Variable 'c' could not be promoted due to an assignment.
// Try null checking the variable after the assignment. See http://dart.dev/go/non-promo-write
// c++;
// ^
//
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:33:5: Error: Property 'cProperty' cannot be accessed on 'C?' because it is potentially null.
// - 'C' is from 'pkg/front_end/testcases/nnbd/why_not_promoted.dart'.
// Try accessing using ?. instead.
// c.cProperty;
// ^^^^^^^^^
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:32:5: Context: Variable 'c' could not be promoted due to an assignment.
// Try null checking the variable after the assignment. See http://dart.dev/go/non-promo-write
// ++c;
// ^
//
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:39:7: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
// Try accessing using ?. instead.
// i.isEven;
// ^^^^^^
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:38:8: Context: Variable 'i' could not be promoted due to an assignment.
// Try null checking the variable after the assignment. See http://dart.dev/go/non-promo-write
// for (i in list) {
// ^
//
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:45:22: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
// Try accessing using ?. instead.
// [for (i in list) i.isEven];
// ^^^^^^
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:45:9: Context: Variable 'i' could not be promoted due to an assignment.
// Try null checking the variable after the assignment. See http://dart.dev/go/non-promo-write
// [for (i in list) i.isEven];
// ^
//
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:50:23: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
// Try accessing using ?. instead.
// ({for (i in list) i.isEven});
// ^^^^^^
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:50:10: Context: Variable 'i' could not be promoted due to an assignment.
// Try null checking the variable after the assignment. See http://dart.dev/go/non-promo-write
// ({for (i in list) i.isEven});
// ^
//
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:55:23: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
// Try accessing using ?. instead.
// ({for (i in list) i.isEven: null});
// ^^^^^^
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:55:10: Context: Variable 'i' could not be promoted due to an assignment.
// Try null checking the variable after the assignment. See http://dart.dev/go/non-promo-write
// ({for (i in list) i.isEven: null});
// ^
//
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:60:29: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
// Try accessing using ?. instead.
// ({for (i in list) null: i.isEven});
// ^^^^^^
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:60:10: Context: Variable 'i' could not be promoted due to an assignment.
// Try null checking the variable after the assignment. See http://dart.dev/go/non-promo-write
// ({for (i in list) null: i.isEven});
// ^
//
import self as self;
import "dart:core" as core;
import "dart:collection" as col;
abstract class C extends core::Object {
synthetic constructor •() → self::C
: super core::Object::•()
;
abstract operator +(core::int i) → self::C?;
get cProperty() → core::int
return 0;
}
static method direct_assignment(core::int? i, core::int? j) → dynamic {
if(i == null)
return;
i = j;
invalid-expression "pkg/front_end/testcases/nnbd/why_not_promoted.dart:15:5: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
Try accessing using ?. instead.
i.isEven;
^^^^^^" in i.{core::int::isEven}{<nullable>}.{core::bool};
}
static method compound_assignment(self::C? c, core::int i) → dynamic {
if(c == null)
return;
c = c{self::C}.{self::C::+}(i){(core::int) → self::C?};
invalid-expression "pkg/front_end/testcases/nnbd/why_not_promoted.dart:21:5: Error: Property 'cProperty' cannot be accessed on 'C?' because it is potentially null.
- 'C' is from 'pkg/front_end/testcases/nnbd/why_not_promoted.dart'.
Try accessing using ?. instead.
c.cProperty;
^^^^^^^^^" in c.{self::C::cProperty}{<nullable>}.{core::int};
}
static method via_postfix_op(self::C? c) → dynamic {
if(c == null)
return;
c = c{self::C}.{self::C::+}(1){(core::int) → self::C?};
invalid-expression "pkg/front_end/testcases/nnbd/why_not_promoted.dart:27:5: Error: Property 'cProperty' cannot be accessed on 'C?' because it is potentially null.
- 'C' is from 'pkg/front_end/testcases/nnbd/why_not_promoted.dart'.
Try accessing using ?. instead.
c.cProperty;
^^^^^^^^^" in c.{self::C::cProperty}{<nullable>}.{core::int};
}
static method via_prefix_op(self::C? c) → dynamic {
if(c == null)
return;
c = c{self::C}.{self::C::+}(1){(core::int) → self::C?};
invalid-expression "pkg/front_end/testcases/nnbd/why_not_promoted.dart:33:5: Error: Property 'cProperty' cannot be accessed on 'C?' because it is potentially null.
- 'C' is from 'pkg/front_end/testcases/nnbd/why_not_promoted.dart'.
Try accessing using ?. instead.
c.cProperty;
^^^^^^^^^" in c.{self::C::cProperty}{<nullable>}.{core::int};
}
static method via_for_each_statement(core::int? i, core::List<core::int?> list) → dynamic {
if(i == null)
return;
for (final core::int? #t1 in list) {
i = #t1;
invalid-expression "pkg/front_end/testcases/nnbd/why_not_promoted.dart:39:7: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
Try accessing using ?. instead.
i.isEven;
^^^^^^" in i.{core::int::isEven}{<nullable>}.{core::bool};
}
}
static method via_for_each_list_element(core::int? i, core::List<core::int?> list) → dynamic {
if(i == null)
return;
{
final core::List<core::bool> #t2 = <core::bool>[];
for (final core::int? #t3 in list) {
i = #t3;
#t2.{core::List::add}{Invariant}(invalid-expression "pkg/front_end/testcases/nnbd/why_not_promoted.dart:45:22: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
Try accessing using ?. instead.
[for (i in list) i.isEven];
^^^^^^" in i.{core::int::isEven}{<nullable>}.{core::bool}){(core::bool) → void};
}
}
}
static method via_for_each_set_element(core::int? i, core::List<core::int?> list) → dynamic {
if(i == null)
return;
{
final core::Set<core::bool> #t4 = col::LinkedHashSet::•<core::bool>();
for (final core::int? #t5 in list) {
i = #t5;
#t4.{core::Set::add}{Invariant}(invalid-expression "pkg/front_end/testcases/nnbd/why_not_promoted.dart:50:23: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
Try accessing using ?. instead.
({for (i in list) i.isEven});
^^^^^^" in i.{core::int::isEven}{<nullable>}.{core::bool}){(core::bool) → core::bool};
}
}
}
static method via_for_each_map_key(core::int? i, core::List<core::int?> list) → dynamic {
if(i == null)
return;
{
final core::Map<core::bool, Null> #t6 = <core::bool, Null>{};
for (final core::int? #t7 in list) {
i = #t7;
#t6.{core::Map::[]=}{Invariant}(invalid-expression "pkg/front_end/testcases/nnbd/why_not_promoted.dart:55:23: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
Try accessing using ?. instead.
({for (i in list) i.isEven: null});
^^^^^^" in i.{core::int::isEven}{<nullable>}.{core::bool}, null){(core::bool, Null) → void};
}
}
}
static method via_for_each_map_value(core::int? i, core::List<core::int?> list) → dynamic {
if(i == null)
return;
{
final core::Map<Null, core::bool> #t8 = <Null, core::bool>{};
for (final core::int? #t9 in list) {
i = #t9;
#t8.{core::Map::[]=}{Invariant}(null, invalid-expression "pkg/front_end/testcases/nnbd/why_not_promoted.dart:60:29: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
Try accessing using ?. instead.
({for (i in list) null: i.isEven});
^^^^^^" in i.{core::int::isEven}{<nullable>}.{core::bool}){(Null, core::bool) → void};
}
}
}
@@ -0,0 +1,206 @@
library;
//
// Problems in library:
//
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:15:5: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
// Try accessing using ?. instead.
// i.isEven;
// ^^^^^^
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:14:3: Context: Variable 'i' could not be promoted due to an assignment.
// Try null checking the variable after the assignment. See http://dart.dev/go/non-promo-write
// i = j;
// ^
//
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:21:5: Error: Property 'cProperty' cannot be accessed on 'C?' because it is potentially null.
// - 'C' is from 'pkg/front_end/testcases/nnbd/why_not_promoted.dart'.
// Try accessing using ?. instead.
// c.cProperty;
// ^^^^^^^^^
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:20:3: Context: Variable 'c' could not be promoted due to an assignment.
// Try null checking the variable after the assignment. See http://dart.dev/go/non-promo-write
// c += i;
// ^
//
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:27:5: Error: Property 'cProperty' cannot be accessed on 'C?' because it is potentially null.
// - 'C' is from 'pkg/front_end/testcases/nnbd/why_not_promoted.dart'.
// Try accessing using ?. instead.
// c.cProperty;
// ^^^^^^^^^
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:26:3: Context: Variable 'c' could not be promoted due to an assignment.
// Try null checking the variable after the assignment. See http://dart.dev/go/non-promo-write
// c++;
// ^
//
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:33:5: Error: Property 'cProperty' cannot be accessed on 'C?' because it is potentially null.
// - 'C' is from 'pkg/front_end/testcases/nnbd/why_not_promoted.dart'.
// Try accessing using ?. instead.
// c.cProperty;
// ^^^^^^^^^
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:32:5: Context: Variable 'c' could not be promoted due to an assignment.
// Try null checking the variable after the assignment. See http://dart.dev/go/non-promo-write
// ++c;
// ^
//
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:39:7: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
// Try accessing using ?. instead.
// i.isEven;
// ^^^^^^
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:38:8: Context: Variable 'i' could not be promoted due to an assignment.
// Try null checking the variable after the assignment. See http://dart.dev/go/non-promo-write
// for (i in list) {
// ^
//
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:45:22: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
// Try accessing using ?. instead.
// [for (i in list) i.isEven];
// ^^^^^^
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:45:9: Context: Variable 'i' could not be promoted due to an assignment.
// Try null checking the variable after the assignment. See http://dart.dev/go/non-promo-write
// [for (i in list) i.isEven];
// ^
//
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:50:23: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
// Try accessing using ?. instead.
// ({for (i in list) i.isEven});
// ^^^^^^
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:50:10: Context: Variable 'i' could not be promoted due to an assignment.
// Try null checking the variable after the assignment. See http://dart.dev/go/non-promo-write
// ({for (i in list) i.isEven});
// ^
//
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:55:23: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
// Try accessing using ?. instead.
// ({for (i in list) i.isEven: null});
// ^^^^^^
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:55:10: Context: Variable 'i' could not be promoted due to an assignment.
// Try null checking the variable after the assignment. See http://dart.dev/go/non-promo-write
// ({for (i in list) i.isEven: null});
// ^
//
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:60:29: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
// Try accessing using ?. instead.
// ({for (i in list) null: i.isEven});
// ^^^^^^
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:60:10: Context: Variable 'i' could not be promoted due to an assignment.
// Try null checking the variable after the assignment. See http://dart.dev/go/non-promo-write
// ({for (i in list) null: i.isEven});
// ^
//
import self as self;
import "dart:core" as core;
import "dart:collection" as col;
abstract class C extends core::Object {
synthetic constructor •() → self::C
: super core::Object::•()
;
abstract operator +(core::int i) → self::C?;
get cProperty() → core::int
return 0;
}
static method direct_assignment(core::int? i, core::int? j) → dynamic {
if(i == null)
return;
i = j;
invalid-expression "pkg/front_end/testcases/nnbd/why_not_promoted.dart:15:5: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
Try accessing using ?. instead.
i.isEven;
^^^^^^" in i.{core::int::isEven}{<nullable>}.{core::bool};
}
static method compound_assignment(self::C? c, core::int i) → dynamic {
if(c == null)
return;
c = c{self::C}.{self::C::+}(i){(core::int) → self::C?};
invalid-expression "pkg/front_end/testcases/nnbd/why_not_promoted.dart:21:5: Error: Property 'cProperty' cannot be accessed on 'C?' because it is potentially null.
- 'C' is from 'pkg/front_end/testcases/nnbd/why_not_promoted.dart'.
Try accessing using ?. instead.
c.cProperty;
^^^^^^^^^" in c.{self::C::cProperty}{<nullable>}.{core::int};
}
static method via_postfix_op(self::C? c) → dynamic {
if(c == null)
return;
c = c{self::C}.{self::C::+}(1){(core::int) → self::C?};
invalid-expression "pkg/front_end/testcases/nnbd/why_not_promoted.dart:27:5: Error: Property 'cProperty' cannot be accessed on 'C?' because it is potentially null.
- 'C' is from 'pkg/front_end/testcases/nnbd/why_not_promoted.dart'.
Try accessing using ?. instead.
c.cProperty;
^^^^^^^^^" in c.{self::C::cProperty}{<nullable>}.{core::int};
}
static method via_prefix_op(self::C? c) → dynamic {
if(c == null)
return;
c = c{self::C}.{self::C::+}(1){(core::int) → self::C?};
invalid-expression "pkg/front_end/testcases/nnbd/why_not_promoted.dart:33:5: Error: Property 'cProperty' cannot be accessed on 'C?' because it is potentially null.
- 'C' is from 'pkg/front_end/testcases/nnbd/why_not_promoted.dart'.
Try accessing using ?. instead.
c.cProperty;
^^^^^^^^^" in c.{self::C::cProperty}{<nullable>}.{core::int};
}
static method via_for_each_statement(core::int? i, core::List<core::int?> list) → dynamic {
if(i == null)
return;
for (final core::int? #t1 in list) {
i = #t1;
invalid-expression "pkg/front_end/testcases/nnbd/why_not_promoted.dart:39:7: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
Try accessing using ?. instead.
i.isEven;
^^^^^^" in i.{core::int::isEven}{<nullable>}.{core::bool};
}
}
static method via_for_each_list_element(core::int? i, core::List<core::int?> list) → dynamic {
if(i == null)
return;
{
final core::List<core::bool> #t2 = <core::bool>[];
for (final core::int? #t3 in list) {
i = #t3;
#t2.{core::List::add}{Invariant}(invalid-expression "pkg/front_end/testcases/nnbd/why_not_promoted.dart:45:22: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
Try accessing using ?. instead.
[for (i in list) i.isEven];
^^^^^^" in i.{core::int::isEven}{<nullable>}.{core::bool}){(core::bool) → void};
}
}
}
static method via_for_each_set_element(core::int? i, core::List<core::int?> list) → dynamic {
if(i == null)
return;
{
final core::Set<core::bool> #t4 = col::LinkedHashSet::•<core::bool>();
for (final core::int? #t5 in list) {
i = #t5;
#t4.{core::Set::add}{Invariant}(invalid-expression "pkg/front_end/testcases/nnbd/why_not_promoted.dart:50:23: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
Try accessing using ?. instead.
({for (i in list) i.isEven});
^^^^^^" in i.{core::int::isEven}{<nullable>}.{core::bool}){(core::bool) → core::bool};
}
}
}
static method via_for_each_map_key(core::int? i, core::List<core::int?> list) → dynamic {
if(i == null)
return;
{
final core::Map<core::bool, Null> #t6 = <core::bool, Null>{};
for (final core::int? #t7 in list) {
i = #t7;
#t6.{core::Map::[]=}{Invariant}(invalid-expression "pkg/front_end/testcases/nnbd/why_not_promoted.dart:55:23: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
Try accessing using ?. instead.
({for (i in list) i.isEven: null});
^^^^^^" in i.{core::int::isEven}{<nullable>}.{core::bool}, null){(core::bool, Null) → void};
}
}
}
static method via_for_each_map_value(core::int? i, core::List<core::int?> list) → dynamic {
if(i == null)
return;
{
final core::Map<Null, core::bool> #t8 = <Null, core::bool>{};
for (final core::int? #t9 in list) {
i = #t9;
#t8.{core::Map::[]=}{Invariant}(null, invalid-expression "pkg/front_end/testcases/nnbd/why_not_promoted.dart:60:29: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
Try accessing using ?. instead.
({for (i in list) null: i.isEven});
^^^^^^" in i.{core::int::isEven}{<nullable>}.{core::bool}){(Null, core::bool) → void};
}
}
}
@@ -0,0 +1,29 @@
library;
import self as self;
import "dart:core" as core;
abstract class C extends core::Object {
synthetic constructor •() → self::C
;
abstract operator +(core::int i) → self::C?;
get cProperty() → core::int
;
}
static method direct_assignment(core::int? i, core::int? j) → dynamic
;
static method compound_assignment(self::C? c, core::int i) → dynamic
;
static method via_postfix_op(self::C? c) → dynamic
;
static method via_prefix_op(self::C? c) → dynamic
;
static method via_for_each_statement(core::int? i, core::List<core::int?> list) → dynamic
;
static method via_for_each_list_element(core::int? i, core::List<core::int?> list) → dynamic
;
static method via_for_each_set_element(core::int? i, core::List<core::int?> list) → dynamic
;
static method via_for_each_map_key(core::int? i, core::List<core::int?> list) → dynamic
;
static method via_for_each_map_value(core::int? i, core::List<core::int?> list) → dynamic
;
@@ -0,0 +1,236 @@
library;
//
// Problems in library:
//
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:15:5: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
// Try accessing using ?. instead.
// i.isEven;
// ^^^^^^
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:14:3: Context: Variable 'i' could not be promoted due to an assignment.
// Try null checking the variable after the assignment. See http://dart.dev/go/non-promo-write
// i = j;
// ^
//
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:21:5: Error: Property 'cProperty' cannot be accessed on 'C?' because it is potentially null.
// - 'C' is from 'pkg/front_end/testcases/nnbd/why_not_promoted.dart'.
// Try accessing using ?. instead.
// c.cProperty;
// ^^^^^^^^^
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:20:3: Context: Variable 'c' could not be promoted due to an assignment.
// Try null checking the variable after the assignment. See http://dart.dev/go/non-promo-write
// c += i;
// ^
//
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:27:5: Error: Property 'cProperty' cannot be accessed on 'C?' because it is potentially null.
// - 'C' is from 'pkg/front_end/testcases/nnbd/why_not_promoted.dart'.
// Try accessing using ?. instead.
// c.cProperty;
// ^^^^^^^^^
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:26:3: Context: Variable 'c' could not be promoted due to an assignment.
// Try null checking the variable after the assignment. See http://dart.dev/go/non-promo-write
// c++;
// ^
//
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:33:5: Error: Property 'cProperty' cannot be accessed on 'C?' because it is potentially null.
// - 'C' is from 'pkg/front_end/testcases/nnbd/why_not_promoted.dart'.
// Try accessing using ?. instead.
// c.cProperty;
// ^^^^^^^^^
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:32:5: Context: Variable 'c' could not be promoted due to an assignment.
// Try null checking the variable after the assignment. See http://dart.dev/go/non-promo-write
// ++c;
// ^
//
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:39:7: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
// Try accessing using ?. instead.
// i.isEven;
// ^^^^^^
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:38:8: Context: Variable 'i' could not be promoted due to an assignment.
// Try null checking the variable after the assignment. See http://dart.dev/go/non-promo-write
// for (i in list) {
// ^
//
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:45:22: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
// Try accessing using ?. instead.
// [for (i in list) i.isEven];
// ^^^^^^
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:45:9: Context: Variable 'i' could not be promoted due to an assignment.
// Try null checking the variable after the assignment. See http://dart.dev/go/non-promo-write
// [for (i in list) i.isEven];
// ^
//
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:50:23: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
// Try accessing using ?. instead.
// ({for (i in list) i.isEven});
// ^^^^^^
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:50:10: Context: Variable 'i' could not be promoted due to an assignment.
// Try null checking the variable after the assignment. See http://dart.dev/go/non-promo-write
// ({for (i in list) i.isEven});
// ^
//
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:55:23: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
// Try accessing using ?. instead.
// ({for (i in list) i.isEven: null});
// ^^^^^^
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:55:10: Context: Variable 'i' could not be promoted due to an assignment.
// Try null checking the variable after the assignment. See http://dart.dev/go/non-promo-write
// ({for (i in list) i.isEven: null});
// ^
//
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:60:29: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
// Try accessing using ?. instead.
// ({for (i in list) null: i.isEven});
// ^^^^^^
// pkg/front_end/testcases/nnbd/why_not_promoted.dart:60:10: Context: Variable 'i' could not be promoted due to an assignment.
// Try null checking the variable after the assignment. See http://dart.dev/go/non-promo-write
// ({for (i in list) null: i.isEven});
// ^
//
import self as self;
import "dart:core" as core;
import "dart:_compact_hash" as _co;
abstract class C extends core::Object {
synthetic constructor •() → self::C
: super core::Object::•()
;
abstract operator +(core::int i) → self::C?;
get cProperty() → core::int
return 0;
}
static method direct_assignment(core::int? i, core::int? j) → dynamic {
if(i == null)
return;
i = j;
invalid-expression "pkg/front_end/testcases/nnbd/why_not_promoted.dart:15:5: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
Try accessing using ?. instead.
i.isEven;
^^^^^^" in i.{core::int::isEven}{<nullable>}.{core::bool};
}
static method compound_assignment(self::C? c, core::int i) → dynamic {
if(c == null)
return;
c = c{self::C}.{self::C::+}(i){(core::int) → self::C?};
invalid-expression "pkg/front_end/testcases/nnbd/why_not_promoted.dart:21:5: Error: Property 'cProperty' cannot be accessed on 'C?' because it is potentially null.
- 'C' is from 'pkg/front_end/testcases/nnbd/why_not_promoted.dart'.
Try accessing using ?. instead.
c.cProperty;
^^^^^^^^^" in c.{self::C::cProperty}{<nullable>}.{core::int};
}
static method via_postfix_op(self::C? c) → dynamic {
if(c == null)
return;
c = c{self::C}.{self::C::+}(1){(core::int) → self::C?};
invalid-expression "pkg/front_end/testcases/nnbd/why_not_promoted.dart:27:5: Error: Property 'cProperty' cannot be accessed on 'C?' because it is potentially null.
- 'C' is from 'pkg/front_end/testcases/nnbd/why_not_promoted.dart'.
Try accessing using ?. instead.
c.cProperty;
^^^^^^^^^" in c.{self::C::cProperty}{<nullable>}.{core::int};
}
static method via_prefix_op(self::C? c) → dynamic {
if(c == null)
return;
c = c{self::C}.{self::C::+}(1){(core::int) → self::C?};
invalid-expression "pkg/front_end/testcases/nnbd/why_not_promoted.dart:33:5: Error: Property 'cProperty' cannot be accessed on 'C?' because it is potentially null.
- 'C' is from 'pkg/front_end/testcases/nnbd/why_not_promoted.dart'.
Try accessing using ?. instead.
c.cProperty;
^^^^^^^^^" in c.{self::C::cProperty}{<nullable>}.{core::int};
}
static method via_for_each_statement(core::int? i, core::List<core::int?> list) → dynamic {
if(i == null)
return;
{
synthesized core::Iterator<core::int?> :sync-for-iterator = list.{core::Iterable::iterator}{core::Iterator<core::int?>};
for (; :sync-for-iterator.{core::Iterator::moveNext}(){() → core::bool}; ) {
final core::int? #t1 = :sync-for-iterator.{core::Iterator::current}{core::int?};
{
i = #t1;
invalid-expression "pkg/front_end/testcases/nnbd/why_not_promoted.dart:39:7: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
Try accessing using ?. instead.
i.isEven;
^^^^^^" in i.{core::int::isEven}{<nullable>}.{core::bool};
}
}
}
}
static method via_for_each_list_element(core::int? i, core::List<core::int?> list) → dynamic {
if(i == null)
return;
{
final core::List<core::bool> #t2 = core::_GrowableList::•<core::bool>(0);
{
synthesized core::Iterator<core::int?> :sync-for-iterator = list.{core::Iterable::iterator}{core::Iterator<core::int?>};
for (; :sync-for-iterator.{core::Iterator::moveNext}(){() → core::bool}; ) {
final core::int? #t3 = :sync-for-iterator.{core::Iterator::current}{core::int?};
{
i = #t3;
#t2.{core::List::add}{Invariant}(invalid-expression "pkg/front_end/testcases/nnbd/why_not_promoted.dart:45:22: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
Try accessing using ?. instead.
[for (i in list) i.isEven];
^^^^^^" in i.{core::int::isEven}{<nullable>}.{core::bool}){(core::bool) → void};
}
}
}
}
}
static method via_for_each_set_element(core::int? i, core::List<core::int?> list) → dynamic {
if(i == null)
return;
{
final core::Set<core::bool> #t4 = new _co::_Set::•<core::bool>();
{
synthesized core::Iterator<core::int?> :sync-for-iterator = list.{core::Iterable::iterator}{core::Iterator<core::int?>};
for (; :sync-for-iterator.{core::Iterator::moveNext}(){() → core::bool}; ) {
final core::int? #t5 = :sync-for-iterator.{core::Iterator::current}{core::int?};
{
i = #t5;
#t4.{core::Set::add}{Invariant}(invalid-expression "pkg/front_end/testcases/nnbd/why_not_promoted.dart:50:23: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
Try accessing using ?. instead.
({for (i in list) i.isEven});
^^^^^^" in i.{core::int::isEven}{<nullable>}.{core::bool}){(core::bool) → core::bool};
}
}
}
}
}
static method via_for_each_map_key(core::int? i, core::List<core::int?> list) → dynamic {
if(i == null)
return;
{
final core::Map<core::bool, Null> #t6 = <core::bool, Null>{};
{
synthesized core::Iterator<core::int?> :sync-for-iterator = list.{core::Iterable::iterator}{core::Iterator<core::int?>};
for (; :sync-for-iterator.{core::Iterator::moveNext}(){() → core::bool}; ) {
final core::int? #t7 = :sync-for-iterator.{core::Iterator::current}{core::int?};
{
i = #t7;
#t6.{core::Map::[]=}{Invariant}(invalid-expression "pkg/front_end/testcases/nnbd/why_not_promoted.dart:55:23: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
Try accessing using ?. instead.
({for (i in list) i.isEven: null});
^^^^^^" in i.{core::int::isEven}{<nullable>}.{core::bool}, null){(core::bool, Null) → void};
}
}
}
}
}
static method via_for_each_map_value(core::int? i, core::List<core::int?> list) → dynamic {
if(i == null)
return;
{
final core::Map<Null, core::bool> #t8 = <Null, core::bool>{};
{
synthesized core::Iterator<core::int?> :sync-for-iterator = list.{core::Iterable::iterator}{core::Iterator<core::int?>};
for (; :sync-for-iterator.{core::Iterator::moveNext}(){() → core::bool}; ) {
final core::int? #t9 = :sync-for-iterator.{core::Iterator::current}{core::int?};
{
i = #t9;
#t8.{core::Map::[]=}{Invariant}(null, invalid-expression "pkg/front_end/testcases/nnbd/why_not_promoted.dart:60:29: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
Try accessing using ?. instead.
({for (i in list) null: i.isEven});
^^^^^^" in i.{core::int::isEven}{<nullable>}.{core::bool}){(Null, core::bool) → void};
}
}
}
}
}
@@ -0,0 +1,22 @@
abstract class C {
C? operator +(int i);
int get cProperty => 0;
}
direct_assignment(int? i, int? j) {}
compound_assignment(C? c, int i) {}
via_postfix_op(C? c) {}
via_prefix_op(C? c) {}
via_for_each_statement(int? i, List<int?> list) {}
via_for_each_list_element(int? i, List<int?> list) {}
via_for_each_set_element(int? i, List<int?> list) {}
via_for_each_map_key(int? i, List<int?> list) {}
via_for_each_map_value(int? i, List<int?> list) {}
@@ -0,0 +1,22 @@
abstract class C {
C? operator +(int i);
int get cProperty => 0;
}
compound_assignment(C? c, int i) {}
direct_assignment(int? i, int? j) {}
via_for_each_list_element(int? i, List<int?> list) {}
via_for_each_map_key(int? i, List<int?> list) {}
via_for_each_map_value(int? i, List<int?> list) {}
via_for_each_set_element(int? i, List<int?> list) {}
via_for_each_statement(int? i, List<int?> list) {}
via_postfix_op(C? c) {}
via_prefix_op(C? c) {}
+2 -1
View File
@@ -147,7 +147,7 @@ type CanonicalName {
type ComponentFile {
UInt32 magic = 0x90ABCDEF;
UInt32 formatVersion = 131;
UInt32 formatVersion = 132;
Byte[10] shortSdkHash;
List<String> problemsAsJson; // Described in problems.md.
Library[] libraries;
@@ -1743,6 +1743,7 @@ type AssignedVariablePattern extends Pattern {
Byte tag = 129;
FileOffset fileOffset;
VariableReference variable;
Option<VariableReference> setter;
Option<DartType> matchedType;
Byte needsCast;
}
+7 -1
View File
@@ -2237,6 +2237,10 @@ class BinaryBuilder {
variableStack.addAll(variables);
}
Variable? readVariableReferenceOption() {
return readAndCheckOptionTag() ? readVariableReference() : null;
}
Variable readVariableReference() {
readUInt30(); // offset of the variable declaration in the binary.
return _readVariableReferenceInternal();
@@ -3311,12 +3315,14 @@ class BinaryBuilder {
AssignedVariablePattern _readAssignedVariablePattern() {
int fileOffset = readOffset();
Variable variable = readVariableReference();
Variable? setter = readVariableReferenceOption();
DartType? matchedType = readDartTypeOption();
bool needsCheck = readByte() == 1;
return AssignedVariablePattern(variable)
..fileOffset = fileOffset
..matchedValueType = matchedType
..needsCast = needsCheck;
..needsCast = needsCheck
..setter = setter;
}
CastPattern _readCastPattern() {
+10
View File
@@ -2864,6 +2864,15 @@ class BinaryPrinter
writeNode(node.receiver);
}
void _writeVariableReferenceOption(Variable? variable) {
if (variable == null) {
writeByte(Tag.Nothing);
} else {
writeByte(Tag.Something);
_writeVariableReference(variable);
}
}
void _writeVariableReference(Variable variable) {
int index = _getVariableIndex(variable);
writeUInt30(variable.binaryOffsetNoTag);
@@ -2883,6 +2892,7 @@ class BinaryPrinter
writeByte(Tag.AssignedVariablePattern);
writeOffset(node.fileOffset);
_writeVariableReference(node.variable);
_writeVariableReferenceOption(node.setter);
writeOptionalNode(node.matchedValueType);
writeByte(node.needsCast ? 1 : 0);
}
+1 -1
View File
@@ -237,7 +237,7 @@ class Tag {
/// Internal version of kernel binary format.
/// Bump it when making incompatible changes in kernel binaries.
/// Keep in sync with runtime/vm/kernel_binary.h, pkg/kernel/binary.md.
static const int BinaryFormatVersion = 131;
static const int BinaryFormatVersion = 132;
}
abstract class ConstantTag {
+4
View File
@@ -871,6 +871,10 @@ class WildcardPattern extends Pattern {
class AssignedVariablePattern extends Pattern {
final Variable variable;
/// If [variable] is a lowered late variable, [setter] holds the variable of
/// the local function that should be used for assignment.
Variable? setter;
/// The type of the expression against which this pattern is matched.
///
/// This is set during inference.
+11
View File
@@ -4996,6 +4996,9 @@ class EquivalenceStrategy {
if (!checkAssignedVariablePattern_variable(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkAssignedVariablePattern_setter(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkAssignedVariablePattern_matchedValueType(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
@@ -11972,6 +11975,14 @@ class EquivalenceStrategy {
return visitor.checkNodes(node.variable, other.variable, 'variable');
}
bool checkAssignedVariablePattern_setter(
EquivalenceVisitor visitor,
AssignedVariablePattern node,
AssignedVariablePattern other,
) {
return visitor.checkNodes(node.setter, other.setter, 'setter');
}
bool checkAssignedVariablePattern_matchedValueType(
EquivalenceVisitor visitor,
AssignedVariablePattern node,
@@ -12,13 +12,13 @@ RESULT: t3
%this = _Parameter #0 [_T (#lib::C)+]
%x = _Parameter #1
t2 = _Extract (%this[#lib::C/0])
t3 = _TypeCheck (%x against t2) (for #lib::C.T% x)
t3 = _TypeCheck (%x against t2) (for #lib::C.T% x;)
RESULT: t3
------------ C.id2 ------------
%this = _Parameter #0 [_T (#lib::C)+]
%x = _Parameter #1
t2 = _Extract (%this[#lib::C/0])
t3 = _TypeCheck (%x against t2) (for #lib::C.T% x)
t3 = _TypeCheck (%x against t2) (for #lib::C.T% x;)
RESULT: t3
------------ D. ------------
%this = _Parameter #0 [_T (#lib::D)+]
@@ -77,7 +77,7 @@ RESULT: _T {}
%x = _Parameter #1
t2 = _Extract (%this[#lib::C2/0])
t3 = _CreateRuntimeType (dart.core::Comparable @ (t2))
t4 = _TypeCheck (%x against t3) (for dart.core::Comparable<#lib::C2.T%> x)
t4 = _TypeCheck (%x against t3) (for dart.core::Comparable<#lib::C2.T%> x;)
RESULT: t4
------------ C2.id4 ------------
%this = _Parameter #0 [_T (#lib::C2)+]
@@ -85,7 +85,7 @@ RESULT: t4
t2 = _Extract (%this[#lib::C2/0])
t3 = _CreateRuntimeType (#lib::I @ (t2))
t4 = _CreateRuntimeType (#lib::K @ (t3))
t5 = _TypeCheck (%x against t4) (for #lib::K<#lib::I<#lib::C2.T%>> x)
t5 = _TypeCheck (%x against t4) (for #lib::K<#lib::I<#lib::C2.T%>> x;)
RESULT: t5
------------ main ------------
t0* = _Call direct [#lib::C.] (_T (#lib::C<dart.core::int>))
@@ -17,9 +17,9 @@ RESULT: _T {}
%key = _Parameter #1
%value = _Parameter #2
t3 = _Extract (%this[#lib::_NotRealHashMap/0])
t4 = _TypeCheck (%key against t3) (for #lib::_NotRealHashMap.K% key)
t4 = _TypeCheck (%key against t3) (for #lib::_NotRealHashMap.K% key;)
t5 = _Extract (%this[#lib::_NotRealHashMap/1])
t6 = _TypeCheck (%value against t5) (for #lib::_NotRealHashMap.V% value)
t6 = _TypeCheck (%value against t5) (for #lib::_NotRealHashMap.V% value;)
RESULT: _T {}?
------------ InheritedElement. ------------
%this = _Parameter #0 [_T (#lib::InheritedElement)+]
+1 -1
View File
@@ -18,7 +18,7 @@ namespace kernel {
// package:kernel/binary.md.
static const uint32_t kMagicProgramFile = 0x90ABCDEFu;
static const uint32_t kSupportedKernelFormatVersion = 131;
static const uint32_t kSupportedKernelFormatVersion = 132;
// Keep in sync with package:kernel/lib/binary/tag.dart
#define KERNEL_TAG_LIST(V) \