diff --git a/pkg/front_end/lib/src/fragment/enum_element.dart b/pkg/front_end/lib/src/fragment/enum_element.dart index 6deda5e9561..d5ca1eb0aa6 100644 --- a/pkg/front_end/lib/src/fragment/enum_element.dart +++ b/pkg/front_end/lib/src/fragment/enum_element.dart @@ -428,7 +428,7 @@ class EnumElementDeclaration fieldType = inferredFieldType; } - (DartType, Expression?) _computeType( + (DartType, Expression?, ScopeProviderInfo?) _computeType( ClassHierarchyBase hierarchy, Token? token, ) { @@ -441,12 +441,16 @@ class EnumElementDeclaration libraryBuilder.loader.coreTypes, token, ); - return (fieldType, _field!.initializer); + return (fieldType, _field!.initializer, null); } @override // Coverage-ignore(suite): Not run. - void buildBody(CoreTypes coreTypes, Expression? initializer) { + void buildBody( + CoreTypes coreTypes, + Expression? initializer, { + required ScopeProviderInfo? scopeProviderInfo, + }) { // Initializer has already been created through [_buildElement]. } diff --git a/pkg/front_end/lib/src/fragment/field/declaration.dart b/pkg/front_end/lib/src/fragment/field/declaration.dart index 48341a1966e..8d083965610 100644 --- a/pkg/front_end/lib/src/fragment/field/declaration.dart +++ b/pkg/front_end/lib/src/fragment/field/declaration.dart @@ -34,7 +34,7 @@ import '../../source/source_library_builder.dart'; import '../../source/source_member_builder.dart'; import '../../source/source_property_builder.dart'; import '../../source/type_parameter_factory.dart'; -import '../../type_inference/inference_results.dart'; +import '../../type_inference/context_allocation_strategy.dart'; import '../../type_inference/type_inference_engine.dart'; import '../../type_inference/type_inferrer.dart'; import '../../util/helpers.dart'; @@ -285,7 +285,11 @@ class RegularFieldDeclaration InferenceDefaultType get inferenceDefaultType => InferenceDefaultType.Dynamic; @override - void buildBody(CoreTypes coreTypes, Expression? initializer) { + void buildBody( + CoreTypes coreTypes, + Expression? initializer, { + required ScopeProviderInfo? scopeProviderInfo, + }) { assert(!hasBodyBeenBuilt, "Body has already been built for $this."); hasBodyBeenBuilt = true; if (!_fragment.modifiers.hasInitializer && @@ -301,7 +305,11 @@ class RegularFieldDeclaration fileUri, ); } - _encoding.createBodies(coreTypes, initializer); + _encoding.createBodies( + coreTypes, + initializer, + scopeProviderInfo: scopeProviderInfo, + ); } @override @@ -356,9 +364,17 @@ class RegularFieldDeclaration if (!hasBodyBeenBuilt && token != null) { if (_fragment.modifiers.isConst || forConstantConstructor) { if (hasInitializerBeenComputed) { - buildBody(classHierarchy.coreTypes, cachedFieldInitializer); + buildBody( + classHierarchy.coreTypes, + cachedFieldInitializer, + scopeProviderInfo: null, + ); } else { - var (_, initializer) = _buildFieldInitializerFromToken( + var ( + _, + initializer, + scopeProviderInfo, + ) = _buildFieldInitializerFromToken( classHierarchy: classHierarchy, libraryBuilder: libraryBuilder, bodyBuilderContext: bodyBuilderContext, @@ -366,13 +382,17 @@ class RegularFieldDeclaration token: token, inferenceDefaultType: inferenceDefaultType, ); - buildBody(classHierarchy.coreTypes, initializer); + buildBody( + classHierarchy.coreTypes, + initializer, + scopeProviderInfo: scopeProviderInfo, + ); } } } } - (DartType, Expression) _buildFieldInitializerFromToken({ + (DartType, Expression, ScopeProviderInfo?) _buildFieldInitializerFromToken({ required ClassHierarchyBase classHierarchy, required SourceLibraryBuilder libraryBuilder, required BodyBuilderContext bodyBuilderContext, @@ -381,7 +401,7 @@ class RegularFieldDeclaration required InferenceDefaultType inferenceDefaultType, }) { LookupScope scope = _fragment.enclosingScope; - ExpressionInferenceResult expressionInferenceResult = libraryBuilder.loader + InferredFieldInitializer inferredFieldInitializer = libraryBuilder.loader .createResolver() .buildFieldInitializer( libraryBuilder: libraryBuilder, @@ -410,8 +430,9 @@ class RegularFieldDeclaration ); } return ( - expressionInferenceResult.inferredType, - expressionInferenceResult.expression, + inferredFieldInitializer.expressionInferenceResult.inferredType, + inferredFieldInitializer.expressionInferenceResult.expression, + inferredFieldInitializer.scopeProviderInfo, ); } @@ -641,7 +662,7 @@ class RegularFieldDeclaration _encoding.registerSuperCall(); } - (DartType, Expression?) _computeInferredType( + (DartType, Expression?, ScopeProviderInfo?) _computeInferredType( ClassHierarchyBase classHierarchy, Token? token, ) { @@ -655,7 +676,7 @@ class RegularFieldDeclaration inferenceDefaultType: InferenceDefaultType.Dynamic, ); } else { - return (const DynamicType(), null); + return (const DynamicType(), null, null); } } @@ -831,8 +852,13 @@ mixin FieldDeclarationMixin nameOffset, () { InferredType implicitFieldType = fieldType as InferredType; - var (DartType inferredType, Expression? initializer) = implicitFieldType - .computeType(hierarchy); + var ( + DartType inferredType, + Expression? initializer, + ScopeProviderInfo? _, + ) = implicitFieldType.computeType( + hierarchy, + ); if (fieldType is InferredType) { // `fieldType` may have changed if a circularity was detected when // [inferredType] was computed. @@ -867,7 +893,11 @@ mixin FieldDeclarationMixin /// Builds the body of this field using [initializer] as the initializer /// expression. - void buildBody(CoreTypes coreTypes, Expression? initializer); + void buildBody( + CoreTypes coreTypes, + Expression? initializer, { + required ScopeProviderInfo? scopeProviderInfo, + }); /// Caches the [initializer], computed for top level inference. /// @@ -912,6 +942,7 @@ abstract class FieldFragmentDeclaration { required CoreTypes coreTypes, required Uri fileUri, Expression? initializer, + required ThisVariable? internalThisVariable, }); BodyBuilderContext createBodyBuilderContext(); @@ -941,7 +972,11 @@ mixin FieldFragmentDeclarationMixin implements FieldFragmentDeclaration { /// Builds the body of this field using [initializer] as the initializer /// expression. - void buildBody(CoreTypes coreType, Expression? initializer); + void buildBody( + CoreTypes coreType, + Expression? initializer, { + required ScopeProviderInfo? scopeProviderInfo, + }); /// Caches the [initializer], computed for top level inference. /// @@ -963,27 +998,34 @@ mixin FieldFragmentDeclarationMixin implements FieldFragmentDeclaration { required CoreTypes coreTypes, required Uri fileUri, Expression? initializer, + required ThisVariable? internalThisVariable, }) { if (_fieldInitializerCache != null) { if (!hasBodyBeenBuilt) { - buildBody(coreTypes, _fieldInitializerCache); + buildBody(coreTypes, _fieldInitializerCache, scopeProviderInfo: null); } } else if (initializer != null) { if (!hasBodyBeenBuilt) { - initializer = typeInferrer + InferredFieldInitializer inferredFieldInitializer = typeInferrer .inferFieldInitializer( fileUri: fileUri, declaredType: fieldType, initializer: initializer, inferenceDefaultType: inferenceDefaultType, - ) - .expression; + internalThisVariable: internalThisVariable, + ); + initializer = + inferredFieldInitializer.expressionInferenceResult.expression; _hasInitializerBeenComputed = true; - buildBody(coreTypes, initializer); + buildBody( + coreTypes, + initializer, + scopeProviderInfo: inferredFieldInitializer.scopeProviderInfo, + ); } } else if (!hasBodyBeenBuilt) { _hasInitializerBeenComputed = true; - buildBody(coreTypes, null); + buildBody(coreTypes, null, scopeProviderInfo: null); } } } diff --git a/pkg/front_end/lib/src/fragment/field/encoding.dart b/pkg/front_end/lib/src/fragment/field/encoding.dart index ab3ea0264da..0b1b691f21a 100644 --- a/pkg/front_end/lib/src/fragment/field/encoding.dart +++ b/pkg/front_end/lib/src/fragment/field/encoding.dart @@ -30,7 +30,11 @@ sealed class FieldEncoding { /// /// This method is not called for fields in outlines unless their are constant /// or part of a const constructor. - void createBodies(CoreTypes coreTypes, Expression? initializer); + void createBodies( + CoreTypes coreTypes, + Expression? initializer, { + required ScopeProviderInfo? scopeProviderInfo, + }); /// The type of the declared field. abstract DartType type; @@ -193,10 +197,15 @@ mixin RegularFieldEncodingMixin implements FieldEncoding { } @override - void createBodies(CoreTypes coreTypes, Expression? initializer) { + void createBodies( + CoreTypes coreTypes, + Expression? initializer, { + required ScopeProviderInfo? scopeProviderInfo, + }) { if (initializer != null) { _field!.initializer = initializer..parent = _field; } + _field!.scope = scopeProviderInfo?.scope; } @override @@ -454,7 +463,11 @@ abstract class AbstractLateFieldEncoding implements FieldEncoding { } @override - void createBodies(CoreTypes coreTypes, Expression? initializer) { + void createBodies( + CoreTypes coreTypes, + Expression? initializer, { + required ScopeProviderInfo? scopeProviderInfo, + }) { assert( _type != null, "Type has not been computed for field ${_fragment.name}.", @@ -494,6 +507,9 @@ abstract class AbstractLateFieldEncoding implements FieldEncoding { ), ); } + _field?.scope = + // Coverage-ignore(suite): Not run. + scopeProviderInfo?.scope; } @override @@ -1190,7 +1206,11 @@ class AbstractOrExternalFieldEncoding implements FieldEncoding { } @override - void createBodies(CoreTypes coreTypes, Expression? initializer) { + void createBodies( + CoreTypes coreTypes, + Expression? initializer, { + required ScopeProviderInfo? scopeProviderInfo, + }) { // TODO(johnniwinther): Enable this assert. //assert(initializer != null); } @@ -1495,7 +1515,11 @@ class RepresentationFieldEncoding implements FieldEncoding { @override // Coverage-ignore(suite): Not run. - void createBodies(CoreTypes coreTypes, Expression? initializer) { + void createBodies( + CoreTypes coreTypes, + Expression? initializer, { + required ScopeProviderInfo? scopeProviderInfo, + }) { // TODO(johnniwinther): Enable this assert. //assert(initializer != null); } @@ -1732,7 +1756,11 @@ class ExtensionInstanceFieldEncoding implements FieldEncoding { } @override - void createBodies(CoreTypes coreTypes, Expression? initializer) { + void createBodies( + CoreTypes coreTypes, + Expression? initializer, { + required ScopeProviderInfo? scopeProviderInfo, + }) { // TODO(johnniwinther): Enable this assert. //assert(initializer != null); } diff --git a/pkg/front_end/lib/src/fragment/fragment.dart b/pkg/front_end/lib/src/fragment/fragment.dart index 7a32896e76c..ba25cba0f79 100644 --- a/pkg/front_end/lib/src/fragment/fragment.dart +++ b/pkg/front_end/lib/src/fragment/fragment.dart @@ -61,8 +61,9 @@ import '../source/source_property_builder.dart'; import '../source/source_type_alias_builder.dart'; import '../source/source_type_parameter_builder.dart'; import '../source/type_parameter_factory.dart'; -import '../type_inference/inference_results.dart'; +import '../type_inference/context_allocation_strategy.dart'; import '../type_inference/type_inference_engine.dart'; +import '../type_inference/type_inferrer.dart'; import '../util/helpers.dart'; import 'constructor/declaration.dart'; import 'factory/declaration.dart'; diff --git a/pkg/front_end/lib/src/fragment/primary_constructor_field.dart b/pkg/front_end/lib/src/fragment/primary_constructor_field.dart index 7f155fe36a4..29c10d1431f 100644 --- a/pkg/front_end/lib/src/fragment/primary_constructor_field.dart +++ b/pkg/front_end/lib/src/fragment/primary_constructor_field.dart @@ -109,10 +109,18 @@ class PrimaryConstructorFieldDeclaration @override // Coverage-ignore(suite): Not run. - void buildBody(CoreTypes coreTypes, Expression? initializer) { + void buildBody( + CoreTypes coreTypes, + Expression? initializer, { + required ScopeProviderInfo? scopeProviderInfo, + }) { assert(!hasBodyBeenBuilt, "Body has already been built for $this."); hasBodyBeenBuilt = true; - _encoding.createBodies(coreTypes, initializer); + _encoding.createBodies( + coreTypes, + initializer, + scopeProviderInfo: scopeProviderInfo, + ); } @override @@ -440,15 +448,14 @@ class PrimaryConstructorFieldDeclaration _encoding.setCovariantByClass(); } - (DartType, Expression?) _computeInferredType( + (DartType, Expression?, ScopeProviderInfo?) _computeInferredType( ClassHierarchyBase classHierarchy, Token? token, ) { SourceLibraryBuilder libraryBuilder = builder.libraryBuilder; if (token != null) { LookupScope scope = _fragment.enclosingScope; - ExpressionInferenceResult expressionInferenceResult = libraryBuilder - .loader + InferredFieldInitializer inferredFieldInitializer = libraryBuilder.loader .createResolver() .buildFieldInitializer( libraryBuilder: libraryBuilder, @@ -465,12 +472,13 @@ class PrimaryConstructorFieldDeclaration inferenceDefaultType: inferenceDefaultType, ); return ( - expressionInferenceResult.inferredType, - expressionInferenceResult.expression, + inferredFieldInitializer.expressionInferenceResult.inferredType, + inferredFieldInitializer.expressionInferenceResult.expression, + inferredFieldInitializer.scopeProviderInfo, ); } else { assert(inferenceDefaultType == InferenceDefaultType.NullableObject); - return (classHierarchy.coreTypes.objectNullableRawType, null); + return (classHierarchy.coreTypes.objectNullableRawType, null, null); } } diff --git a/pkg/front_end/lib/src/kernel/implicit_field_type.dart b/pkg/front_end/lib/src/kernel/implicit_field_type.dart index 03c0f1f93e5..27b642bf516 100644 --- a/pkg/front_end/lib/src/kernel/implicit_field_type.dart +++ b/pkg/front_end/lib/src/kernel/implicit_field_type.dart @@ -13,6 +13,7 @@ import '../base/problems.dart' show unsupported; import '../builder/inferable_type_builder.dart'; import '../builder/type_builder.dart'; import '../source/source_library_builder.dart'; +import '../type_inference/context_allocation_strategy.dart'; abstract class InferredType extends AuxiliaryType { Uri? get fileUri; @@ -90,7 +91,9 @@ abstract class InferredType extends AuxiliaryType { DartType inferType(ClassHierarchyBase hierarchy); - (DartType, Expression?) computeType(ClassHierarchyBase hierarchy); + (DartType, Expression?, ScopeProviderInfo?) computeType( + ClassHierarchyBase hierarchy, + ); } /// Signature for function called to trigger the inference of the type of @@ -102,7 +105,7 @@ typedef InferTypeFunction = DartType Function(ClassHierarchyBase hierarchy); /// The function returns the compute type along with the inferred initializer, /// if any. typedef ComputeTypeFunction = - (DartType, Expression?) Function( + (DartType, Expression?, ScopeProviderInfo?) Function( ClassHierarchyBase hierarchy, Token? token, ); @@ -157,7 +160,9 @@ class _ImplicitType extends InferredType { } @override - (DartType, Expression?) computeType(ClassHierarchyBase hierarchy) { + (DartType, Expression?, ScopeProviderInfo?) computeType( + ClassHierarchyBase hierarchy, + ) { if (isStarted) { _libraryBuilder.addProblem( diag.cantInferTypeDueToCircularity.withArguments(name: _name), @@ -167,7 +172,7 @@ class _ImplicitType extends InferredType { ); DartType type = const InvalidType(); _typeBuilder.registerInferredType(type); - return (type, null); + return (type, null, null); } isStarted = true; Token? token = _token; @@ -210,8 +215,10 @@ class _InferredTypeUse extends InferredType { @override // Coverage-ignore(suite): Not run. - (DartType, Expression?) computeType(ClassHierarchyBase hierarchy) { - return (inferType(hierarchy), null); + (DartType, Expression?, ScopeProviderInfo?) computeType( + ClassHierarchyBase hierarchy, + ) { + return (inferType(hierarchy), null, null); } @override diff --git a/pkg/front_end/lib/src/kernel/resolver.dart b/pkg/front_end/lib/src/kernel/resolver.dart index 5a64147a908..3373df14f18 100644 --- a/pkg/front_end/lib/src/kernel/resolver.dart +++ b/pkg/front_end/lib/src/kernel/resolver.dart @@ -43,7 +43,7 @@ import '../type_inference/inference_visitor.dart' show ExpressionEvaluationHelper; import '../type_inference/type_inference_engine.dart'; import '../type_inference/type_inferrer.dart' - show TypeInferrer, InferredFunctionBody; + show TypeInferrer, InferredFieldInitializer, InferredFunctionBody; import '../type_inference/type_schema.dart'; import '../util/helpers.dart'; import 'assigned_variables_impl.dart'; @@ -233,7 +233,10 @@ class Resolver { declaredType: const UnknownType(), initializer: initializer, inferenceDefaultType: InferenceDefaultType.Dynamic, - ); + internalThisVariable: bodyBuilderContext + .createInternalThisVariable(), + ) + .expressionInferenceResult; initializer = inferenceResult.expression; fieldType = inferenceResult.inferredType; } @@ -242,7 +245,7 @@ class Resolver { return (initializer, fieldType); } - ExpressionInferenceResult buildFieldInitializer({ + InferredFieldInitializer buildFieldInitializer({ required SourceLibraryBuilder libraryBuilder, required BodyBuilderContext bodyBuilderContext, required Uri fileUri, @@ -264,6 +267,8 @@ class Resolver { ConstantContext constantContext = bodyBuilderContext.constantContext; List? primaryConstructorInitializerScopeParameters = bodyBuilderContext.primaryConstructorInitializerScopeParameters; + ThisVariable? internalThisVariable = bodyBuilderContext + .createInternalThisVariable(); BodyBuilder bodyBuilder = _createBodyBuilder( context: context, bodyBuilderContext: bodyBuilderContext, @@ -272,8 +277,7 @@ class Resolver { thisVariable: null, thisTypeParameters: null, formalParameterScope: null, - // TODO(cstefantsova): Should a [ThisVariable] be created here? - internalThisVariable: null, + internalThisVariable: internalThisVariable, ); BuildFieldInitializerResult result = bodyBuilder.buildFieldInitializer( startToken: startToken, @@ -285,15 +289,16 @@ class Resolver { thisVariable: null, formals: primaryConstructorInitializerScopeParameters, ); - ExpressionInferenceResult expressionInferenceResult = context.typeInferrer + InferredFieldInitializer inferredFieldInitializer = context.typeInferrer .inferFieldInitializer( fileUri: fileUri, declaredType: declaredFieldType, initializer: result.initializer, inferenceDefaultType: inferenceDefaultType, + internalThisVariable: internalThisVariable, ); context.performBacklog(result.annotations); - return expressionInferenceResult; + return inferredFieldInitializer; } void buildFields({ @@ -353,6 +358,7 @@ class Resolver { coreTypes: _coreTypes, fileUri: fileUri, initializer: initializer, + internalThisVariable: bodyBuilderContext.createInternalThisVariable(), ); } context.performBacklog(result.annotations); diff --git a/pkg/front_end/lib/src/type_inference/context_allocation_strategy.dart b/pkg/front_end/lib/src/type_inference/context_allocation_strategy.dart index eb6af572048..5e3b5f05b7f 100644 --- a/pkg/front_end/lib/src/type_inference/context_allocation_strategy.dart +++ b/pkg/front_end/lib/src/type_inference/context_allocation_strategy.dart @@ -9,11 +9,11 @@ extension type ScopeProviderInfoStack( List _list ) implements LocalStack { ScopeProviderInfo? topmostOfKind( - ScopeProviderInfoKind scopeProviderInfoKind, + Set scopeProviderInfoKinds, ) { for (int index = _list.length - 1; index >= 0; index--) { Info info = _list[index]; - if (info.kind == scopeProviderInfoKind) { + if (scopeProviderInfoKinds.contains(info.kind)) { return info; } } @@ -25,9 +25,11 @@ enum ScopeProviderInfoKind { Block, BlockExpression, Catch, - Loop, FunctionNode, FunctionNodeWithThis, + InstanceField, + Loop, + StaticField, } class ScopeProviderInfo { @@ -107,7 +109,10 @@ abstract class ContextAllocationStrategy { Scope _ensureScopeWithThis() { ScopeProviderInfo? scopeProviderInfo = _scopeProviderInfoStack - .topmostOfKind(ScopeProviderInfoKind.FunctionNodeWithThis); + .topmostOfKind(const { + ScopeProviderInfoKind.FunctionNodeWithThis, + ScopeProviderInfoKind.InstanceField, + }); assert(scopeProviderInfo != null); return scopeProviderInfo!.scope ??= // Coverage-ignore(suite): Not run. new Scope( @@ -230,6 +235,9 @@ class LoopDepthAllocationStrategy case ScopeProviderInfoKind.Loop: case ScopeProviderInfoKind.FunctionNode: case ScopeProviderInfoKind.FunctionNodeWithThis: + case ScopeProviderInfoKind.InstanceField: + // Coverage-ignore(suite): Not run. + case ScopeProviderInfoKind.StaticField: return true; } } diff --git a/pkg/front_end/lib/src/type_inference/inference_visitor.dart b/pkg/front_end/lib/src/type_inference/inference_visitor.dart index 14ec43a4ba2..7a6271055a4 100644 --- a/pkg/front_end/lib/src/type_inference/inference_visitor.dart +++ b/pkg/front_end/lib/src/type_inference/inference_visitor.dart @@ -17234,6 +17234,30 @@ class InferenceVisitorImpl extends InferenceVisitorBase } return const StatementInferenceResult(); } + + @override + ScopeProviderInfo beginFieldInference({ + required ThisVariable? internalThisVariable, + }) { + ScopeProviderInfo scopeProviderInfo = _contextAllocationStrategy + .enterScopeProvider( + scopeProviderInfoKind: internalThisVariable == null + ? ScopeProviderInfoKind.StaticField + : ScopeProviderInfoKind.InstanceField, + ); + if (internalThisVariable != null) { + _contextAllocationStrategy.handleDeclarationOfVariable( + internalThisVariable, + captureKind: _captureKindForVariable(internalThisVariable), + ); + } + return scopeProviderInfo; + } + + @override + void endFieldInference(ScopeProviderInfo scopeProviderInfo) { + _contextAllocationStrategy.exitScopeProvider(scopeProviderInfo); + } } /// Offset and type information collection in [InferenceVisitor.inferMapEntry]. diff --git a/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart b/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart index 6ea8f99ee73..d46d9d2a4e0 100644 --- a/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart +++ b/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart @@ -5524,8 +5524,16 @@ abstract class InferenceVisitorBase implements InferenceVisitor { required ThisVariable? internalThisVariable, }); - /// Performs finishing computations after inferring the body of a function. + /// Finishes computations after inferring the body of a function. void endFunctionBodyInference(ScopeProviderInfo scopeProviderInfo); + + /// Performs preliminary computations before inferring the field initializer. + ScopeProviderInfo beginFieldInference({ + required ThisVariable? internalThisVariable, + }); + + /// Finishes computations after inferring the field initializer. + void endFieldInference(ScopeProviderInfo scopeProviderInfo); } /// Describes assignability kind of one type to another. diff --git a/pkg/front_end/lib/src/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/type_inference/type_inferrer.dart index fd351fbda91..0db3d5d3468 100644 --- a/pkg/front_end/lib/src/type_inference/type_inferrer.dart +++ b/pkg/front_end/lib/src/type_inference/type_inferrer.dart @@ -49,11 +49,12 @@ abstract class TypeInferrer { /// /// When [declaredType] is `null` and the [initializer] has type `Null`, the /// inferred field type is determined by [inferenceDefaultType]. - ExpressionInferenceResult inferFieldInitializer({ + InferredFieldInitializer inferFieldInitializer({ required Uri fileUri, DartType? declaredType, required Expression initializer, required InferenceDefaultType inferenceDefaultType, + required ThisVariable? internalThisVariable, }); /// Performs type inference on the given function body. @@ -200,18 +201,28 @@ class TypeInferrerImpl implements TypeInferrer { } @override - ExpressionInferenceResult inferFieldInitializer({ + InferredFieldInitializer inferFieldInitializer({ required Uri fileUri, DartType? declaredType, required Expression initializer, required InferenceDefaultType inferenceDefaultType, + required ThisVariable? internalThisVariable, }) { InferenceVisitorBase visitor = _createInferenceVisitor(fileUri: fileUri); + ScopeProviderInfo? scopeProviderInfo; + if (isClosureContextLoweringEnabled) { + scopeProviderInfo = visitor.beginFieldInference( + internalThisVariable: internalThisVariable, + ); + } ExpressionInferenceResult initializerResult = visitor.inferExpression( initializer, declaredType ?? const UnknownType(), isVoidAllowed: true, ); + if (scopeProviderInfo != null) { + visitor.endFieldInference(scopeProviderInfo); + } if (declaredType != null) { // If the field has a declared type, check for assignability. initializerResult = visitor.ensureAssignableResult( @@ -231,7 +242,7 @@ class TypeInferrerImpl implements TypeInferrer { ); } visitor.checkCleanState(); - return initializerResult; + return new InferredFieldInitializer(initializerResult, scopeProviderInfo); } @override @@ -454,18 +465,20 @@ class TypeInferrerImplBenchmarked implements TypeInferrer { TypeSchemaEnvironment get typeSchemaEnvironment => impl.typeSchemaEnvironment; @override - ExpressionInferenceResult inferFieldInitializer({ + InferredFieldInitializer inferFieldInitializer({ required Uri fileUri, DartType? declaredType, required Expression initializer, required InferenceDefaultType inferenceDefaultType, + required ThisVariable? internalThisVariable, }) { benchmarker.beginSubdivide(BenchmarkSubdivides.inferFieldInitializer); - ExpressionInferenceResult result = impl.inferFieldInitializer( + InferredFieldInitializer result = impl.inferFieldInitializer( fileUri: fileUri, declaredType: declaredType, initializer: initializer, inferenceDefaultType: inferenceDefaultType, + internalThisVariable: internalThisVariable, ); benchmarker.endSubdivide(); return result; @@ -586,3 +599,13 @@ class InferredFunctionBody { this.scopeProviderInfo, ); } + +class InferredFieldInitializer { + final ExpressionInferenceResult expressionInferenceResult; + final ScopeProviderInfo? scopeProviderInfo; + + InferredFieldInitializer( + this.expressionInferenceResult, + this.scopeProviderInfo, + ); +} diff --git a/pkg/front_end/testcases/closure_context_lowering/late_field_initializers.dart b/pkg/front_end/testcases/closure_context_lowering/late_field_initializers.dart new file mode 100644 index 00000000000..7f0807d14e4 --- /dev/null +++ b/pkg/front_end/testcases/closure_context_lowering/late_field_initializers.dart @@ -0,0 +1,7 @@ +// 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. + +class A { + late A Function() f = () => this; +} diff --git a/pkg/front_end/testcases/closure_context_lowering/late_field_initializers.dart.strong.expect b/pkg/front_end/testcases/closure_context_lowering/late_field_initializers.dart.strong.expect new file mode 100644 index 00000000000..3b7c46cb558 --- /dev/null +++ b/pkg/front_end/testcases/closure_context_lowering/late_field_initializers.dart.strong.expect @@ -0,0 +1,14 @@ +library; +import self as self; +import "dart:core" as core; + +class A extends core::Object { + late field () → self::A f/* scope=[ + #ctx1: not-captured VariableContext([ + this-variable final this-variable; + ]), + ] */ = () → self::A => this-variable; + synthetic constructor •() → self::A + : super core::Object::•() + ; +} diff --git a/pkg/front_end/testcases/closure_context_lowering/late_field_initializers.dart.strong.modular.expect b/pkg/front_end/testcases/closure_context_lowering/late_field_initializers.dart.strong.modular.expect new file mode 100644 index 00000000000..3b7c46cb558 --- /dev/null +++ b/pkg/front_end/testcases/closure_context_lowering/late_field_initializers.dart.strong.modular.expect @@ -0,0 +1,14 @@ +library; +import self as self; +import "dart:core" as core; + +class A extends core::Object { + late field () → self::A f/* scope=[ + #ctx1: not-captured VariableContext([ + this-variable final this-variable; + ]), + ] */ = () → self::A => this-variable; + synthetic constructor •() → self::A + : super core::Object::•() + ; +} diff --git a/pkg/front_end/testcases/closure_context_lowering/late_field_initializers.dart.strong.outline.expect b/pkg/front_end/testcases/closure_context_lowering/late_field_initializers.dart.strong.outline.expect new file mode 100644 index 00000000000..2acf4da87d3 --- /dev/null +++ b/pkg/front_end/testcases/closure_context_lowering/late_field_initializers.dart.strong.outline.expect @@ -0,0 +1,9 @@ +library; +import self as self; +import "dart:core" as core; + +class A extends core::Object { + late field () → self::A f; + synthetic constructor •() → self::A + ; +} diff --git a/pkg/front_end/testcases/closure_context_lowering/late_field_initializers.dart.textual_outline.expect b/pkg/front_end/testcases/closure_context_lowering/late_field_initializers.dart.textual_outline.expect new file mode 100644 index 00000000000..ce4277b0dac --- /dev/null +++ b/pkg/front_end/testcases/closure_context_lowering/late_field_initializers.dart.textual_outline.expect @@ -0,0 +1,3 @@ +class A { + late A Function() f = () => this; +} diff --git a/pkg/front_end/testcases/closure_context_lowering/late_field_initializers.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/closure_context_lowering/late_field_initializers.dart.textual_outline_modelled.expect new file mode 100644 index 00000000000..ce4277b0dac --- /dev/null +++ b/pkg/front_end/testcases/closure_context_lowering/late_field_initializers.dart.textual_outline_modelled.expect @@ -0,0 +1,3 @@ +class A { + late A Function() f = () => this; +} diff --git a/pkg/front_end/testcases/closure_context_lowering/this_variable.dart.strong.expect b/pkg/front_end/testcases/closure_context_lowering/this_variable.dart.strong.expect index 1509358f2d2..be8b77ecef4 100644 --- a/pkg/front_end/testcases/closure_context_lowering/this_variable.dart.strong.expect +++ b/pkg/front_end/testcases/closure_context_lowering/this_variable.dart.strong.expect @@ -3,278 +3,286 @@ import self as self; import "dart:core" as core; class A extends core::Object { - field self::A a = new self::A::•(); + field self::A a/* scope=[ + #ctx1: not-captured VariableContext([ + this-variable final this-variable; + ]), + ] */ = new self::A::•(); field self::A? aNull = null; - field core::int n = 0; + field core::int n/* scope=[ + #ctx2: not-captured VariableContext([ + this-variable final this-variable; + ]), + ] */ = 0; field core::Object? field = null; synthetic constructor •() → self::A : super core::Object::•() ; method method() → dynamic/* scope=[ - #ctx1: not-captured VariableContext([ + #ctx3: not-captured VariableContext([ this-variable final this-variable; ]), ] */ {} method call() → core::Object?/* scope=[ - #ctx2: not-captured VariableContext([ + #ctx4: not-captured VariableContext([ this-variable final this-variable; ]), ] */ return null; operator [](positional-parameter index) → core::Object?/* scope=[ - #ctx3: not-captured VariableContext([ + #ctx5: not-captured VariableContext([ this-variable final this-variable; positional-parameter index; ]), ] */ return null; operator []=(positional-parameter index, positional-parameter value) → void/* scope=[ - #ctx4: not-captured VariableContext([ + #ctx6: not-captured VariableContext([ this-variable final this-variable; positional-parameter index; positional-parameter value; ]), ] */ {} operator +(positional-parameter other) → self::A/* scope=[ - #ctx5: not-captured VariableContext([ + #ctx7: not-captured VariableContext([ this-variable final this-variable; positional-parameter other; ]), ] */ return this-variable; operator unary-() → self::A/* scope=[ - #ctx6: not-captured VariableContext([ + #ctx8: not-captured VariableContext([ this-variable final this-variable; ]), ] */ return this-variable; method notCapturedMethodCall() → dynamic/* scope=[ - #ctx7: not-captured VariableContext([ + #ctx9: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::method}(){() → dynamic}; } method notCapturedExpression() → dynamic/* scope=[ - #ctx8: not-captured VariableContext([ + #ctx10: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable; } method notCapturedPropertyGet() → dynamic/* scope=[ - #ctx9: not-captured VariableContext([ + #ctx11: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::field}{core::Object?}; } method notCapturedPropertySet() → dynamic/* scope=[ - #ctx10: not-captured VariableContext([ + #ctx12: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::field} = null; } method notCapturedCall() → dynamic/* scope=[ - #ctx11: not-captured VariableContext([ + #ctx13: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::call}(){() → core::Object?}; } method notCapturedIndexGet() → dynamic/* scope=[ - #ctx12: not-captured VariableContext([ + #ctx14: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::[]}(0){(core::int) → core::Object?}; } method notCapturedIndexSet() → dynamic/* scope=[ - #ctx13: not-captured VariableContext([ + #ctx15: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::[]=}(0, null){(core::int, core::Object?) → void}; } method notCapturedUnary() → dynamic/* scope=[ - #ctx14: not-captured VariableContext([ + #ctx16: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::unary-}(){() → self::A}; } method notCapturedBinary() → dynamic/* scope=[ - #ctx15: not-captured VariableContext([ + #ctx17: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::+}(this-variable){(self::A) → self::A}; } method notCapturedPropertyCall() → dynamic/* scope=[ - #ctx16: not-captured VariableContext([ + #ctx18: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::a}{self::A}.{self::A::call}(){() → core::Object?}; } method notCapturedPropertyPrefix() → dynamic/* scope=[ - #ctx17: not-captured VariableContext([ + #ctx19: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::n} = this-variable.{self::A::n}{core::int}.{core::num::+}(1){(core::num) → core::int}; } method notCapturedPropertyPostfix() → dynamic/* scope=[ - #ctx18: not-captured VariableContext([ + #ctx20: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::n} = this-variable.{self::A::n}{core::int}.{core::num::+}(1){(core::num) → core::int}; } method notCapturedPropertyIndexGet() → dynamic/* scope=[ - #ctx19: not-captured VariableContext([ + #ctx21: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::a}{self::A}.{self::A::[]}(0){(core::int) → core::Object?}; } method notCapturedPropertyIndexSet() → dynamic/* scope=[ - #ctx20: not-captured VariableContext([ + #ctx22: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::a}{self::A}.{self::A::[]=}(0, null){(core::int, core::Object?) → void}; } method notCapturedPropertyIfNullAssignment() → dynamic/* scope=[ - #ctx21: not-captured VariableContext([ + #ctx23: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::aNull}{self::A?} == null ?{self::A?} this-variable.{self::A::aNull} = new self::A::•() : null; } method notCapturedPropertyCompoundAssignment() → dynamic/* scope=[ - #ctx22: not-captured VariableContext([ + #ctx24: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::a} = this-variable.{self::A::a}{self::A}.{self::A::+}(new self::A::•()){(self::A) → self::A}; } method capturedMethodCall() → dynamic/* scope=[ - #ctx23: direct-captured VariableContext([ - this-variable final this-variable; - ]), - ] */ { - return () /* #ctx23 */ → dynamic => this-variable.{self::A::method}(){() → dynamic}; - } - method capturedExpression() → dynamic/* scope=[ - #ctx24: direct-captured VariableContext([ - this-variable final this-variable; - ]), - ] */ { - return () /* #ctx24 */ → self::A => this-variable; - } - method capturedPropertyGet() → dynamic/* scope=[ #ctx25: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx25 */ → core::Object? => this-variable.{self::A::field}{core::Object?}; + return () /* #ctx25 */ → dynamic => this-variable.{self::A::method}(){() → dynamic}; } - method capturedPropertySet() → dynamic/* scope=[ + method capturedExpression() → dynamic/* scope=[ #ctx26: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx26 */ → Null { - this-variable.{self::A::field} = null; - }; + return () /* #ctx26 */ → self::A => this-variable; } - method capturedCall() → dynamic/* scope=[ + method capturedPropertyGet() → dynamic/* scope=[ #ctx27: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx27 */ → core::Object? => this-variable.{self::A::call}(){() → core::Object?}; + return () /* #ctx27 */ → core::Object? => this-variable.{self::A::field}{core::Object?}; } - method capturedIndexGet() → dynamic/* scope=[ + method capturedPropertySet() → dynamic/* scope=[ #ctx28: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx28 */ → core::Object? => this-variable.{self::A::[]}(0){(core::int) → core::Object?}; + return () /* #ctx28 */ → Null { + this-variable.{self::A::field} = null; + }; } - method capturedIndexSet() → dynamic/* scope=[ + method capturedCall() → dynamic/* scope=[ #ctx29: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx29 */ → Null { - this-variable.{self::A::[]=}(0, null){(core::int, core::Object?) → void}; - }; + return () /* #ctx29 */ → core::Object? => this-variable.{self::A::call}(){() → core::Object?}; } - method capturedUnary() → dynamic/* scope=[ + method capturedIndexGet() → dynamic/* scope=[ #ctx30: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx30 */ → self::A => this-variable.{self::A::unary-}(){() → self::A}; + return () /* #ctx30 */ → core::Object? => this-variable.{self::A::[]}(0){(core::int) → core::Object?}; } - method capturedBinary() → dynamic/* scope=[ + method capturedIndexSet() → dynamic/* scope=[ #ctx31: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx31 */ → self::A => this-variable.{self::A::+}(this-variable){(self::A) → self::A}; + return () /* #ctx31 */ → Null { + this-variable.{self::A::[]=}(0, null){(core::int, core::Object?) → void}; + }; } - method capturedPropertyCall() → dynamic/* scope=[ + method capturedUnary() → dynamic/* scope=[ #ctx32: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx32 */ → core::Object? => this-variable.{self::A::a}{self::A}.{self::A::call}(){() → core::Object?}; + return () /* #ctx32 */ → self::A => this-variable.{self::A::unary-}(){() → self::A}; } - method capturedPropertyPrefix() → dynamic/* scope=[ + method capturedBinary() → dynamic/* scope=[ #ctx33: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx33 */ → core::int => this-variable.{self::A::n} = this-variable.{self::A::n}{core::int}.{core::num::+}(1){(core::num) → core::int}; + return () /* #ctx33 */ → self::A => this-variable.{self::A::+}(this-variable){(self::A) → self::A}; } - method capturedPropertyPostfix() → dynamic/* scope=[ + method capturedPropertyCall() → dynamic/* scope=[ #ctx34: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx34 */ → core::int => let final core::int #t1 = this-variable.{self::A::n}{core::int} in let final void #t2 = this-variable.{self::A::n} = #t1.{core::num::+}(1){(core::num) → core::int} in #t1; + return () /* #ctx34 */ → core::Object? => this-variable.{self::A::a}{self::A}.{self::A::call}(){() → core::Object?}; } - method capturedPropertyIndexGet() → dynamic/* scope=[ + method capturedPropertyPrefix() → dynamic/* scope=[ #ctx35: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx35 */ → core::Object? => this-variable.{self::A::a}{self::A}.{self::A::[]}(0){(core::int) → core::Object?}; + return () /* #ctx35 */ → core::int => this-variable.{self::A::n} = this-variable.{self::A::n}{core::int}.{core::num::+}(1){(core::num) → core::int}; } - method capturedPropertyIndexSet() → dynamic/* scope=[ + method capturedPropertyPostfix() → dynamic/* scope=[ #ctx36: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx36 */ → Null => let final self::A #t3 = this-variable.{self::A::a}{self::A} in let final core::int #t4 = 0 in let final has-declared-initializer Null #t5 = null in let final void #t6 = #t3.{self::A::[]=}(#t4, #t5){(core::int, core::Object?) → void} in #t5; + return () /* #ctx36 */ → core::int => let final core::int #t1 = this-variable.{self::A::n}{core::int} in let final void #t2 = this-variable.{self::A::n} = #t1.{core::num::+}(1){(core::num) → core::int} in #t1; } - method capturedPropertyIfNullAssignment() → dynamic/* scope=[ + method capturedPropertyIndexGet() → dynamic/* scope=[ #ctx37: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx37 */ → self::A => let final self::A? #t7 = this-variable.{self::A::aNull}{self::A?} in #t7 == null ?{self::A} this-variable.{self::A::aNull} = new self::A::•() : #t7{self::A}; + return () /* #ctx37 */ → core::Object? => this-variable.{self::A::a}{self::A}.{self::A::[]}(0){(core::int) → core::Object?}; } - method capturedPropertyCompoundAssignment() → dynamic/* scope=[ + method capturedPropertyIndexSet() → dynamic/* scope=[ #ctx38: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx38 */ → self::A => this-variable.{self::A::a} = this-variable.{self::A::a}{self::A}.{self::A::+}(new self::A::•()){(self::A) → self::A}; + return () /* #ctx38 */ → Null => let final self::A #t3 = this-variable.{self::A::a}{self::A} in let final core::int #t4 = 0 in let final has-declared-initializer Null #t5 = null in let final void #t6 = #t3.{self::A::[]=}(#t4, #t5){(core::int, core::Object?) → void} in #t5; + } + method capturedPropertyIfNullAssignment() → dynamic/* scope=[ + #ctx39: direct-captured VariableContext([ + this-variable final this-variable; + ]), + ] */ { + return () /* #ctx39 */ → self::A => let final self::A? #t7 = this-variable.{self::A::aNull}{self::A?} in #t7 == null ?{self::A} this-variable.{self::A::aNull} = new self::A::•() : #t7{self::A}; + } + method capturedPropertyCompoundAssignment() → dynamic/* scope=[ + #ctx40: direct-captured VariableContext([ + this-variable final this-variable; + ]), + ] */ { + return () /* #ctx40 */ → self::A => this-variable.{self::A::a} = this-variable.{self::A::a}{self::A}.{self::A::+}(new self::A::•()){(self::A) → self::A}; } } class B extends self::A { @@ -283,7 +291,7 @@ class B extends self::A { ; @#C1 method notCapturedMethodCall() → dynamic/* scope=[ - #ctx39: not-captured VariableContext([ + #ctx41: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -291,7 +299,7 @@ class B extends self::A { } @#C1 method notCapturedPropertyGet() → dynamic/* scope=[ - #ctx40: not-captured VariableContext([ + #ctx42: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -299,7 +307,7 @@ class B extends self::A { } @#C1 method notCapturedPropertySet() → dynamic/* scope=[ - #ctx41: not-captured VariableContext([ + #ctx43: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -307,7 +315,7 @@ class B extends self::A { } @#C1 method notCapturedCall() → dynamic/* scope=[ - #ctx42: not-captured VariableContext([ + #ctx44: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -315,7 +323,7 @@ class B extends self::A { } @#C1 method notCapturedIndexGet() → dynamic/* scope=[ - #ctx43: not-captured VariableContext([ + #ctx45: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -323,7 +331,7 @@ class B extends self::A { } @#C1 method notCapturedIndexSet() → dynamic/* scope=[ - #ctx44: not-captured VariableContext([ + #ctx46: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -331,7 +339,7 @@ class B extends self::A { } @#C1 method notCapturedUnary() → dynamic/* scope=[ - #ctx45: not-captured VariableContext([ + #ctx47: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -339,7 +347,7 @@ class B extends self::A { } @#C1 method notCapturedBinary() → dynamic/* scope=[ - #ctx46: not-captured VariableContext([ + #ctx48: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -347,7 +355,7 @@ class B extends self::A { } @#C1 method notCapturedPropertyCall() → dynamic/* scope=[ - #ctx47: not-captured VariableContext([ + #ctx49: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -355,7 +363,7 @@ class B extends self::A { } @#C1 method notCapturedPropertyPrefix() → dynamic/* scope=[ - #ctx48: not-captured VariableContext([ + #ctx50: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -363,7 +371,7 @@ class B extends self::A { } @#C1 method notCapturedPropertyPostfix() → dynamic/* scope=[ - #ctx49: not-captured VariableContext([ + #ctx51: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -371,7 +379,7 @@ class B extends self::A { } @#C1 method notCapturedPropertyIndexGet() → dynamic/* scope=[ - #ctx50: not-captured VariableContext([ + #ctx52: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -379,7 +387,7 @@ class B extends self::A { } @#C1 method notCapturedPropertyIndexSet() → dynamic/* scope=[ - #ctx51: not-captured VariableContext([ + #ctx53: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -387,7 +395,7 @@ class B extends self::A { } @#C1 method notCapturedPropertyIfNullAssignment() → dynamic/* scope=[ - #ctx52: not-captured VariableContext([ + #ctx54: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -395,7 +403,7 @@ class B extends self::A { } @#C1 method notCapturedPropertyCompoundAssignment() → dynamic/* scope=[ - #ctx53: not-captured VariableContext([ + #ctx55: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -403,127 +411,127 @@ class B extends self::A { } @#C1 method capturedMethodCall() → dynamic/* scope=[ - #ctx54: direct-captured VariableContext([ - this-variable final this-variable; - ]), - ] */ { - return () /* #ctx54 */ → dynamic => super{this-variable}.{self::A::method}(); - } - @#C1 - method capturedPropertyGet() → dynamic/* scope=[ - #ctx55: direct-captured VariableContext([ - this-variable final this-variable; - ]), - ] */ { - return () /* #ctx55 */ → core::Object? => super{this-variable}.{self::A::field}; - } - @#C1 - method capturedPropertySet() → dynamic/* scope=[ #ctx56: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx56 */ → Null { + return () /* #ctx56 */ → dynamic => super{this-variable}.{self::A::method}(); + } + @#C1 + method capturedPropertyGet() → dynamic/* scope=[ + #ctx57: direct-captured VariableContext([ + this-variable final this-variable; + ]), + ] */ { + return () /* #ctx57 */ → core::Object? => super{this-variable}.{self::A::field}; + } + @#C1 + method capturedPropertySet() → dynamic/* scope=[ + #ctx58: direct-captured VariableContext([ + this-variable final this-variable; + ]), + ] */ { + return () /* #ctx58 */ → Null { super{this-variable}.{self::A::field} = null; }; } @#C1 method capturedCall() → dynamic/* scope=[ - #ctx57: direct-captured VariableContext([ - this-variable final this-variable; - ]), - ] */ { - return () /* #ctx57 */ → core::Object? => super{this-variable}.{self::A::call}(); - } - @#C1 - method capturedIndexGet() → dynamic/* scope=[ - #ctx58: direct-captured VariableContext([ - this-variable final this-variable; - ]), - ] */ { - return () /* #ctx58 */ → core::Object? => super{this-variable}.{self::A::[]}(0); - } - @#C1 - method capturedIndexSet() → dynamic/* scope=[ #ctx59: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx59 */ → Null { + return () /* #ctx59 */ → core::Object? => super{this-variable}.{self::A::call}(); + } + @#C1 + method capturedIndexGet() → dynamic/* scope=[ + #ctx60: direct-captured VariableContext([ + this-variable final this-variable; + ]), + ] */ { + return () /* #ctx60 */ → core::Object? => super{this-variable}.{self::A::[]}(0); + } + @#C1 + method capturedIndexSet() → dynamic/* scope=[ + #ctx61: direct-captured VariableContext([ + this-variable final this-variable; + ]), + ] */ { + return () /* #ctx61 */ → Null { super{this-variable}.{self::A::[]=}(0, null); }; } @#C1 method capturedUnary() → dynamic/* scope=[ - #ctx60: direct-captured VariableContext([ - this-variable final this-variable; - ]), - ] */ { - return () /* #ctx60 */ → self::A => super{this-variable}.{self::A::unary-}(); - } - @#C1 - method capturedBinary() → dynamic/* scope=[ - #ctx61: direct-captured VariableContext([ - this-variable final this-variable; - ]), - ] */ { - return () /* #ctx61 */ → self::A => super{this-variable}.{self::A::+}(this-variable); - } - @#C1 - method capturedPropertyCall() → dynamic/* scope=[ #ctx62: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx62 */ → core::Object? => super{this-variable}.{self::A::a}.{self::A::call}(){() → core::Object?}; + return () /* #ctx62 */ → self::A => super{this-variable}.{self::A::unary-}(); } @#C1 - method capturedPropertyPrefix() → dynamic/* scope=[ + method capturedBinary() → dynamic/* scope=[ #ctx63: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx63 */ → core::int => super{this-variable}.{self::A::n} = super{this-variable}.{self::A::n}.{core::num::+}(1){(core::num) → core::int}; + return () /* #ctx63 */ → self::A => super{this-variable}.{self::A::+}(this-variable); } @#C1 - method capturedPropertyPostfix() → dynamic/* scope=[ + method capturedPropertyCall() → dynamic/* scope=[ #ctx64: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx64 */ → core::int => let final core::int #t8 = super{this-variable}.{self::A::n} in let final void #t9 = super{this-variable}.{self::A::n} = #t8.{core::num::+}(1){(core::num) → core::int} in #t8; + return () /* #ctx64 */ → core::Object? => super{this-variable}.{self::A::a}.{self::A::call}(){() → core::Object?}; } @#C1 - method capturedPropertyIndexGet() → dynamic/* scope=[ + method capturedPropertyPrefix() → dynamic/* scope=[ #ctx65: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx65 */ → core::Object? => super{this-variable}.{self::A::a}.{self::A::[]}(0){(core::int) → core::Object?}; + return () /* #ctx65 */ → core::int => super{this-variable}.{self::A::n} = super{this-variable}.{self::A::n}.{core::num::+}(1){(core::num) → core::int}; } @#C1 - method capturedPropertyIndexSet() → dynamic/* scope=[ + method capturedPropertyPostfix() → dynamic/* scope=[ #ctx66: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx66 */ → Null => let final self::A #t10 = super{this-variable}.{self::A::a} in let final core::int #t11 = 0 in let final has-declared-initializer Null #t12 = null in let final void #t13 = #t10.{self::A::[]=}(#t11, #t12){(core::int, core::Object?) → void} in #t12; + return () /* #ctx66 */ → core::int => let final core::int #t8 = super{this-variable}.{self::A::n} in let final void #t9 = super{this-variable}.{self::A::n} = #t8.{core::num::+}(1){(core::num) → core::int} in #t8; } @#C1 - method capturedPropertyIfNullAssignment() → dynamic/* scope=[ + method capturedPropertyIndexGet() → dynamic/* scope=[ #ctx67: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx67 */ → self::A => let final self::A? #t14 = super{this-variable}.{self::A::aNull} in #t14 == null ?{self::A} super{this-variable}.{self::A::aNull} = new self::A::•() : #t14{self::A}; + return () /* #ctx67 */ → core::Object? => super{this-variable}.{self::A::a}.{self::A::[]}(0){(core::int) → core::Object?}; } @#C1 - method capturedPropertyCompoundAssignment() → dynamic/* scope=[ + method capturedPropertyIndexSet() → dynamic/* scope=[ #ctx68: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx68 */ → self::A => super{this-variable}.{self::A::a} = super{this-variable}.{self::A::a}.{self::A::+}(new self::A::•()){(self::A) → self::A}; + return () /* #ctx68 */ → Null => let final self::A #t10 = super{this-variable}.{self::A::a} in let final core::int #t11 = 0 in let final has-declared-initializer Null #t12 = null in let final void #t13 = #t10.{self::A::[]=}(#t11, #t12){(core::int, core::Object?) → void} in #t12; + } + @#C1 + method capturedPropertyIfNullAssignment() → dynamic/* scope=[ + #ctx69: direct-captured VariableContext([ + this-variable final this-variable; + ]), + ] */ { + return () /* #ctx69 */ → self::A => let final self::A? #t14 = super{this-variable}.{self::A::aNull} in #t14 == null ?{self::A} super{this-variable}.{self::A::aNull} = new self::A::•() : #t14{self::A}; + } + @#C1 + method capturedPropertyCompoundAssignment() → dynamic/* scope=[ + #ctx70: direct-captured VariableContext([ + this-variable final this-variable; + ]), + ] */ { + return () /* #ctx70 */ → self::A => super{this-variable}.{self::A::a} = super{this-variable}.{self::A::a}.{self::A::+}(new self::A::•()){(self::A) → self::A}; } } diff --git a/pkg/front_end/testcases/closure_context_lowering/this_variable.dart.strong.modular.expect b/pkg/front_end/testcases/closure_context_lowering/this_variable.dart.strong.modular.expect index 1509358f2d2..be8b77ecef4 100644 --- a/pkg/front_end/testcases/closure_context_lowering/this_variable.dart.strong.modular.expect +++ b/pkg/front_end/testcases/closure_context_lowering/this_variable.dart.strong.modular.expect @@ -3,278 +3,286 @@ import self as self; import "dart:core" as core; class A extends core::Object { - field self::A a = new self::A::•(); + field self::A a/* scope=[ + #ctx1: not-captured VariableContext([ + this-variable final this-variable; + ]), + ] */ = new self::A::•(); field self::A? aNull = null; - field core::int n = 0; + field core::int n/* scope=[ + #ctx2: not-captured VariableContext([ + this-variable final this-variable; + ]), + ] */ = 0; field core::Object? field = null; synthetic constructor •() → self::A : super core::Object::•() ; method method() → dynamic/* scope=[ - #ctx1: not-captured VariableContext([ + #ctx3: not-captured VariableContext([ this-variable final this-variable; ]), ] */ {} method call() → core::Object?/* scope=[ - #ctx2: not-captured VariableContext([ + #ctx4: not-captured VariableContext([ this-variable final this-variable; ]), ] */ return null; operator [](positional-parameter index) → core::Object?/* scope=[ - #ctx3: not-captured VariableContext([ + #ctx5: not-captured VariableContext([ this-variable final this-variable; positional-parameter index; ]), ] */ return null; operator []=(positional-parameter index, positional-parameter value) → void/* scope=[ - #ctx4: not-captured VariableContext([ + #ctx6: not-captured VariableContext([ this-variable final this-variable; positional-parameter index; positional-parameter value; ]), ] */ {} operator +(positional-parameter other) → self::A/* scope=[ - #ctx5: not-captured VariableContext([ + #ctx7: not-captured VariableContext([ this-variable final this-variable; positional-parameter other; ]), ] */ return this-variable; operator unary-() → self::A/* scope=[ - #ctx6: not-captured VariableContext([ + #ctx8: not-captured VariableContext([ this-variable final this-variable; ]), ] */ return this-variable; method notCapturedMethodCall() → dynamic/* scope=[ - #ctx7: not-captured VariableContext([ + #ctx9: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::method}(){() → dynamic}; } method notCapturedExpression() → dynamic/* scope=[ - #ctx8: not-captured VariableContext([ + #ctx10: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable; } method notCapturedPropertyGet() → dynamic/* scope=[ - #ctx9: not-captured VariableContext([ + #ctx11: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::field}{core::Object?}; } method notCapturedPropertySet() → dynamic/* scope=[ - #ctx10: not-captured VariableContext([ + #ctx12: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::field} = null; } method notCapturedCall() → dynamic/* scope=[ - #ctx11: not-captured VariableContext([ + #ctx13: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::call}(){() → core::Object?}; } method notCapturedIndexGet() → dynamic/* scope=[ - #ctx12: not-captured VariableContext([ + #ctx14: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::[]}(0){(core::int) → core::Object?}; } method notCapturedIndexSet() → dynamic/* scope=[ - #ctx13: not-captured VariableContext([ + #ctx15: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::[]=}(0, null){(core::int, core::Object?) → void}; } method notCapturedUnary() → dynamic/* scope=[ - #ctx14: not-captured VariableContext([ + #ctx16: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::unary-}(){() → self::A}; } method notCapturedBinary() → dynamic/* scope=[ - #ctx15: not-captured VariableContext([ + #ctx17: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::+}(this-variable){(self::A) → self::A}; } method notCapturedPropertyCall() → dynamic/* scope=[ - #ctx16: not-captured VariableContext([ + #ctx18: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::a}{self::A}.{self::A::call}(){() → core::Object?}; } method notCapturedPropertyPrefix() → dynamic/* scope=[ - #ctx17: not-captured VariableContext([ + #ctx19: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::n} = this-variable.{self::A::n}{core::int}.{core::num::+}(1){(core::num) → core::int}; } method notCapturedPropertyPostfix() → dynamic/* scope=[ - #ctx18: not-captured VariableContext([ + #ctx20: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::n} = this-variable.{self::A::n}{core::int}.{core::num::+}(1){(core::num) → core::int}; } method notCapturedPropertyIndexGet() → dynamic/* scope=[ - #ctx19: not-captured VariableContext([ + #ctx21: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::a}{self::A}.{self::A::[]}(0){(core::int) → core::Object?}; } method notCapturedPropertyIndexSet() → dynamic/* scope=[ - #ctx20: not-captured VariableContext([ + #ctx22: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::a}{self::A}.{self::A::[]=}(0, null){(core::int, core::Object?) → void}; } method notCapturedPropertyIfNullAssignment() → dynamic/* scope=[ - #ctx21: not-captured VariableContext([ + #ctx23: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::aNull}{self::A?} == null ?{self::A?} this-variable.{self::A::aNull} = new self::A::•() : null; } method notCapturedPropertyCompoundAssignment() → dynamic/* scope=[ - #ctx22: not-captured VariableContext([ + #ctx24: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { this-variable.{self::A::a} = this-variable.{self::A::a}{self::A}.{self::A::+}(new self::A::•()){(self::A) → self::A}; } method capturedMethodCall() → dynamic/* scope=[ - #ctx23: direct-captured VariableContext([ - this-variable final this-variable; - ]), - ] */ { - return () /* #ctx23 */ → dynamic => this-variable.{self::A::method}(){() → dynamic}; - } - method capturedExpression() → dynamic/* scope=[ - #ctx24: direct-captured VariableContext([ - this-variable final this-variable; - ]), - ] */ { - return () /* #ctx24 */ → self::A => this-variable; - } - method capturedPropertyGet() → dynamic/* scope=[ #ctx25: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx25 */ → core::Object? => this-variable.{self::A::field}{core::Object?}; + return () /* #ctx25 */ → dynamic => this-variable.{self::A::method}(){() → dynamic}; } - method capturedPropertySet() → dynamic/* scope=[ + method capturedExpression() → dynamic/* scope=[ #ctx26: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx26 */ → Null { - this-variable.{self::A::field} = null; - }; + return () /* #ctx26 */ → self::A => this-variable; } - method capturedCall() → dynamic/* scope=[ + method capturedPropertyGet() → dynamic/* scope=[ #ctx27: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx27 */ → core::Object? => this-variable.{self::A::call}(){() → core::Object?}; + return () /* #ctx27 */ → core::Object? => this-variable.{self::A::field}{core::Object?}; } - method capturedIndexGet() → dynamic/* scope=[ + method capturedPropertySet() → dynamic/* scope=[ #ctx28: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx28 */ → core::Object? => this-variable.{self::A::[]}(0){(core::int) → core::Object?}; + return () /* #ctx28 */ → Null { + this-variable.{self::A::field} = null; + }; } - method capturedIndexSet() → dynamic/* scope=[ + method capturedCall() → dynamic/* scope=[ #ctx29: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx29 */ → Null { - this-variable.{self::A::[]=}(0, null){(core::int, core::Object?) → void}; - }; + return () /* #ctx29 */ → core::Object? => this-variable.{self::A::call}(){() → core::Object?}; } - method capturedUnary() → dynamic/* scope=[ + method capturedIndexGet() → dynamic/* scope=[ #ctx30: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx30 */ → self::A => this-variable.{self::A::unary-}(){() → self::A}; + return () /* #ctx30 */ → core::Object? => this-variable.{self::A::[]}(0){(core::int) → core::Object?}; } - method capturedBinary() → dynamic/* scope=[ + method capturedIndexSet() → dynamic/* scope=[ #ctx31: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx31 */ → self::A => this-variable.{self::A::+}(this-variable){(self::A) → self::A}; + return () /* #ctx31 */ → Null { + this-variable.{self::A::[]=}(0, null){(core::int, core::Object?) → void}; + }; } - method capturedPropertyCall() → dynamic/* scope=[ + method capturedUnary() → dynamic/* scope=[ #ctx32: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx32 */ → core::Object? => this-variable.{self::A::a}{self::A}.{self::A::call}(){() → core::Object?}; + return () /* #ctx32 */ → self::A => this-variable.{self::A::unary-}(){() → self::A}; } - method capturedPropertyPrefix() → dynamic/* scope=[ + method capturedBinary() → dynamic/* scope=[ #ctx33: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx33 */ → core::int => this-variable.{self::A::n} = this-variable.{self::A::n}{core::int}.{core::num::+}(1){(core::num) → core::int}; + return () /* #ctx33 */ → self::A => this-variable.{self::A::+}(this-variable){(self::A) → self::A}; } - method capturedPropertyPostfix() → dynamic/* scope=[ + method capturedPropertyCall() → dynamic/* scope=[ #ctx34: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx34 */ → core::int => let final core::int #t1 = this-variable.{self::A::n}{core::int} in let final void #t2 = this-variable.{self::A::n} = #t1.{core::num::+}(1){(core::num) → core::int} in #t1; + return () /* #ctx34 */ → core::Object? => this-variable.{self::A::a}{self::A}.{self::A::call}(){() → core::Object?}; } - method capturedPropertyIndexGet() → dynamic/* scope=[ + method capturedPropertyPrefix() → dynamic/* scope=[ #ctx35: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx35 */ → core::Object? => this-variable.{self::A::a}{self::A}.{self::A::[]}(0){(core::int) → core::Object?}; + return () /* #ctx35 */ → core::int => this-variable.{self::A::n} = this-variable.{self::A::n}{core::int}.{core::num::+}(1){(core::num) → core::int}; } - method capturedPropertyIndexSet() → dynamic/* scope=[ + method capturedPropertyPostfix() → dynamic/* scope=[ #ctx36: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx36 */ → Null => let final self::A #t3 = this-variable.{self::A::a}{self::A} in let final core::int #t4 = 0 in let final has-declared-initializer Null #t5 = null in let final void #t6 = #t3.{self::A::[]=}(#t4, #t5){(core::int, core::Object?) → void} in #t5; + return () /* #ctx36 */ → core::int => let final core::int #t1 = this-variable.{self::A::n}{core::int} in let final void #t2 = this-variable.{self::A::n} = #t1.{core::num::+}(1){(core::num) → core::int} in #t1; } - method capturedPropertyIfNullAssignment() → dynamic/* scope=[ + method capturedPropertyIndexGet() → dynamic/* scope=[ #ctx37: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx37 */ → self::A => let final self::A? #t7 = this-variable.{self::A::aNull}{self::A?} in #t7 == null ?{self::A} this-variable.{self::A::aNull} = new self::A::•() : #t7{self::A}; + return () /* #ctx37 */ → core::Object? => this-variable.{self::A::a}{self::A}.{self::A::[]}(0){(core::int) → core::Object?}; } - method capturedPropertyCompoundAssignment() → dynamic/* scope=[ + method capturedPropertyIndexSet() → dynamic/* scope=[ #ctx38: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx38 */ → self::A => this-variable.{self::A::a} = this-variable.{self::A::a}{self::A}.{self::A::+}(new self::A::•()){(self::A) → self::A}; + return () /* #ctx38 */ → Null => let final self::A #t3 = this-variable.{self::A::a}{self::A} in let final core::int #t4 = 0 in let final has-declared-initializer Null #t5 = null in let final void #t6 = #t3.{self::A::[]=}(#t4, #t5){(core::int, core::Object?) → void} in #t5; + } + method capturedPropertyIfNullAssignment() → dynamic/* scope=[ + #ctx39: direct-captured VariableContext([ + this-variable final this-variable; + ]), + ] */ { + return () /* #ctx39 */ → self::A => let final self::A? #t7 = this-variable.{self::A::aNull}{self::A?} in #t7 == null ?{self::A} this-variable.{self::A::aNull} = new self::A::•() : #t7{self::A}; + } + method capturedPropertyCompoundAssignment() → dynamic/* scope=[ + #ctx40: direct-captured VariableContext([ + this-variable final this-variable; + ]), + ] */ { + return () /* #ctx40 */ → self::A => this-variable.{self::A::a} = this-variable.{self::A::a}{self::A}.{self::A::+}(new self::A::•()){(self::A) → self::A}; } } class B extends self::A { @@ -283,7 +291,7 @@ class B extends self::A { ; @#C1 method notCapturedMethodCall() → dynamic/* scope=[ - #ctx39: not-captured VariableContext([ + #ctx41: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -291,7 +299,7 @@ class B extends self::A { } @#C1 method notCapturedPropertyGet() → dynamic/* scope=[ - #ctx40: not-captured VariableContext([ + #ctx42: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -299,7 +307,7 @@ class B extends self::A { } @#C1 method notCapturedPropertySet() → dynamic/* scope=[ - #ctx41: not-captured VariableContext([ + #ctx43: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -307,7 +315,7 @@ class B extends self::A { } @#C1 method notCapturedCall() → dynamic/* scope=[ - #ctx42: not-captured VariableContext([ + #ctx44: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -315,7 +323,7 @@ class B extends self::A { } @#C1 method notCapturedIndexGet() → dynamic/* scope=[ - #ctx43: not-captured VariableContext([ + #ctx45: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -323,7 +331,7 @@ class B extends self::A { } @#C1 method notCapturedIndexSet() → dynamic/* scope=[ - #ctx44: not-captured VariableContext([ + #ctx46: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -331,7 +339,7 @@ class B extends self::A { } @#C1 method notCapturedUnary() → dynamic/* scope=[ - #ctx45: not-captured VariableContext([ + #ctx47: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -339,7 +347,7 @@ class B extends self::A { } @#C1 method notCapturedBinary() → dynamic/* scope=[ - #ctx46: not-captured VariableContext([ + #ctx48: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -347,7 +355,7 @@ class B extends self::A { } @#C1 method notCapturedPropertyCall() → dynamic/* scope=[ - #ctx47: not-captured VariableContext([ + #ctx49: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -355,7 +363,7 @@ class B extends self::A { } @#C1 method notCapturedPropertyPrefix() → dynamic/* scope=[ - #ctx48: not-captured VariableContext([ + #ctx50: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -363,7 +371,7 @@ class B extends self::A { } @#C1 method notCapturedPropertyPostfix() → dynamic/* scope=[ - #ctx49: not-captured VariableContext([ + #ctx51: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -371,7 +379,7 @@ class B extends self::A { } @#C1 method notCapturedPropertyIndexGet() → dynamic/* scope=[ - #ctx50: not-captured VariableContext([ + #ctx52: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -379,7 +387,7 @@ class B extends self::A { } @#C1 method notCapturedPropertyIndexSet() → dynamic/* scope=[ - #ctx51: not-captured VariableContext([ + #ctx53: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -387,7 +395,7 @@ class B extends self::A { } @#C1 method notCapturedPropertyIfNullAssignment() → dynamic/* scope=[ - #ctx52: not-captured VariableContext([ + #ctx54: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -395,7 +403,7 @@ class B extends self::A { } @#C1 method notCapturedPropertyCompoundAssignment() → dynamic/* scope=[ - #ctx53: not-captured VariableContext([ + #ctx55: not-captured VariableContext([ this-variable final this-variable; ]), ] */ { @@ -403,127 +411,127 @@ class B extends self::A { } @#C1 method capturedMethodCall() → dynamic/* scope=[ - #ctx54: direct-captured VariableContext([ - this-variable final this-variable; - ]), - ] */ { - return () /* #ctx54 */ → dynamic => super{this-variable}.{self::A::method}(); - } - @#C1 - method capturedPropertyGet() → dynamic/* scope=[ - #ctx55: direct-captured VariableContext([ - this-variable final this-variable; - ]), - ] */ { - return () /* #ctx55 */ → core::Object? => super{this-variable}.{self::A::field}; - } - @#C1 - method capturedPropertySet() → dynamic/* scope=[ #ctx56: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx56 */ → Null { + return () /* #ctx56 */ → dynamic => super{this-variable}.{self::A::method}(); + } + @#C1 + method capturedPropertyGet() → dynamic/* scope=[ + #ctx57: direct-captured VariableContext([ + this-variable final this-variable; + ]), + ] */ { + return () /* #ctx57 */ → core::Object? => super{this-variable}.{self::A::field}; + } + @#C1 + method capturedPropertySet() → dynamic/* scope=[ + #ctx58: direct-captured VariableContext([ + this-variable final this-variable; + ]), + ] */ { + return () /* #ctx58 */ → Null { super{this-variable}.{self::A::field} = null; }; } @#C1 method capturedCall() → dynamic/* scope=[ - #ctx57: direct-captured VariableContext([ - this-variable final this-variable; - ]), - ] */ { - return () /* #ctx57 */ → core::Object? => super{this-variable}.{self::A::call}(); - } - @#C1 - method capturedIndexGet() → dynamic/* scope=[ - #ctx58: direct-captured VariableContext([ - this-variable final this-variable; - ]), - ] */ { - return () /* #ctx58 */ → core::Object? => super{this-variable}.{self::A::[]}(0); - } - @#C1 - method capturedIndexSet() → dynamic/* scope=[ #ctx59: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx59 */ → Null { + return () /* #ctx59 */ → core::Object? => super{this-variable}.{self::A::call}(); + } + @#C1 + method capturedIndexGet() → dynamic/* scope=[ + #ctx60: direct-captured VariableContext([ + this-variable final this-variable; + ]), + ] */ { + return () /* #ctx60 */ → core::Object? => super{this-variable}.{self::A::[]}(0); + } + @#C1 + method capturedIndexSet() → dynamic/* scope=[ + #ctx61: direct-captured VariableContext([ + this-variable final this-variable; + ]), + ] */ { + return () /* #ctx61 */ → Null { super{this-variable}.{self::A::[]=}(0, null); }; } @#C1 method capturedUnary() → dynamic/* scope=[ - #ctx60: direct-captured VariableContext([ - this-variable final this-variable; - ]), - ] */ { - return () /* #ctx60 */ → self::A => super{this-variable}.{self::A::unary-}(); - } - @#C1 - method capturedBinary() → dynamic/* scope=[ - #ctx61: direct-captured VariableContext([ - this-variable final this-variable; - ]), - ] */ { - return () /* #ctx61 */ → self::A => super{this-variable}.{self::A::+}(this-variable); - } - @#C1 - method capturedPropertyCall() → dynamic/* scope=[ #ctx62: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx62 */ → core::Object? => super{this-variable}.{self::A::a}.{self::A::call}(){() → core::Object?}; + return () /* #ctx62 */ → self::A => super{this-variable}.{self::A::unary-}(); } @#C1 - method capturedPropertyPrefix() → dynamic/* scope=[ + method capturedBinary() → dynamic/* scope=[ #ctx63: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx63 */ → core::int => super{this-variable}.{self::A::n} = super{this-variable}.{self::A::n}.{core::num::+}(1){(core::num) → core::int}; + return () /* #ctx63 */ → self::A => super{this-variable}.{self::A::+}(this-variable); } @#C1 - method capturedPropertyPostfix() → dynamic/* scope=[ + method capturedPropertyCall() → dynamic/* scope=[ #ctx64: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx64 */ → core::int => let final core::int #t8 = super{this-variable}.{self::A::n} in let final void #t9 = super{this-variable}.{self::A::n} = #t8.{core::num::+}(1){(core::num) → core::int} in #t8; + return () /* #ctx64 */ → core::Object? => super{this-variable}.{self::A::a}.{self::A::call}(){() → core::Object?}; } @#C1 - method capturedPropertyIndexGet() → dynamic/* scope=[ + method capturedPropertyPrefix() → dynamic/* scope=[ #ctx65: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx65 */ → core::Object? => super{this-variable}.{self::A::a}.{self::A::[]}(0){(core::int) → core::Object?}; + return () /* #ctx65 */ → core::int => super{this-variable}.{self::A::n} = super{this-variable}.{self::A::n}.{core::num::+}(1){(core::num) → core::int}; } @#C1 - method capturedPropertyIndexSet() → dynamic/* scope=[ + method capturedPropertyPostfix() → dynamic/* scope=[ #ctx66: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx66 */ → Null => let final self::A #t10 = super{this-variable}.{self::A::a} in let final core::int #t11 = 0 in let final has-declared-initializer Null #t12 = null in let final void #t13 = #t10.{self::A::[]=}(#t11, #t12){(core::int, core::Object?) → void} in #t12; + return () /* #ctx66 */ → core::int => let final core::int #t8 = super{this-variable}.{self::A::n} in let final void #t9 = super{this-variable}.{self::A::n} = #t8.{core::num::+}(1){(core::num) → core::int} in #t8; } @#C1 - method capturedPropertyIfNullAssignment() → dynamic/* scope=[ + method capturedPropertyIndexGet() → dynamic/* scope=[ #ctx67: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx67 */ → self::A => let final self::A? #t14 = super{this-variable}.{self::A::aNull} in #t14 == null ?{self::A} super{this-variable}.{self::A::aNull} = new self::A::•() : #t14{self::A}; + return () /* #ctx67 */ → core::Object? => super{this-variable}.{self::A::a}.{self::A::[]}(0){(core::int) → core::Object?}; } @#C1 - method capturedPropertyCompoundAssignment() → dynamic/* scope=[ + method capturedPropertyIndexSet() → dynamic/* scope=[ #ctx68: direct-captured VariableContext([ this-variable final this-variable; ]), ] */ { - return () /* #ctx68 */ → self::A => super{this-variable}.{self::A::a} = super{this-variable}.{self::A::a}.{self::A::+}(new self::A::•()){(self::A) → self::A}; + return () /* #ctx68 */ → Null => let final self::A #t10 = super{this-variable}.{self::A::a} in let final core::int #t11 = 0 in let final has-declared-initializer Null #t12 = null in let final void #t13 = #t10.{self::A::[]=}(#t11, #t12){(core::int, core::Object?) → void} in #t12; + } + @#C1 + method capturedPropertyIfNullAssignment() → dynamic/* scope=[ + #ctx69: direct-captured VariableContext([ + this-variable final this-variable; + ]), + ] */ { + return () /* #ctx69 */ → self::A => let final self::A? #t14 = super{this-variable}.{self::A::aNull} in #t14 == null ?{self::A} super{this-variable}.{self::A::aNull} = new self::A::•() : #t14{self::A}; + } + @#C1 + method capturedPropertyCompoundAssignment() → dynamic/* scope=[ + #ctx70: direct-captured VariableContext([ + this-variable final this-variable; + ]), + ] */ { + return () /* #ctx70 */ → self::A => super{this-variable}.{self::A::a} = super{this-variable}.{self::A::a}.{self::A::+}(new self::A::•()){(self::A) → self::A}; } } diff --git a/pkg/front_end/testcases/modular.status b/pkg/front_end/testcases/modular.status index f427f21328e..aff2248d6a8 100644 --- a/pkg/front_end/testcases/modular.status +++ b/pkg/front_end/testcases/modular.status @@ -33,4 +33,5 @@ closure_context_lowering/catch_variables: Crash closure_context_lowering/synthetic_variables: Crash closure_context_lowering/assert_captured_variables: ExpectationFileMismatchSerialized closure_context_lowering/constructor_initializers: ExpectationFileMismatchSerialized -closure_context_lowering/super_initializing_formal: ExpectationFileMismatchSerialized \ No newline at end of file +closure_context_lowering/super_initializing_formal: ExpectationFileMismatchSerialized +closure_context_lowering/late_field_initializers: Crash \ No newline at end of file diff --git a/pkg/front_end/testcases/strong.status b/pkg/front_end/testcases/strong.status index e2563694750..b858d6402da 100644 --- a/pkg/front_end/testcases/strong.status +++ b/pkg/front_end/testcases/strong.status @@ -272,4 +272,5 @@ closure_context_lowering/catch_variables: Crash closure_context_lowering/synthetic_variables: Crash closure_context_lowering/assert_captured_variables: ExpectationFileMismatchSerialized closure_context_lowering/constructor_initializers: ExpectationFileMismatchSerialized -closure_context_lowering/super_initializing_formal: ExpectationFileMismatchSerialized \ No newline at end of file +closure_context_lowering/super_initializing_formal: ExpectationFileMismatchSerialized +closure_context_lowering/late_field_initializers: Crash \ No newline at end of file diff --git a/pkg/kernel/lib/src/ast/members.dart b/pkg/kernel/lib/src/ast/members.dart index d58c6467bbd..6315e2cac37 100644 --- a/pkg/kernel/lib/src/ast/members.dart +++ b/pkg/kernel/lib/src/ast/members.dart @@ -264,7 +264,7 @@ sealed class Member extends NamedNode implements Annotatable, FileUriNode { /// /// The implied getter and setter for the field are not represented explicitly, /// but can be made explicit if needed. -class Field extends Member { +class Field extends Member implements ScopeProvider { DartType type; // Not null. Defaults to DynamicType. int flags = 0; Expression? initializer; // May be null. @@ -291,6 +291,9 @@ class Field extends Member { /// in the field values of [InstanceConstant]. Reference get fieldReference => super.reference; + @override + Scope? scope; + Field.mutable( Name name, { this.type = const DynamicType(), diff --git a/pkg/kernel/lib/src/equivalence.dart b/pkg/kernel/lib/src/equivalence.dart index 55c79d1aeef..7521736f9f0 100644 --- a/pkg/kernel/lib/src/equivalence.dart +++ b/pkg/kernel/lib/src/equivalence.dart @@ -2342,6 +2342,9 @@ class EquivalenceStrategy { if (!checkField_setterReference(visitor, node, other)) { result = visitor.resultOnInequivalence; } + if (!checkField_scope(visitor, node, other)) { + result = visitor.resultOnInequivalence; + } if (!checkField_fileEndOffset(visitor, node, other)) { result = visitor.resultOnInequivalence; } @@ -8030,6 +8033,10 @@ class EquivalenceStrategy { ); } + bool checkField_scope(EquivalenceVisitor visitor, Field node, Field other) { + return visitor.checkNodes(node.scope, other.scope, 'scope'); + } + bool checkMember_fileEndOffset( EquivalenceVisitor visitor, Member node, diff --git a/pkg/kernel/lib/text/ast_to_text.dart b/pkg/kernel/lib/text/ast_to_text.dart index dd9fd93bb5b..e0010ae8762 100644 --- a/pkg/kernel/lib/text/ast_to_text.dart +++ b/pkg/kernel/lib/text/ast_to_text.dart @@ -1345,6 +1345,9 @@ class Printer extends VisitorDefault with VisitorVoidMixin { writeSpace(); writeAnnotatedType(node.type, annotator?.annotateField(this, node)); writeName(getMemberName(node), showLibrary: true); + if (node.scope case Scope scope?) { + writeScope(scope); + } Expression? initializer = node.initializer; if (initializer != null) { writeSpaced('=');