| // Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| import 'package:_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/types/shared_type.dart'; | |
| import 'package:front_end/src/codes/diagnostic.dart' as diag; | |
| import 'package:kernel/ast.dart'; | |
| import 'package:kernel/class_hierarchy.dart'; | |
| import 'package:kernel/clone.dart'; | |
| import 'package:kernel/core_types.dart'; | |
| import 'package:kernel/type_environment.dart'; | |
| import '../api_prototype/experimental_flags.dart'; | |
| import '../base/compiler_context.dart'; | |
| import '../base/constant_context.dart' show ConstantContext; | |
| import '../base/crash.dart'; | |
| import '../base/extension_scope.dart'; | |
| import '../base/identifiers.dart'; | |
| import '../base/local_scope.dart'; | |
| import '../base/lookup_result.dart'; | |
| import '../base/messages.dart'; | |
| import '../base/modifiers.dart'; | |
| import '../base/problems.dart'; | |
| import '../base/scope.dart'; | |
| import '../builder/declaration_builders.dart'; | |
| import '../builder/formal_parameter_builder.dart'; | |
| import '../builder/member_builder.dart'; | |
| import '../builder/metadata_builder.dart'; | |
| import '../builder/omitted_type_builder.dart'; | |
| import '../builder/type_builder.dart'; | |
| import '../dill/dill_type_parameter_builder.dart'; | |
| import '../fragment/fragment.dart'; | |
| import '../source/check_helper.dart'; | |
| import '../source/offset_map.dart'; | |
| import '../source/source_constructor_builder.dart'; | |
| import '../source/source_library_builder.dart'; | |
| import '../source/stack_listener_impl.dart' show AsyncModifier; | |
| import '../type_inference/context_allocation_strategy.dart'; | |
| import '../type_inference/inference_results.dart'; | |
| import '../type_inference/type_inference_engine.dart'; | |
| import '../type_inference/type_inferrer.dart' | |
| show | |
| TypeInferrer, | |
| InferredConstructorInitializers, | |
| InferredFieldInitializer, | |
| InferredFunctionBody; | |
| import '../type_inference/type_schema.dart'; | |
| import '../util/expression_evaluation_helpers.dart'; | |
| import '../util/helpers.dart'; | |
| import 'assigned_variables_impl.dart'; | |
| import 'benchmarker.dart' show Benchmarker, BenchmarkSubdivides; | |
| import 'body_builder.dart'; | |
| import 'body_builder_context.dart'; | |
| import 'expression_compilation_data.dart'; | |
| import 'external_ast_helper.dart' as extern; | |
| import 'internal_ast.dart'; | |
| import 'internal_ast_helper.dart' as intern; | |
| part 'resolver_helpers.dart'; | |
| class Resolver { | |
| final ClassHierarchy _classHierarchy; | |
| final CoreTypes _coreTypes; | |
| final TypeInferenceEngineImpl _typeInferenceEngine; | |
| final Benchmarker? _benchmarker; | |
| new({ | |
| required ClassHierarchy classHierarchy, | |
| required CoreTypes coreTypes, | |
| required TypeInferenceEngineImpl typeInferenceEngine, | |
| required Benchmarker? benchmarker, | |
| }) : this._classHierarchy = classHierarchy, | |
| this._coreTypes = coreTypes, | |
| _typeInferenceEngine = typeInferenceEngine, | |
| _benchmarker = benchmarker; | |
| void buildAnnotations({ | |
| required SourceLibraryBuilder libraryBuilder, | |
| required BodyBuilderContext bodyBuilderContext, | |
| required Uri annotationsFileUri, | |
| required ExtensionScope extensionScope, | |
| required LookupScope scope, | |
| required Annotatable annotatable, | |
| required List<Annotation> annotations, | |
| }) { | |
| _ResolverContext context = new _ResolverContext( | |
| typeInferenceEngine: _typeInferenceEngine, | |
| libraryBuilder: libraryBuilder, | |
| bodyBuilderContext: bodyBuilderContext, | |
| extensionScope: extensionScope, | |
| fileUri: annotationsFileUri, | |
| ); | |
| // TODO(johnniwinther): Should this be `ConstantContext.required`? | |
| ConstantContext constantContext = ConstantContext.none; | |
| BodyBuilder bodyBuilder = _createBodyBuilder( | |
| context: context, | |
| bodyBuilderContext: bodyBuilderContext, | |
| scope: scope, | |
| constantContext: constantContext, | |
| thisVariable: null, | |
| thisTypeParameters: null, | |
| formalParameterScope: null, | |
| internalThisVariable: null, | |
| ); | |
| List<InternalExpression> annotationsToBeInferred = []; | |
| for (Annotation annotation in annotations) { | |
| InternalExpression expression = bodyBuilder.buildAnnotation( | |
| atToken: annotation.atToken, | |
| ); | |
| if (annotation.createFileUriExpression) { | |
| expression = intern.createFileUriExpression( | |
| expression: expression, | |
| fileUri: annotation.metadataBuilder.fileUri, | |
| fileOffset: annotation.metadataBuilder.atOffset, | |
| ); | |
| } | |
| // It is important for the inference and backlog computations that the | |
| // annotation is already a child of [parent]. | |
| // TODO(johnniwinther): Is the parent relation still needed? | |
| annotationsToBeInferred.add(expression); | |
| } | |
| List<Expression> inferredAnnotations = context.inferSingleTargetAnnotation( | |
| singleTarget: new SingleTargetAnnotations( | |
| new DelegatingAnnotatable(annotatable), | |
| annotationsToBeInferred, | |
| ), | |
| ); | |
| // TODO(johnniwinther): We need to process annotations within annotations. | |
| context.performBacklog(null); | |
| for (int index = 0; index < annotations.length; index++) { | |
| annotations[index].expression = inferredAnnotations[index]; | |
| } | |
| } | |
| (Expression, DartType?) buildEnumConstant({ | |
| required SourceLibraryBuilder libraryBuilder, | |
| required BodyBuilderContext bodyBuilderContext, | |
| required ExtensionScope extensionScope, | |
| required LookupScope scope, | |
| required Token? token, | |
| required List<Argument> enumSyntheticArguments, | |
| required int enumTypeParameterCount, | |
| required TypeArguments? typeArguments, | |
| required MemberBuilder? constructorBuilder, | |
| required Uri fileUri, | |
| required int fileOffset, | |
| required String fullConstructorNameForErrors, | |
| }) { | |
| _ResolverContext context = new _ResolverContext( | |
| typeInferenceEngine: _typeInferenceEngine, | |
| libraryBuilder: libraryBuilder, | |
| bodyBuilderContext: bodyBuilderContext, | |
| extensionScope: extensionScope, | |
| fileUri: fileUri, | |
| ); | |
| CompilerContext compilerContext = libraryBuilder.loader.target.context; | |
| ProblemReporting problemReporting = libraryBuilder; | |
| LibraryFeatures libraryFeatures = libraryBuilder.libraryFeatures; | |
| ConstantContext constantContext = ConstantContext.inferred; | |
| // We need to create a BodyBuilder to solve the following: 1) if | |
| // the arguments token is provided, we'll use the BodyBuilder to | |
| // parse them and perform inference, 2) if the type arguments | |
| // aren't provided, but required, we'll use it to infer them, and | |
| // 3) in case of erroneous code the constructor invocation should | |
| // be built via a body builder to detect potential errors. | |
| BodyBuilder bodyBuilder = _createBodyBuilder( | |
| context: context, | |
| bodyBuilderContext: bodyBuilderContext, | |
| scope: scope, | |
| constantContext: constantContext, | |
| thisVariable: null, | |
| thisTypeParameters: null, | |
| formalParameterScope: null, | |
| internalThisVariable: null, | |
| ); | |
| BuildEnumConstantResult? result; | |
| ActualArguments arguments; | |
| if (token != null) { | |
| result = bodyBuilder.buildEnumConstant(token: token); | |
| arguments = result.arguments; | |
| arguments.prependArguments( | |
| enumSyntheticArguments, | |
| positionalCount: enumSyntheticArguments.length, | |
| ); | |
| } else { | |
| arguments = new ActualArguments( | |
| argumentList: enumSyntheticArguments, | |
| hasNamedBeforePositional: false, | |
| positionalCount: enumSyntheticArguments.length, | |
| fileOffset: TreeNode.noOffset, | |
| ); | |
| } | |
| Expression initializer; | |
| DartType? fieldType; | |
| if (constructorBuilder == null || | |
| constructorBuilder is! SourceConstructorBuilder) { | |
| initializer = _buildUnresolvedError( | |
| compilerContext: compilerContext, | |
| problemReporting: problemReporting, | |
| name: fullConstructorNameForErrors, | |
| fileUri: fileUri, | |
| fileOffset: fileOffset, | |
| ); | |
| } else { | |
| InternalExpression internalInitializer = _buildConstructorInvocation( | |
| compilerContext: compilerContext, | |
| problemReporting: problemReporting, | |
| libraryFeatures: libraryFeatures, | |
| typeEnvironment: context.typeEnvironment, | |
| target: constructorBuilder.invokeTarget, | |
| typeArguments: typeArguments, | |
| arguments: arguments, | |
| fileUri: fileUri, | |
| fileOffset: fileOffset, | |
| hasInferredTypeArguments: false, | |
| ); | |
| InternalThisVariable? internalThisVariable = bodyBuilderContext | |
| .createInternalThisVariable(); | |
| ExpressionInferenceResult inferenceResult = context.typeInferrer | |
| .inferFieldInitializer( | |
| fileUri: fileUri, | |
| declaredType: const UnknownType(), | |
| initializer: internalInitializer, | |
| inferenceDefaultType: InferenceDefaultType.Dynamic, | |
| internalThisVariable: internalThisVariable, | |
| thisType: | |
| internalThisVariable | |
| // Coverage-ignore(suite): Not run. | |
| ?.type ?? | |
| bodyBuilderContext.thisType, | |
| ) | |
| .expressionInferenceResult; | |
| initializer = inferenceResult.expression; | |
| fieldType = inferenceResult.inferredType; | |
| } | |
| context.performBacklog(result?.annotations); | |
| return (initializer, fieldType); | |
| } | |
| InferredFieldInitializer buildFieldInitializer({ | |
| required SourceLibraryBuilder libraryBuilder, | |
| required BodyBuilderContext bodyBuilderContext, | |
| required Uri fileUri, | |
| required ExtensionScope extensionScope, | |
| required LookupScope scope, | |
| required bool isLate, | |
| DartType? fieldType, | |
| required Token startToken, | |
| required InferenceDataForTesting? inferenceDataForTesting, | |
| required InferenceDefaultType inferenceDefaultType, | |
| }) { | |
| _ResolverContext context = new _ResolverContext( | |
| typeInferenceEngine: _typeInferenceEngine, | |
| libraryBuilder: libraryBuilder, | |
| bodyBuilderContext: bodyBuilderContext, | |
| extensionScope: extensionScope, | |
| fileUri: fileUri, | |
| ); | |
| ConstantContext constantContext = bodyBuilderContext.constantContext; | |
| List<FormalParameterBuilder>? primaryConstructorInitializerScopeParameters = | |
| bodyBuilderContext.primaryConstructorInitializerScopeParameters; | |
| InternalThisVariable? internalThisVariable = bodyBuilderContext | |
| .createInternalThisVariable(); | |
| BodyBuilder bodyBuilder = _createBodyBuilder( | |
| context: context, | |
| bodyBuilderContext: bodyBuilderContext, | |
| scope: scope, | |
| constantContext: constantContext, | |
| thisVariable: null, | |
| thisTypeParameters: null, | |
| formalParameterScope: null, | |
| internalThisVariable: internalThisVariable, | |
| ); | |
| BuildFieldInitializerResult result = bodyBuilder.buildFieldInitializer( | |
| startToken: startToken, | |
| isLate: isLate, | |
| ); | |
| _declareFormals( | |
| typeInferrer: context.typeInferrer, | |
| bodyBuilderContext: bodyBuilderContext, | |
| thisVariable: null, | |
| formals: primaryConstructorInitializerScopeParameters, | |
| ); | |
| InferredFieldInitializer inferredFieldInitializer = context.typeInferrer | |
| .inferFieldInitializer( | |
| fileUri: fileUri, | |
| declaredType: fieldType, | |
| initializer: result.initializer, | |
| inferenceDefaultType: inferenceDefaultType, | |
| internalThisVariable: internalThisVariable, | |
| thisType: internalThisVariable?.type ?? bodyBuilderContext.thisType, | |
| ); | |
| context.performBacklog(result.annotations); | |
| return inferredFieldInitializer; | |
| } | |
| void buildFields({ | |
| required SourceLibraryBuilder libraryBuilder, | |
| required BodyBuilderContext bodyBuilderContext, | |
| required Uri fileUri, | |
| required OffsetMap offsetMap, | |
| required ExtensionScope extensionScope, | |
| required LookupScope scope, | |
| required InferenceDataForTesting? inferenceDataForTesting, | |
| required Token startToken, | |
| required Token? metadata, | |
| required bool isTopLevel, | |
| }) { | |
| // TODO(paulberry): don't re-parse the field if we've already parsed it | |
| // for type inference. | |
| _ResolverContext context = new _ResolverContext( | |
| typeInferenceEngine: _typeInferenceEngine, | |
| libraryBuilder: libraryBuilder, | |
| bodyBuilderContext: bodyBuilderContext, | |
| extensionScope: extensionScope, | |
| fileUri: fileUri, | |
| inferenceDataForTesting: inferenceDataForTesting, | |
| ); | |
| ConstantContext constantContext = bodyBuilderContext.constantContext; | |
| List<FormalParameterBuilder>? primaryConstructorInitializerScopeParameters = | |
| bodyBuilderContext.primaryConstructorInitializerScopeParameters; | |
| BodyBuilder bodyBuilder = _createBodyBuilder( | |
| context: context, | |
| bodyBuilderContext: bodyBuilderContext, | |
| scope: scope, | |
| constantContext: constantContext, | |
| thisVariable: null, | |
| thisTypeParameters: null, | |
| formalParameterScope: null, | |
| // TODO(cstefantsova): Should a [ThisVariable] be created here? | |
| internalThisVariable: null, | |
| ); | |
| BuildFieldsResult result = bodyBuilder.buildFields( | |
| startToken: startToken, | |
| metadata: metadata, | |
| isTopLevel: isTopLevel, | |
| ); | |
| _declareFormals( | |
| typeInferrer: context.typeInferrer, | |
| bodyBuilderContext: bodyBuilderContext, | |
| thisVariable: null, | |
| formals: primaryConstructorInitializerScopeParameters, | |
| ); | |
| for (MapEntry<Identifier, InternalExpression?> entry | |
| in result.fieldInitializers.entries) { | |
| Identifier identifier = entry.key; | |
| InternalExpression? initializer = entry.value; | |
| FieldFragment fieldFragment = offsetMap.lookupField(identifier); | |
| fieldFragment.declaration.buildFieldInitializer( | |
| typeInferrer: context.typeInferrer, | |
| coreTypes: _coreTypes, | |
| fileUri: fileUri, | |
| initializer: initializer, | |
| internalThisVariable: bodyBuilderContext.createInternalThisVariable(), | |
| bodyBuilderContext: bodyBuilderContext, | |
| ); | |
| } | |
| context.performBacklog(result.annotations); | |
| } | |
| void buildFunctionBody({ | |
| required SourceLibraryBuilder libraryBuilder, | |
| required FunctionBodyBuildingContext functionBodyBuildingContext, | |
| required Uri fileUri, | |
| required Token startToken, | |
| required Token? metadata, | |
| }) { | |
| _benchmarker | |
| // Coverage-ignore(suite): Not run. | |
| ?.beginSubdivide(BenchmarkSubdivides.resolver_buildFunctionBody); | |
| CompilerContext compilerContext = libraryBuilder.loader.target.context; | |
| ProblemReporting problemReporting = libraryBuilder; | |
| LibraryFeatures libraryFeatures = libraryBuilder.libraryFeatures; | |
| ExtensionScope extensionScope = functionBodyBuildingContext.extensionScope; | |
| LookupScope typeParameterScope = | |
| functionBodyBuildingContext.typeParameterScope; | |
| LocalScope formalParameterScope = | |
| functionBodyBuildingContext.formalParameterScope; | |
| BodyBuilderContext bodyBuilderContext = functionBodyBuildingContext | |
| .createBodyBuilderContext(); | |
| _ResolverContext context = new _ResolverContext( | |
| typeInferenceEngine: _typeInferenceEngine, | |
| libraryBuilder: libraryBuilder, | |
| bodyBuilderContext: bodyBuilderContext, | |
| extensionScope: extensionScope, | |
| fileUri: fileUri, | |
| inferenceDataForTesting: | |
| functionBodyBuildingContext.inferenceDataForTesting, | |
| ); | |
| ConstantContext constantContext = bodyBuilderContext.constantContext; | |
| InternalThisVariable? internalThisVariable = bodyBuilderContext | |
| .createInternalThisVariable(); | |
| BodyBuilder bodyBuilder = _createBodyBuilder( | |
| context: context, | |
| bodyBuilderContext: bodyBuilderContext, | |
| scope: typeParameterScope, | |
| thisVariable: functionBodyBuildingContext.thisVariable, | |
| thisTypeParameters: functionBodyBuildingContext.thisTypeParameters, | |
| formalParameterScope: formalParameterScope, | |
| constantContext: constantContext, | |
| internalThisVariable: internalThisVariable, | |
| ); | |
| Token token = startToken; | |
| try { | |
| BuildFunctionBodyResult result = bodyBuilder.buildFunctionBody( | |
| startToken: startToken, | |
| metadata: metadata, | |
| kind: functionBodyBuildingContext.memberKind, | |
| ); | |
| _finishFunction( | |
| context: context, | |
| compilerContext: compilerContext, | |
| problemReporting: problemReporting, | |
| libraryBuilder: libraryBuilder, | |
| libraryFeatures: libraryFeatures, | |
| asyncModifier: result.asyncModifier, | |
| body: result.body, | |
| fileUri: fileUri, | |
| bodyBuilderContext: bodyBuilderContext, | |
| thisVariable: functionBodyBuildingContext.thisVariable, | |
| initializers: result.initializers, | |
| constantContext: constantContext, | |
| internalThisVariable: internalThisVariable, | |
| forPrimaryConstructor: false, | |
| isImplementation: functionBodyBuildingContext.isImplementation, | |
| ); | |
| context.performBacklog(result.annotations); | |
| } | |
| // Coverage-ignore(suite): Not run. | |
| on DebugAbort { | |
| rethrow; | |
| } catch (e, s) { | |
| throw new Crash(fileUri, token.charOffset, e, s); | |
| } | |
| _benchmarker | |
| // Coverage-ignore(suite): Not run. | |
| ?.endSubdivide(); | |
| } | |
| void buildInitializers({ | |
| required SourceLibraryBuilder libraryBuilder, | |
| required SourceConstructorBuilder constructorBuilder, | |
| required BodyBuilderContext bodyBuilderContext, | |
| required ExtensionScope extensionScope, | |
| required LookupScope typeParameterScope, | |
| required LocalScope? formalParameterScope, | |
| required Uri fileUri, | |
| required Token? beginInitializers, | |
| required bool isConst, | |
| required bool forPrimaryConstructor, | |
| required bool isImplementation, | |
| }) { | |
| _ResolverContext context = new _ResolverContext( | |
| typeInferenceEngine: _typeInferenceEngine, | |
| libraryBuilder: libraryBuilder, | |
| bodyBuilderContext: bodyBuilderContext, | |
| extensionScope: extensionScope, | |
| fileUri: fileUri, | |
| ); | |
| CompilerContext compilerContext = libraryBuilder.loader.target.context; | |
| ProblemReporting problemReporting = libraryBuilder; | |
| LibraryFeatures libraryFeatures = libraryBuilder.libraryFeatures; | |
| ConstantContext constantContext = bodyBuilderContext.constantContext; | |
| InternalThisVariable? internalThisVariable = bodyBuilderContext | |
| .createInternalThisVariable(); | |
| BodyBuilder bodyBuilder = _createBodyBuilder( | |
| context: context, | |
| bodyBuilderContext: bodyBuilderContext, | |
| scope: typeParameterScope, | |
| constantContext: constantContext, | |
| formalParameterScope: formalParameterScope, | |
| thisVariable: null, | |
| thisTypeParameters: null, | |
| internalThisVariable: internalThisVariable, | |
| ); | |
| constructorBuilder.inferFormalTypes(_classHierarchy); | |
| BuildInitializersResult result = bodyBuilder.buildInitializers( | |
| beginInitializers: beginInitializers, | |
| ); | |
| List<InternalInitializer> initializers = result.initializers; | |
| if (isConst) { | |
| List<FormalParameterBuilder>? formals = bodyBuilderContext.formals; | |
| _SuperParameterArguments? superParameterArguments = | |
| _createSuperParameterArguments( | |
| assignedVariables: context.typeInferrer.assignedVariables, | |
| formals: formals, | |
| ); | |
| _declareFormals( | |
| typeInferrer: context.typeInferrer, | |
| bodyBuilderContext: bodyBuilderContext, | |
| thisVariable: null, | |
| formals: bodyBuilderContext.formals, | |
| ); | |
| _finishConstructor( | |
| context: context, | |
| compilerContext: compilerContext, | |
| problemReporting: problemReporting, | |
| libraryBuilder: libraryBuilder, | |
| libraryFeatures: libraryFeatures, | |
| bodyBuilderContext: bodyBuilderContext, | |
| asyncModifier: AsyncModifier.implicitSync, | |
| body: null, | |
| superParameterArguments: superParameterArguments, | |
| fileUri: fileUri, | |
| constantContext: constantContext, | |
| initializers: initializers, | |
| forPrimaryConstructor: forPrimaryConstructor, | |
| isImplementation: isImplementation, | |
| parameters: [ | |
| for (FormalParameterBuilder formal | |
| in bodyBuilderContext.formals ?? []) | |
| formal.variable, | |
| ], | |
| internalThisVariable: internalThisVariable, | |
| contextAllocationStrategy: | |
| ContextAllocationStrategy.createContextAllocationStrategy( | |
| isClosureContextLoweringEnabled: | |
| libraryBuilder.loader.isClosureContextLoweringEnabled, | |
| ), | |
| ); | |
| } | |
| context.performBacklog(result.annotations); | |
| } | |
| List<InternalInitializer> buildInitializersUnfinished({ | |
| required SourceLibraryBuilder libraryBuilder, | |
| required BodyBuilderContext bodyBuilderContext, | |
| required ExtensionScope extensionScope, | |
| required LookupScope typeParameterScope, | |
| required Uri fileUri, | |
| required Token? beginInitializers, | |
| required bool isConst, | |
| }) { | |
| _ResolverContext context = new _ResolverContext( | |
| typeInferenceEngine: _typeInferenceEngine, | |
| libraryBuilder: libraryBuilder, | |
| bodyBuilderContext: bodyBuilderContext, | |
| extensionScope: extensionScope, | |
| fileUri: fileUri, | |
| ); | |
| ConstantContext constantContext = isConst | |
| ? ConstantContext.required | |
| : ConstantContext.none; | |
| BodyBuilder bodyBuilder = _createBodyBuilder( | |
| context: context, | |
| bodyBuilderContext: bodyBuilderContext, | |
| scope: typeParameterScope, | |
| constantContext: constantContext, | |
| thisVariable: null, | |
| thisTypeParameters: null, | |
| // TODO(johnniwinther): Should we provide this? | |
| formalParameterScope: null, | |
| // TODO(cstefantsova): Should a [ThisVariable] be created here? | |
| internalThisVariable: null, | |
| ); | |
| return bodyBuilder.buildInitializersUnfinished( | |
| beginInitializers: beginInitializers, | |
| ); | |
| } | |
| List<Expression>? buildMetadata({ | |
| required SourceLibraryBuilder libraryBuilder, | |
| required BodyBuilderContext bodyBuilderContext, | |
| required Uri fileUri, | |
| required ExtensionScope extensionScope, | |
| required LookupScope scope, | |
| required Token metadata, | |
| required Annotatable annotatable, | |
| }) { | |
| _ResolverContext context = new _ResolverContext( | |
| typeInferenceEngine: _typeInferenceEngine, | |
| libraryBuilder: libraryBuilder, | |
| bodyBuilderContext: bodyBuilderContext, | |
| extensionScope: extensionScope, | |
| fileUri: fileUri, | |
| ); | |
| ConstantContext constantContext = bodyBuilderContext.constantContext; | |
| BodyBuilder bodyBuilder = _createBodyBuilder( | |
| context: context, | |
| bodyBuilderContext: bodyBuilderContext, | |
| scope: scope, | |
| constantContext: constantContext, | |
| thisVariable: null, | |
| thisTypeParameters: null, | |
| formalParameterScope: null, | |
| internalThisVariable: null, | |
| ); | |
| BuildMetadataListResult result = bodyBuilder.buildMetadataList( | |
| metadata: metadata, | |
| ); | |
| // The invocation of [resolveRedirectingFactoryTargets] below may change the | |
| // root nodes of the annotation expressions. We need to have a parent of | |
| // the annotation nodes before the resolution is performed, to collect and | |
| // return them later. If [parent] is not provided, [temporaryParent] is | |
| // used. | |
| // TODO(johnniwinther): Do we still need this. | |
| List<Expression> expressions = context.inferSingleTargetAnnotation( | |
| singleTarget: new SingleTargetAnnotations( | |
| new DelegatingAnnotatable(annotatable), | |
| result.expressions, | |
| ), | |
| ); | |
| context.performBacklog(result.annotations); | |
| return expressions; | |
| } | |
| Expression buildParameterDefaultValue({ | |
| required SourceLibraryBuilder libraryBuilder, | |
| required BodyBuilderContext bodyBuilderContext, | |
| required ExtensionScope extensionScope, | |
| required LookupScope scope, | |
| required Uri fileUri, | |
| required Token defaultValueToken, | |
| required DartType declaredType, | |
| required bool hasDeclaredDefaultValue, | |
| }) { | |
| _ResolverContext context = new _ResolverContext( | |
| typeInferenceEngine: _typeInferenceEngine, | |
| libraryBuilder: libraryBuilder, | |
| bodyBuilderContext: bodyBuilderContext, | |
| extensionScope: extensionScope, | |
| fileUri: fileUri, | |
| ); | |
| ConstantContext constantContext = ConstantContext.required; | |
| BodyBuilder bodyBuilder = _createBodyBuilder( | |
| context: context, | |
| bodyBuilderContext: bodyBuilderContext, | |
| scope: scope, | |
| constantContext: constantContext, | |
| thisVariable: null, | |
| thisTypeParameters: null, | |
| formalParameterScope: null, | |
| internalThisVariable: null, | |
| ); | |
| BuildParameterDefaultValueResult result = bodyBuilder | |
| .buildParameterDefaultValue(initializerToken: defaultValueToken); | |
| Expression defaultValue = context.typeInferrer.inferParameterDefaultValue( | |
| fileUri: fileUri, | |
| defaultValue: result.defaultValue, | |
| declaredType: declaredType, | |
| hasDeclaredDefaultValue: hasDeclaredDefaultValue, | |
| ); | |
| context.performBacklog(result.annotations); | |
| return defaultValue; | |
| } | |
| void buildPrimaryConstructor({ | |
| required SourceLibraryBuilder libraryBuilder, | |
| required FunctionBodyBuildingContext functionBodyBuildingContext, | |
| required Uri fileUri, | |
| required Token startToken, | |
| required bool finishFunction, | |
| }) { | |
| _benchmarker | |
| // Coverage-ignore(suite): Not run. | |
| ?.beginSubdivide(BenchmarkSubdivides.diet_listener_buildPrimaryConstructor); | |
| CompilerContext compilerContext = libraryBuilder.loader.target.context; | |
| ProblemReporting problemReporting = libraryBuilder; | |
| LibraryFeatures libraryFeatures = libraryBuilder.libraryFeatures; | |
| ExtensionScope extensionScope = functionBodyBuildingContext.extensionScope; | |
| LookupScope typeParameterScope = | |
| functionBodyBuildingContext.typeParameterScope; | |
| LocalScope formalParameterScope = | |
| functionBodyBuildingContext.formalParameterScope; | |
| BodyBuilderContext bodyBuilderContext = functionBodyBuildingContext | |
| .createBodyBuilderContext(); | |
| _ResolverContext context = new _ResolverContext( | |
| typeInferenceEngine: _typeInferenceEngine, | |
| libraryBuilder: libraryBuilder, | |
| bodyBuilderContext: bodyBuilderContext, | |
| extensionScope: extensionScope, | |
| fileUri: fileUri, | |
| inferenceDataForTesting: | |
| functionBodyBuildingContext.inferenceDataForTesting, | |
| ); | |
| ConstantContext constantContext = bodyBuilderContext.constantContext; | |
| InternalThisVariable? internalThisVariable = bodyBuilderContext | |
| .createInternalThisVariable(); | |
| BodyBuilder bodyBuilder = _createBodyBuilder( | |
| context: context, | |
| bodyBuilderContext: bodyBuilderContext, | |
| scope: typeParameterScope, | |
| thisVariable: functionBodyBuildingContext.thisVariable, | |
| thisTypeParameters: functionBodyBuildingContext.thisTypeParameters, | |
| formalParameterScope: formalParameterScope, | |
| constantContext: constantContext, | |
| internalThisVariable: internalThisVariable, | |
| ); | |
| try { | |
| BuildPrimaryConstructorResult result = bodyBuilder | |
| .buildPrimaryConstructor(startToken: startToken); | |
| if (finishFunction) { | |
| _finishFunction( | |
| context: context, | |
| compilerContext: compilerContext, | |
| problemReporting: problemReporting, | |
| libraryBuilder: libraryBuilder, | |
| libraryFeatures: libraryFeatures, | |
| asyncModifier: AsyncModifier.implicitSync, | |
| body: null, | |
| fileUri: fileUri, | |
| bodyBuilderContext: bodyBuilderContext, | |
| thisVariable: functionBodyBuildingContext.thisVariable, | |
| initializers: result.initializers, | |
| constantContext: constantContext, | |
| internalThisVariable: internalThisVariable, | |
| forPrimaryConstructor: true, | |
| isImplementation: functionBodyBuildingContext.isImplementation, | |
| ); | |
| } | |
| context.performBacklog(result.annotations); | |
| } | |
| // Coverage-ignore(suite): Not run. | |
| on DebugAbort { | |
| rethrow; | |
| } catch (e, s) { | |
| throw new Crash(fileUri, startToken.charOffset, e, s); | |
| } | |
| _benchmarker | |
| // Coverage-ignore(suite): Not run. | |
| ?.endSubdivide(); | |
| } | |
| void buildPrimaryConstructorBody({ | |
| required SourceLibraryBuilder libraryBuilder, | |
| required SourceConstructorBuilder constructorBuilder, | |
| required FunctionBodyBuildingContext functionBodyBuildingContext, | |
| required Uri fileUri, | |
| required Token thisToken, | |
| required Token? metadata, | |
| }) { | |
| _benchmarker | |
| // Coverage-ignore(suite): Not run. | |
| ?.beginSubdivide( | |
| BenchmarkSubdivides.diet_listener_buildPrimaryConstructorBody, | |
| ); | |
| ExtensionScope extensionScope = functionBodyBuildingContext.extensionScope; | |
| LookupScope typeParameterScope = | |
| functionBodyBuildingContext.typeParameterScope; | |
| LocalScope formalParameterScope = | |
| functionBodyBuildingContext.formalParameterScope; | |
| BodyBuilderContext bodyBuilderContext = functionBodyBuildingContext | |
| .createBodyBuilderContext(); | |
| _ResolverContext context = new _ResolverContext( | |
| typeInferenceEngine: _typeInferenceEngine, | |
| libraryBuilder: libraryBuilder, | |
| bodyBuilderContext: bodyBuilderContext, | |
| extensionScope: extensionScope, | |
| fileUri: fileUri, | |
| ); | |
| CompilerContext compilerContext = libraryBuilder.loader.target.context; | |
| ProblemReporting problemReporting = libraryBuilder; | |
| LibraryFeatures libraryFeatures = libraryBuilder.libraryFeatures; | |
| ConstantContext constantContext = bodyBuilderContext.constantContext; | |
| InternalThisVariable? internalThisVariable = bodyBuilderContext | |
| .createInternalThisVariable(); | |
| BodyBuilder bodyBuilder = _createBodyBuilder( | |
| context: context, | |
| bodyBuilderContext: bodyBuilderContext, | |
| scope: typeParameterScope, | |
| constantContext: constantContext, | |
| formalParameterScope: formalParameterScope, | |
| thisVariable: functionBodyBuildingContext.thisVariable, | |
| thisTypeParameters: functionBodyBuildingContext.thisTypeParameters, | |
| internalThisVariable: internalThisVariable, | |
| ); | |
| constructorBuilder.inferFormalTypes(_classHierarchy); | |
| try { | |
| BuildPrimaryConstructorBodyResult result = bodyBuilder | |
| .buildPrimaryConstructorBody( | |
| thisToken: thisToken, | |
| metadata: metadata, | |
| ); | |
| _finishFunction( | |
| context: context, | |
| compilerContext: compilerContext, | |
| problemReporting: problemReporting, | |
| libraryBuilder: libraryBuilder, | |
| libraryFeatures: libraryFeatures, | |
| bodyBuilderContext: bodyBuilderContext, | |
| asyncModifier: result.asyncModifier, | |
| body: result.body, | |
| fileUri: fileUri, | |
| constantContext: constantContext, | |
| initializers: result.initializers, | |
| thisVariable: functionBodyBuildingContext.thisVariable, | |
| internalThisVariable: internalThisVariable, | |
| forPrimaryConstructor: true, | |
| isImplementation: functionBodyBuildingContext.isImplementation, | |
| ); | |
| context.performBacklog(result.annotations); | |
| } | |
| // Coverage-ignore(suite): Not run. | |
| on DebugAbort { | |
| rethrow; | |
| } catch (e, s) { | |
| throw new Crash(fileUri, thisToken.charOffset, e, s); | |
| } | |
| _benchmarker | |
| // Coverage-ignore(suite): Not run. | |
| ?.endSubdivide(); | |
| } | |
| void buildRedirectingFactoryMethod({ | |
| required SourceLibraryBuilder libraryBuilder, | |
| required FunctionBodyBuildingContext functionBodyBuildingContext, | |
| required Uri fileUri, | |
| required Token token, | |
| required Token? metadata, | |
| }) { | |
| _benchmarker | |
| // Coverage-ignore(suite): Not run. | |
| ?.beginSubdivide( | |
| BenchmarkSubdivides.diet_listener_buildRedirectingFactoryMethod, | |
| ); | |
| ExtensionScope extensionScope = functionBodyBuildingContext.extensionScope; | |
| LookupScope typeParameterScope = | |
| functionBodyBuildingContext.typeParameterScope; | |
| LocalScope formalParameterScope = | |
| functionBodyBuildingContext.formalParameterScope; | |
| BodyBuilderContext bodyBuilderContext = functionBodyBuildingContext | |
| .createBodyBuilderContext(); | |
| _ResolverContext context = new _ResolverContext( | |
| typeInferenceEngine: _typeInferenceEngine, | |
| libraryBuilder: libraryBuilder, | |
| bodyBuilderContext: bodyBuilderContext, | |
| extensionScope: extensionScope, | |
| fileUri: fileUri, | |
| inferenceDataForTesting: | |
| functionBodyBuildingContext.inferenceDataForTesting, | |
| ); | |
| ConstantContext constantContext = bodyBuilderContext.constantContext; | |
| BodyBuilder bodyBuilder = _createBodyBuilder( | |
| context: context, | |
| bodyBuilderContext: bodyBuilderContext, | |
| scope: typeParameterScope, | |
| thisVariable: functionBodyBuildingContext.thisVariable, | |
| thisTypeParameters: functionBodyBuildingContext.thisTypeParameters, | |
| formalParameterScope: formalParameterScope, | |
| constantContext: constantContext, | |
| internalThisVariable: null, | |
| ); | |
| BuildRedirectingFactoryMethodResult result = bodyBuilder | |
| .buildRedirectingFactoryMethod(token: token, metadata: metadata); | |
| context.performBacklog(result.annotations); | |
| _benchmarker | |
| // Coverage-ignore(suite): Not run. | |
| ?.endSubdivide(); | |
| } | |
| // Coverage-ignore(suite): Not run. | |
| Expression buildSingleExpression({ | |
| required SourceLibraryBuilder libraryBuilder, | |
| required BodyBuilderContext bodyBuilderContext, | |
| required Uri fileUri, | |
| required ExtensionScope extensionScope, | |
| required LookupScope scope, | |
| required Token token, | |
| required ExpressionCompilationData expressionCompilationData, | |
| required ExpressionEvaluationHelper expressionEvaluationHelper, | |
| required Variable? extensionThis, | |
| }) { | |
| _ResolverContext context = new _ResolverContext( | |
| typeInferenceEngine: _typeInferenceEngine, | |
| libraryBuilder: libraryBuilder, | |
| bodyBuilderContext: bodyBuilderContext, | |
| extensionScope: extensionScope, | |
| fileUri: fileUri, | |
| ); | |
| LibraryFeatures libraryFeatures = libraryBuilder.libraryFeatures; | |
| ConstantContext constantContext = bodyBuilderContext.constantContext; | |
| InternalThisVariable? internalThisVariable = bodyBuilderContext | |
| .createInternalThisVariable(); | |
| int wildcardVariableIndex = 0; | |
| InternalVariable? internalExtensionThis; | |
| FormalParameterBuilder createFormalParameterBuilder( | |
| PositionalParameter parameter, | |
| String formalName, | |
| ) { | |
| InternalPositionalParameter formal = new InternalPositionalParameter( | |
| defaultValue: null, | |
| astVariable: parameter, | |
| isImplicitlyTyped: false, | |
| fileOffset: parameter.fileOffset, | |
| ); | |
| bool isWildcard = | |
| libraryFeatures.wildcardVariables.isEnabled && formalName == '_'; | |
| int? wildcardIndex; | |
| if (isWildcard) { | |
| wildcardIndex = wildcardVariableIndex++; | |
| } | |
| if (parameter == extensionThis) { | |
| internalExtensionThis = formal; | |
| } | |
| return new FormalParameterBuilder( | |
| kind: FormalParameterKind.requiredPositional, | |
| modifiers: Modifiers.empty, | |
| type: const ImplicitTypeBuilder(), | |
| name: formalName, | |
| nameOffset: null, | |
| fileOffset: formal.fileOffset, | |
| fileUri: fileUri, | |
| hasImmediatelyDeclaredDefaultValue: false, | |
| wildcardIndex: wildcardIndex, | |
| variable: formal, | |
| ); | |
| } | |
| List<PositionalParameter> positionalParameters = | |
| expressionCompilationData.positionalParameters; | |
| List<FormalParameterBuilder>? formals = positionalParameters.length == 0 | |
| ? null | |
| : new List<FormalParameterBuilder>.generate( | |
| positionalParameters.length, | |
| (int i) { | |
| PositionalParameter parameter = positionalParameters[i]; | |
| return createFormalParameterBuilder( | |
| parameter, | |
| parameter.parameterName, | |
| ); | |
| }, | |
| growable: false, | |
| ); | |
| List<MapEntry<String, PositionalParameter>> extraParametersIfNotShadowing = | |
| expressionCompilationData.extraParametersIfNotShadowing.entries | |
| .toList(); | |
| List<FormalParameterBuilder>? extraFormalsIfNotShadowing = | |
| extraParametersIfNotShadowing.length == 0 | |
| ? null | |
| : new List<FormalParameterBuilder>.generate( | |
| extraParametersIfNotShadowing.length, | |
| (int i) { | |
| MapEntry<String, PositionalParameter> entry = | |
| extraParametersIfNotShadowing[i]; | |
| FormalParameterBuilder result = createFormalParameterBuilder( | |
| entry.value, | |
| entry.key, | |
| ); | |
| // We don't actually pass it to the body builder which would | |
| // declares the normal parameters so do it here. | |
| context.assignedVariables.declare(result.variable); | |
| // Register it in the expression evaluation helper too so it can | |
| // actually be used on otherwise failed lookups. | |
| expressionEvaluationHelper.registerAdditionalScopeLookupResult( | |
| entry.key, | |
| result, | |
| ); | |
| return result; | |
| }, | |
| 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 expressionCompilationData.typeParameters) { | |
| typeParameterBuilders ??= <NominalParameterBuilder>[]; | |
| typeParameterBuilders.add( | |
| new DillNominalParameterBuilder( | |
| typeParameter, | |
| loader: libraryBuilder.loader, | |
| ), | |
| ); | |
| } | |
| BuildSingleExpressionResult result = bodyBuilder.buildSingleExpression( | |
| token: token, | |
| extraKnownVariables: expressionCompilationData.extraKnownVariables, | |
| fileOffset: fileOffset, | |
| typeParameterBuilders: typeParameterBuilders, | |
| formals: formals, | |
| ); | |
| InternalExpression expression = result.expression; | |
| if (formals != null) { | |
| for (int i = 0; i < formals.length; i++) { | |
| InternalVariable variable = formals[i].variable; | |
| context.typeInferrer.flowAnalysis.declare( | |
| variable, | |
| new SharedTypeView(variable.type), | |
| initialized: true, | |
| ); | |
| } | |
| } | |
| if (extraFormalsIfNotShadowing != null) { | |
| for (int i = 0; i < extraFormalsIfNotShadowing.length; i++) { | |
| InternalVariable variable = extraFormalsIfNotShadowing[i].variable; | |
| context.typeInferrer.flowAnalysis.declare( | |
| variable, | |
| new SharedTypeView(variable.type), | |
| initialized: true, | |
| ); | |
| } | |
| } | |
| for (InternalVariable extraVariable | |
| in expressionCompilationData.extraKnownVariables) { | |
| context.typeInferrer.flowAnalysis.declare( | |
| extraVariable, | |
| new SharedTypeView(extraVariable.type), | |
| initialized: true, | |
| ); | |
| } | |
| InternalReturnStatement internalReturn = intern.createReturnStatement( | |
| expression: expression, | |
| isArrow: true, | |
| fileOffset: TreeNode.noOffset, | |
| ); | |
| InferredFunctionBody inferredFunctionBody = context.typeInferrer | |
| .inferFunctionBody( | |
| fileUri: fileUri, | |
| fileOffset: fileOffset, | |
| returnType: const DynamicType(), | |
| asyncModifier: AsyncModifier.implicitSync, | |
| body: internalReturn, | |
| expressionEvaluationHelper: expressionEvaluationHelper, | |
| contextAllocationStrategy: | |
| ContextAllocationStrategy.createContextAllocationStrategy( | |
| isClosureContextLoweringEnabled: | |
| libraryBuilder.loader.isClosureContextLoweringEnabled, | |
| ), | |
| constructorContext: null, | |
| thisType: | |
| extensionThis?.type ?? | |
| internalThisVariable?.type ?? | |
| bodyBuilderContext.thisType, | |
| ); | |
| ReturnStatement returnStatement = | |
| inferredFunctionBody.body as ReturnStatement; | |
| context.performBacklog(result.annotations); | |
| return returnStatement.expression!; | |
| } | |
| InternalExpression _buildConstructorInvocation({ | |
| required CompilerContext compilerContext, | |
| required ProblemReporting problemReporting, | |
| required LibraryFeatures libraryFeatures, | |
| required TypeEnvironment typeEnvironment, | |
| required Member target, | |
| required TypeArguments? typeArguments, | |
| required ActualArguments arguments, | |
| required Uri fileUri, | |
| required int fileOffset, | |
| required bool hasInferredTypeArguments, | |
| }) { | |
| ErrorText? errorText = problemReporting.checkStaticArguments( | |
| compilerContext: compilerContext, | |
| target: target, | |
| explicitTypeArguments: typeArguments, | |
| arguments: arguments, | |
| fileOffset: fileOffset, | |
| fileUri: fileUri, | |
| ); | |
| if (errorText != null) { | |
| return intern.createInvalidExpressionFromErrorText(errorText); | |
| } | |
| if (target is Constructor) { | |
| if (!target.isConst) { | |
| return intern.createInvalidExpressionFromErrorText( | |
| problemReporting.buildProblem( | |
| compilerContext: compilerContext, | |
| message: diag.nonConstConstructor, | |
| fileUri: fileUri, | |
| fileOffset: fileOffset, | |
| length: noLength, | |
| ), | |
| ); | |
| } | |
| InternalExpression node = intern.createConstructorInvocation( | |
| target: target, | |
| typeArguments: typeArguments, | |
| arguments: arguments, | |
| isConst: true, | |
| fileOffset: fileOffset, | |
| ); | |
| if (typeArguments != null) { | |
| problemReporting.checkBoundsInConstructorInvocation( | |
| libraryFeatures: libraryFeatures, | |
| constructor: target, | |
| explicitOrInferredTypeArguments: typeArguments.types, | |
| typeEnvironment: typeEnvironment, | |
| fileUri: fileUri, | |
| fileOffset: fileOffset, | |
| hasInferredTypeArguments: hasInferredTypeArguments, | |
| ); | |
| } | |
| return node; | |
| } else { | |
| // Coverage-ignore-block(suite): Not run. | |
| Procedure procedure = target as Procedure; | |
| if (!procedure.isConst) { | |
| return intern.createInvalidExpressionFromErrorText( | |
| problemReporting.buildProblem( | |
| compilerContext: compilerContext, | |
| message: diag.nonConstConstructor, | |
| fileUri: fileUri, | |
| fileOffset: fileOffset, | |
| length: noLength, | |
| ), | |
| ); | |
| } | |
| InternalExpression node = intern.createFactoryConstructorInvocation( | |
| target: target, | |
| typeArguments: typeArguments, | |
| arguments: arguments, | |
| isConst: true, | |
| fileOffset: fileOffset, | |
| ); | |
| if (typeArguments != null) { | |
| problemReporting.checkBoundsInFactoryInvocation( | |
| libraryFeatures: libraryFeatures, | |
| factory: target, | |
| explicitOrInferredTypeArguments: typeArguments.types, | |
| typeEnvironment: typeEnvironment, | |
| fileUri: fileUri, | |
| fileOffset: fileOffset, | |
| hasInferredTypeArguments: hasInferredTypeArguments, | |
| ); | |
| } | |
| return node; | |
| } | |
| } | |
| Expression _buildUnresolvedError({ | |
| required CompilerContext compilerContext, | |
| required ProblemReporting problemReporting, | |
| required String name, | |
| required Uri fileUri, | |
| required int fileOffset, | |
| }) { | |
| int length = name.length; | |
| int periodIndex = name.lastIndexOf("."); | |
| if (periodIndex != -1) { | |
| length -= periodIndex + 1; | |
| } | |
| LocatedMessage message = diag.constructorNotFound | |
| .withArguments(name: name) | |
| .withLocation(fileUri, fileOffset, length); | |
| return extern.createInvalidExpressionFromErrorText( | |
| problemReporting.buildProblem( | |
| compilerContext: compilerContext, | |
| message: message.messageObject, | |
| fileUri: fileUri, | |
| fileOffset: message.charOffset, | |
| length: message.length, | |
| errorHasBeenReported: false, | |
| ), | |
| ); | |
| } | |
| BodyBuilder _createBodyBuilder({ | |
| required _ResolverContext context, | |
| required BodyBuilderContext bodyBuilderContext, | |
| required LookupScope scope, | |
| required ConstantContext constantContext, | |
| required InternalVariable? thisVariable, | |
| required List<TypeParameter>? thisTypeParameters, | |
| required LocalScope? formalParameterScope, | |
| required InternalThisVariable? internalThisVariable, | |
| }) { | |
| _benchmarker | |
| // Coverage-ignore(suite): Not run. | |
| ?.beginSubdivide(BenchmarkSubdivides.resolver_createBodyBuilder); | |
| BodyBuilder result = _createBodyBuilderInternal( | |
| context: context, | |
| bodyBuilderContext: bodyBuilderContext, | |
| scope: scope, | |
| formalParameterScope: formalParameterScope, | |
| thisVariable: thisVariable, | |
| thisTypeParameters: thisTypeParameters, | |
| constantContext: constantContext, | |
| internalThisVariable: internalThisVariable, | |
| ); | |
| _benchmarker | |
| // Coverage-ignore(suite): Not run. | |
| ?.endSubdivide(); | |
| return result; | |
| } | |
| BodyBuilder _createBodyBuilderInternal({ | |
| required _ResolverContext context, | |
| required BodyBuilderContext bodyBuilderContext, | |
| required LookupScope scope, | |
| required LocalScope? formalParameterScope, | |
| required InternalVariable? thisVariable, | |
| required List<TypeParameter>? thisTypeParameters, | |
| required ConstantContext constantContext, | |
| required InternalThisVariable? internalThisVariable, | |
| }) { | |
| return new BodyBuilderImpl( | |
| libraryBuilder: context.libraryBuilder, | |
| context: bodyBuilderContext, | |
| enclosingScope: new EnclosingLocalScope(scope), | |
| extensionScope: context.extensionScope, | |
| formalParameterScope: formalParameterScope, | |
| hierarchy: _classHierarchy, | |
| coreTypes: _coreTypes, | |
| thisVariable: thisVariable, | |
| thisTypeParameters: thisTypeParameters, | |
| uri: context.fileUri, | |
| assignedVariables: context.assignedVariables, | |
| typeEnvironment: context.typeEnvironment, | |
| constantContext: constantContext, | |
| internalThisVariable: internalThisVariable, | |
| ); | |
| } | |
| _SuperParameterArguments? _createSuperParameterArguments({ | |
| required AssignedVariablesImpl assignedVariables, | |
| required List<FormalParameterBuilder>? formals, | |
| }) { | |
| if (formals == null) { | |
| return null; | |
| } | |
| List<Argument>? superParametersAsArguments; | |
| int positionalCount = 0; | |
| int? firstPositionalOffset; | |
| for (int i = 0; i < formals.length; i++) { | |
| FormalParameterBuilder formal = formals[i]; | |
| if (formal.isSuperInitializingFormal) { | |
| if (formal.isNamed) { | |
| (superParametersAsArguments ??= []).add( | |
| new SuperNamedArgument( | |
| intern.createNamedExpression( | |
| formal.name, | |
| _createVariableGet( | |
| assignedVariables: assignedVariables, | |
| variable: formal.variable, | |
| fileOffset: formal.fileOffset, | |
| ), | |
| fileOffset: formal.fileOffset, | |
| ), | |
| ), | |
| ); | |
| } else { | |
| positionalCount++; | |
| firstPositionalOffset ??= formal.fileOffset; | |
| (superParametersAsArguments ??= []).add( | |
| new SuperPositionalArgument( | |
| _createVariableGet( | |
| assignedVariables: assignedVariables, | |
| variable: formal.variable, | |
| fileOffset: formal.fileOffset, | |
| ), | |
| ), | |
| ); | |
| } | |
| } | |
| } | |
| if (superParametersAsArguments == null) { | |
| return null; | |
| } | |
| return new _SuperParameterArguments( | |
| superParametersAsArguments, | |
| positionalCount: positionalCount, | |
| firstPositionalOffset: firstPositionalOffset ?? -1, | |
| ); | |
| } | |
| /// Helper method to create a [VariableGet] of the [variable] using | |
| /// [fileOffset] as the file offset. | |
| InternalExpression _createVariableGet({ | |
| required AssignedVariablesImpl assignedVariables, | |
| required InternalVariable variable, | |
| required int fileOffset, | |
| }) { | |
| if (variable is! InternalLocalFunctionVariable && !variable.isWildcard) { | |
| assignedVariables.read(variable); | |
| } | |
| return intern.createVariableGet(variable, fileOffset: fileOffset); | |
| } | |
| void _declareFormals({ | |
| required TypeInferrer typeInferrer, | |
| required BodyBuilderContext bodyBuilderContext, | |
| required InternalVariable? thisVariable, | |
| required List<FormalParameterBuilder>? formals, | |
| }) { | |
| if (thisVariable != null && bodyBuilderContext.isConstructor) { | |
| // `thisVariable` usually appears in `_context.formals`, but for a | |
| // constructor, it doesn't. So declare it separately. | |
| typeInferrer.flowAnalysis.declare( | |
| thisVariable, | |
| new SharedTypeView(thisVariable.type), | |
| initialized: true, | |
| ); | |
| } | |
| if (formals != null) { | |
| for (int i = 0; i < formals.length; i++) { | |
| FormalParameterBuilder parameter = formals[i]; | |
| InternalVariable variable = parameter.variable; | |
| // TODO(62401): Remove the cast when the flow analysis uses | |
| // [InternalExpressionVariable]s. | |
| typeInferrer.flowAnalysis.declare( | |
| variable, | |
| new SharedTypeView(variable.type), | |
| initialized: true, | |
| ); | |
| } | |
| } | |
| } | |
| void _finishConstructor({ | |
| required _ResolverContext context, | |
| required CompilerContext compilerContext, | |
| required ProblemReporting problemReporting, | |
| required SourceLibraryBuilder libraryBuilder, | |
| required LibraryFeatures libraryFeatures, | |
| required BodyBuilderContext bodyBuilderContext, | |
| required AsyncModifier asyncModifier, | |
| required InternalStatement? body, | |
| required _SuperParameterArguments? superParameterArguments, | |
| required Uri fileUri, | |
| required ConstantContext constantContext, | |
| required List<InternalInitializer> initializers, | |
| required bool forPrimaryConstructor, | |
| required bool isImplementation, | |
| required List<InternalVariable> parameters, | |
| required InternalThisVariable? internalThisVariable, | |
| required ContextAllocationStrategy contextAllocationStrategy, | |
| }) { | |
| _InitializerBuilder initializerBuilder = new _InitializerBuilder( | |
| compilerContext: compilerContext, | |
| problemReporting: problemReporting, | |
| bodyBuilderContext: bodyBuilderContext, | |
| typeInferrer: context.typeInferrer, | |
| coreTypes: _coreTypes, | |
| fileUri: fileUri, | |
| forImplementation: isImplementation, | |
| ); | |
| initializerBuilder.processInitializers( | |
| libraryBuilder: libraryBuilder, | |
| libraryFeatures: libraryFeatures, | |
| superParameterArguments: superParameterArguments, | |
| initializers: initializers, | |
| asyncModifier: asyncModifier, | |
| forPrimaryConstructor: forPrimaryConstructor, | |
| parameters: parameters, | |
| internalThisVariable: internalThisVariable, | |
| contextAllocationStrategy: contextAllocationStrategy, | |
| isConstructorWithoutBody: body == null, | |
| ); | |
| if (body == null && !bodyBuilderContext.isExternalConstructor) { | |
| /// >If a generative constructor c is not a redirecting constructor | |
| /// >and no body is provided, then c implicitly has an empty body {}. | |
| /// We use an empty statement instead. | |
| // TODO(cstefantsova): Verify that the scope object shouldn't be passed | |
| // along with the thisVariable in the ScopeProviderInfo object in the | |
| // call below. | |
| ScopeProviderInfo? scopeProviderInfo; | |
| if (internalThisVariable != null) { | |
| scopeProviderInfo = new ScopeProviderInfo( | |
| kind: ScopeProviderInfoKind.FunctionNodeWithThis, | |
| )..thisVariable = internalThisVariable.astVariable; | |
| } | |
| bodyBuilderContext.registerNoBodyConstructor( | |
| scopeProviderInfo: scopeProviderInfo, | |
| ); | |
| } else if (body != null && | |
| bodyBuilderContext.isMixinClass && | |
| !bodyBuilderContext.isFactory) { | |
| // Report an error if a mixin class has a non-factory constructor with a | |
| // body. | |
| problemReporting.buildProblem( | |
| compilerContext: compilerContext, | |
| message: diag.illegalMixinDueToConstructors.withArguments( | |
| className: bodyBuilderContext.className, | |
| ), | |
| fileUri: fileUri, | |
| // It is allowed to have a primary constructor without a body, so | |
| // for primary constructors we report the error on the body and not | |
| // the name of the constructor. | |
| fileOffset: forPrimaryConstructor | |
| ? body.fileOffset | |
| : bodyBuilderContext.memberNameOffset, | |
| length: noLength, | |
| ); | |
| } | |
| } | |
| void _finishFunction({ | |
| required _ResolverContext context, | |
| required CompilerContext compilerContext, | |
| required ProblemReporting problemReporting, | |
| required SourceLibraryBuilder libraryBuilder, | |
| required LibraryFeatures libraryFeatures, | |
| required AsyncModifier asyncModifier, | |
| required InternalStatement? body, | |
| required Uri fileUri, | |
| required BodyBuilderContext bodyBuilderContext, | |
| required InternalVariable? thisVariable, | |
| required List<InternalInitializer> initializers, | |
| required ConstantContext constantContext, | |
| required InternalThisVariable? internalThisVariable, | |
| required bool forPrimaryConstructor, | |
| required bool isImplementation, | |
| }) { | |
| AssignedVariablesImpl assignedVariables = context.assignedVariables; | |
| // Create variable get expressions for super parameters before finishing | |
| // the analysis of the assigned variables. Creating the expressions later | |
| // that point results in a flow analysis error. | |
| _SuperParameterArguments? superParameterArguments = | |
| _createSuperParameterArguments( | |
| assignedVariables: assignedVariables, | |
| formals: bodyBuilderContext.formals, | |
| ); | |
| assignedVariables.finish(); | |
| _declareFormals( | |
| typeInferrer: context.typeInferrer, | |
| bodyBuilderContext: bodyBuilderContext, | |
| thisVariable: thisVariable, | |
| formals: bodyBuilderContext.formals, | |
| ); | |
| late List<InternalFunctionParameter>? parameters = [ | |
| for (FormalParameterBuilder formal in bodyBuilderContext.formals ?? []) | |
| formal.variable, | |
| ]; | |
| ScopeProviderInfo? scopeProviderInfo; | |
| ContextAllocationStrategy contextAllocationStrategy = | |
| ContextAllocationStrategy.createContextAllocationStrategy( | |
| isClosureContextLoweringEnabled: | |
| libraryBuilder.loader.isClosureContextLoweringEnabled, | |
| ); | |
| if (libraryBuilder.loader.isClosureContextLoweringEnabled) { | |
| scopeProviderInfo = contextAllocationStrategy | |
| .beginClosureContextAllocation( | |
| [ | |
| for (InternalFunctionParameter parameter in parameters) | |
| new VariableWithCaptureKind( | |
| parameter.functionParameter, | |
| context.typeInferrer.captureKindForVariable(parameter), | |
| ), | |
| ], | |
| thisVariable: internalThisVariable == null | |
| ? null | |
| : new VariableWithCaptureKind( | |
| internalThisVariable.astVariable, | |
| context.typeInferrer.captureKindForVariable( | |
| internalThisVariable, | |
| ), | |
| ), | |
| ); | |
| } | |
| if (bodyBuilderContext.isConstructor) { | |
| _finishConstructor( | |
| context: context, | |
| compilerContext: compilerContext, | |
| problemReporting: problemReporting, | |
| libraryBuilder: libraryBuilder, | |
| libraryFeatures: libraryFeatures, | |
| bodyBuilderContext: bodyBuilderContext, | |
| asyncModifier: asyncModifier, | |
| body: body, | |
| superParameterArguments: superParameterArguments, | |
| fileUri: fileUri, | |
| constantContext: constantContext, | |
| initializers: initializers, | |
| forPrimaryConstructor: forPrimaryConstructor, | |
| isImplementation: isImplementation, | |
| parameters: parameters, | |
| internalThisVariable: internalThisVariable, | |
| contextAllocationStrategy: contextAllocationStrategy, | |
| ); | |
| } | |
| DartType returnType = bodyBuilderContext.returnTypeContext; | |
| if (bodyBuilderContext.returnTypeBuilder is! OmittedTypeBuilder) { | |
| problemReporting.checkAsyncReturnType( | |
| libraryBuilder: libraryBuilder, | |
| typeEnvironment: context.typeInferrer.typeSchemaEnvironment, | |
| asyncModifier: asyncModifier, | |
| returnType: returnType, | |
| returnTypeBuilder: bodyBuilderContext.returnTypeBuilder, | |
| fileUri: fileUri, | |
| ); | |
| } | |
| InferredFunctionBody? inferredFunctionBody; | |
| Statement? inferredBody; | |
| if (body != null) { | |
| inferredFunctionBody = context.typeInferrer.inferFunctionBody( | |
| fileUri: fileUri, | |
| fileOffset: bodyBuilderContext.memberNameOffset, | |
| returnType: returnType, | |
| asyncModifier: asyncModifier, | |
| body: body, | |
| contextAllocationStrategy: contextAllocationStrategy, | |
| constructorContext: bodyBuilderContext.constructorContext, | |
| thisType: | |
| thisVariable?.type ?? | |
| internalThisVariable?.type ?? | |
| bodyBuilderContext.thisType, | |
| ); | |
| inferredBody = inferredFunctionBody.body; | |
| } else { | |
| // Normalize abstract members markers to sync. | |
| asyncModifier = AsyncModifier.implicitSync; | |
| } | |
| // No-such-method forwarders get their bodies injected during outline | |
| // building, so we should skip them here. | |
| bool isNoSuchMethodForwarder = bodyBuilderContext.isNoSuchMethodForwarder; | |
| if (inferredBody != null) { | |
| if (bodyBuilderContext.isExternalFunction || isNoSuchMethodForwarder) { | |
| inferredBody = new Block(<Statement>[ | |
| new ExpressionStatement( | |
| extern.createInvalidExpressionFromErrorText( | |
| problemReporting.buildProblem( | |
| compilerContext: compilerContext, | |
| message: diag.externalMethodWithBody, | |
| fileUri: fileUri, | |
| fileOffset: inferredBody.fileOffset, | |
| length: noLength, | |
| ), | |
| ), | |
| )..fileOffset = inferredBody.fileOffset, | |
| inferredBody, | |
| ])..fileOffset = inferredBody.fileOffset; | |
| } | |
| } | |
| DartType? emittedValueType = inferredFunctionBody?.emittedValueType; | |
| assert( | |
| !(asyncModifier.kind == AsyncMarker.Sync && emittedValueType != null), | |
| "Unexpected emitted value type for sync function.", | |
| ); | |
| assert( | |
| !(asyncModifier.kind != AsyncMarker.Sync && emittedValueType == null), | |
| "Missing emitted value type for non-sync function.", | |
| ); | |
| if (scopeProviderInfo != null) { | |
| contextAllocationStrategy.endClosureContextAllocation(scopeProviderInfo); | |
| } | |
| bodyBuilderContext.registerFunctionBody( | |
| body: inferredBody, | |
| scopeProviderInfo: scopeProviderInfo, | |
| asyncModifier: asyncModifier, | |
| emittedValueType: emittedValueType, | |
| ); | |
| } | |
| } |