blob: 466d4abed09ed9f95141b7cf4327847e03d6b19c [file] [log] [blame] [edit]
// 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/type_inference/assigned_variables.dart';
import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
import 'package:front_end/src/codes/diagnostic.dart' as diag;
import 'package:kernel/ast.dart';
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 '../api_prototype/lowering_predicates.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 '../type_inference/external_ast_helper.dart';
import '../type_inference/inference_results.dart';
import '../type_inference/inference_visitor.dart'
show ExpressionEvaluationHelper;
import '../type_inference/type_inference_engine.dart';
import '../type_inference/type_inferrer.dart'
show TypeInferrer, InferredFunctionBody;
import '../type_inference/type_schema.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 'forest.dart';
import 'internal_ast.dart';
part 'resolver_helpers.dart';
class Resolver {
final ClassHierarchy _classHierarchy;
final CoreTypes _coreTypes;
final TypeInferenceEngineImpl _typeInferenceEngine;
final Benchmarker? _benchmarker;
late CloneVisitorNotMembers _simpleCloner = new CloneVisitorNotMembers();
Resolver({
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<int> indicesOfAnnotationsToBeInferred = [];
for (Annotation annotation in annotations) {
Expression expression = bodyBuilder.buildAnnotation(
atToken: annotation.atToken,
);
if (annotation.createFileUriExpression) {
expression = new FileUriExpression(
expression,
annotation.metadataBuilder.fileUri,
)..fileOffset = annotation.metadataBuilder.atOffset;
}
// Record the index of [annotation] in `annotatable.annotations` in order
// to perform inference only on the new annotations, and to be able to
// store inferred [Expression] to the corresponding [MetadataBuilder]
// after inference.
int annotationIndex = annotation.annotationIndex =
annotatable.annotations.length;
indicesOfAnnotationsToBeInferred.add(annotationIndex);
// 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?
annotatable.addAnnotation(expression);
}
context.inferSingleTargetAnnotation(
singleTarget: new SingleTargetAnnotations(
annotatable,
indicesOfAnnotationsToBeInferred,
),
);
// TODO(johnniwinther): We need to process annotations within annotations.
context.performBacklog(null);
for (Annotation annotation in annotations) {
annotation.expression =
annotatable.annotations[annotation.annotationIndex];
}
}
(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,
);
}
Expression initializer;
DartType? fieldType;
if (constructorBuilder == null ||
constructorBuilder is! SourceConstructorBuilder) {
initializer = _buildUnresolvedError(
compilerContext: compilerContext,
problemReporting: problemReporting,
name: fullConstructorNameForErrors,
fileUri: fileUri,
fileOffset: fileOffset,
);
} else {
initializer = _buildConstructorInvocation(
compilerContext: compilerContext,
problemReporting: problemReporting,
libraryFeatures: libraryFeatures,
typeEnvironment: context.typeEnvironment,
target: constructorBuilder.invokeTarget,
typeArguments: typeArguments,
arguments: arguments,
fileUri: fileUri,
fileOffset: fileOffset,
hasInferredTypeArguments: false,
);
ExpressionInferenceResult inferenceResult = context.typeInferrer
.inferFieldInitializer(
fileUri: fileUri,
declaredType: const UnknownType(),
initializer: initializer,
inferenceDefaultType: InferenceDefaultType.Dynamic,
);
initializer = inferenceResult.expression;
fieldType = inferenceResult.inferredType;
}
context.performBacklog(result?.annotations);
return (initializer, fieldType);
}
ExpressionInferenceResult buildFieldInitializer({
required SourceLibraryBuilder libraryBuilder,
required BodyBuilderContext bodyBuilderContext,
required Uri fileUri,
required ExtensionScope extensionScope,
required LookupScope scope,
required bool isLate,
DartType? declaredFieldType,
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;
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,
);
BuildFieldInitializerResult result = bodyBuilder.buildFieldInitializer(
startToken: startToken,
isLate: isLate,
);
ExpressionInferenceResult expressionInferenceResult = context.typeInferrer
.inferFieldInitializer(
fileUri: fileUri,
declaredType: declaredFieldType,
initializer: result.initializer,
inferenceDefaultType: inferenceDefaultType,
);
context.performBacklog(result.annotations);
return expressionInferenceResult;
}
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, Expression?> entry
in result.fieldInitializers.entries) {
Identifier identifier = entry.key;
Expression? initializer = entry.value;
FieldFragment fieldFragment = offsetMap.lookupField(identifier);
fieldFragment.declaration.buildFieldInitializer(
typeInferrer: context.typeInferrer,
coreTypes: _coreTypes,
fileUri: fileUri,
initializer: initializer,
);
}
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;
ThisVariable? 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,
asyncMarker: result.asyncMarker,
body: result.body,
fileUri: fileUri,
bodyBuilderContext: bodyBuilderContext,
thisVariable: functionBodyBuildingContext.thisVariable,
initializers: result.initializers,
constantContext: constantContext,
internalThisVariable: internalThisVariable,
);
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,
}) {
_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;
BodyBuilder bodyBuilder = _createBodyBuilder(
context: context,
bodyBuilderContext: bodyBuilderContext,
scope: typeParameterScope,
constantContext: constantContext,
formalParameterScope: formalParameterScope,
thisVariable: null,
thisTypeParameters: null,
// TODO(cstefantsova): Should [ThisVariable] be created here?
internalThisVariable: null,
);
constructorBuilder.inferFormalTypes(_classHierarchy);
BuildInitializersResult result = bodyBuilder.buildInitializers(
beginInitializers: beginInitializers,
);
List<Initializer> 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: AsyncMarker.Sync,
body: null,
superParameterArguments: superParameterArguments,
fileUri: fileUri,
constantContext: constantContext,
initializers: initializers,
);
}
context.performBacklog(result.annotations);
}
List<Initializer> 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.
for (Expression expression in result.expressions) {
annotatable.addAnnotation(expression);
}
context.inferSingleTargetAnnotation(
singleTarget: new SingleTargetAnnotations(annotatable),
);
List<Expression> expressions = annotatable.annotations;
context.performBacklog(result.annotations);
return expressions;
}
Expression buildParameterInitializer({
required SourceLibraryBuilder libraryBuilder,
required BodyBuilderContext bodyBuilderContext,
required ExtensionScope extensionScope,
required LookupScope scope,
required Uri fileUri,
required Token initializerToken,
required DartType declaredType,
required bool hasDeclaredInitializer,
}) {
_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,
);
BuildParameterInitializerResult result = bodyBuilder
.buildParameterInitializer(initializerToken: initializerToken);
Expression initializer = context.typeInferrer.inferParameterInitializer(
fileUri: fileUri,
initializer: result.initializer,
declaredType: declaredType,
hasDeclaredInitializer: hasDeclaredInitializer,
);
context.performBacklog(result.annotations);
return initializer;
}
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;
ThisVariable? 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,
asyncMarker: AsyncMarker.Sync,
body: null,
fileUri: fileUri,
bodyBuilderContext: bodyBuilderContext,
thisVariable: functionBodyBuildingContext.thisVariable,
initializers: result.initializers,
constantContext: constantContext,
internalThisVariable: internalThisVariable,
);
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 startToken,
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;
ThisVariable? 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(
startToken: startToken,
metadata: metadata,
);
_finishFunction(
context: context,
compilerContext: compilerContext,
problemReporting: problemReporting,
libraryBuilder: libraryBuilder,
libraryFeatures: libraryFeatures,
bodyBuilderContext: bodyBuilderContext,
asyncMarker: result.asyncMarker,
body: result.body,
fileUri: fileUri,
constantContext: constantContext,
initializers: result.initializers,
thisVariable: functionBodyBuildingContext.thisVariable,
internalThisVariable: internalThisVariable,
);
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 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 Procedure procedure,
required List<ExpressionVariable> extraKnownVariables,
required ExpressionEvaluationHelper expressionEvaluationHelper,
required VariableDeclaration? extensionThis,
}) {
_ResolverContext context = new _ResolverContext(
typeInferenceEngine: _typeInferenceEngine,
libraryBuilder: libraryBuilder,
bodyBuilderContext: bodyBuilderContext,
extensionScope: extensionScope,
fileUri: fileUri,
);
LibraryFeatures libraryFeatures = libraryBuilder.libraryFeatures;
ConstantContext constantContext = bodyBuilderContext.constantContext;
ThisVariable? internalThisVariable = bodyBuilderContext
.createInternalThisVariable();
BodyBuilder bodyBuilder = _createBodyBuilder(
context: context,
bodyBuilderContext: bodyBuilderContext,
scope: scope,
thisVariable: extensionThis,
constantContext: constantContext,
// TODO(johnniwinther): Should we provide these?
thisTypeParameters: null,
formalParameterScope: null,
internalThisVariable: internalThisVariable,
);
int fileOffset = token.charOffset;
FunctionNode parameters = procedure.function;
List<NominalParameterBuilder>? typeParameterBuilders;
for (TypeParameter typeParameter in parameters.typeParameters) {
typeParameterBuilders ??= <NominalParameterBuilder>[];
typeParameterBuilders.add(
new DillNominalParameterBuilder(
typeParameter,
loader: libraryBuilder.loader,
),
);
}
int wildcardVariableIndex = 0;
List<FormalParameterBuilder>? formals =
parameters.positionalParameters.length == 0
? null
: new List<FormalParameterBuilder>.generate(
parameters.positionalParameters.length,
(int i) {
VariableDeclaration formal = parameters.positionalParameters[i];
String formalName = formal.name!;
bool isWildcard =
libraryFeatures.wildcardVariables.isEnabled &&
formalName == '_';
if (isWildcard) {
formalName = createWildcardFormalParameterName(
wildcardVariableIndex,
);
wildcardVariableIndex++;
}
return new FormalParameterBuilder(
kind: FormalParameterKind.requiredPositional,
modifiers: Modifiers.empty,
type: const ImplicitTypeBuilder(),
name: formalName,
nameOffset: null,
fileOffset: formal.fileOffset,
fileUri: fileUri,
hasImmediatelyDeclaredInitializer: false,
isWildcard: isWildcard,
isClosureContextLoweringEnabled: libraryBuilder
.loader
.target
.backendTarget
.flags
.isClosureContextLoweringEnabled,
)..variable = formal;
},
growable: false,
);
BuildSingleExpressionResult result = bodyBuilder.buildSingleExpression(
token: token,
extraKnownVariables: extraKnownVariables,
fileOffset: fileOffset,
typeParameterBuilders: typeParameterBuilders,
formals: formals,
);
Expression expression = result.expression;
if (formals != null) {
for (int i = 0; i < formals.length; i++) {
VariableDeclaration variable = formals[i].variable!;
context.typeInferrer.flowAnalysis.declare(
variable,
new SharedTypeView(variable.type),
initialized: true,
);
}
}
for (ExpressionVariable extraVariable in extraKnownVariables) {
context.typeInferrer.flowAnalysis.declare(
extraVariable,
new SharedTypeView(extraVariable.type),
initialized: true,
);
}
ReturnStatementImpl fakeReturn = new ReturnStatementImpl(true, expression);
// TODO(cstefantsova): Remove special-casing over
// ExpressionCompilerProcedureBodyBuildContext below by computing formals in
// it.
List<VariableDeclaration> formalParameters =
bodyBuilderContext is ExpressionCompilerProcedureBodyBuildContext
? []
: <VariableDeclaration>[
for (FormalParameterBuilder formal
in bodyBuilderContext.formals ?? [])
formal.variable!,
];
InferredFunctionBody inferredFunctionBody = context.typeInferrer
.inferFunctionBody(
fileUri: fileUri,
fileOffset: fileOffset,
returnType: const DynamicType(),
asyncMarker: AsyncMarker.Sync,
body: fakeReturn,
expressionEvaluationHelper: expressionEvaluationHelper,
parameters: formalParameters,
internalThisVariable: internalThisVariable,
);
assert(
fakeReturn == inferredFunctionBody.body,
"Previously implicit assumption about inferFunctionBody "
"not returning anything different.",
);
context.performBacklog(result.annotations);
return fakeReturn.expression!;
}
Expression _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,
}) {
Expression? result = problemReporting.checkStaticArguments(
compilerContext: compilerContext,
target: target,
explicitTypeArguments: typeArguments,
arguments: arguments,
fileOffset: fileOffset,
fileUri: fileUri,
);
if (result != null) {
return result;
}
if (target is Constructor) {
if (!target.isConst) {
return problemReporting.buildProblem(
compilerContext: compilerContext,
message: diag.nonConstConstructor,
fileUri: fileUri,
fileOffset: fileOffset,
length: noLength,
);
}
Expression node = new InternalConstructorInvocation(
target,
typeArguments,
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 problemReporting.buildProblem(
compilerContext: compilerContext,
message: diag.nonConstConstructor,
fileUri: fileUri,
fileOffset: fileOffset,
length: noLength,
);
}
FactoryConstructorInvocation node = new FactoryConstructorInvocation(
target,
typeArguments,
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 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 VariableDeclaration? thisVariable,
required List<TypeParameter>? thisTypeParameters,
required LocalScope? formalParameterScope,
required ThisVariable? 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 VariableDeclaration? thisVariable,
required List<TypeParameter>? thisTypeParameters,
required ConstantContext constantContext,
required ThisVariable? 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 AssignedVariables 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(
new NamedExpression(
formal.name,
_createVariableGet(
assignedVariables: assignedVariables,
variable: formal.variable as VariableDeclarationImpl,
fileOffset: formal.fileOffset,
),
)..fileOffset = formal.fileOffset,
),
);
} else {
positionalCount++;
firstPositionalOffset ??= formal.fileOffset;
(superParametersAsArguments ??= []).add(
new SuperPositionalArgument(
_createVariableGet(
assignedVariables: assignedVariables,
variable: formal.variable as VariableDeclarationImpl,
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.
VariableGet _createVariableGet({
required AssignedVariables assignedVariables,
required InternalExpressionVariable variable,
required int fileOffset,
}) {
if (!variable.isLocalFunction && !variable.isWildcard) {
assignedVariables.read(variable);
}
return new VariableGet(variable.astVariable)..fileOffset = fileOffset;
}
void _declareFormals({
required TypeInferrer typeInferrer,
required BodyBuilderContext bodyBuilderContext,
required VariableDeclaration? 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];
VariableDeclaration variable = parameter.variable!;
// TODO(62401): Ensure `variable` is an InternalExpressionVariable.
if (variable
case InternalExpressionVariable(
astVariable: ExpressionVariable variable,
) ||
// Coverage-ignore(suite): Not run.
ExpressionVariable variable) {
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 AsyncMarker asyncModifier,
required Statement? body,
required _SuperParameterArguments? superParameterArguments,
required Uri fileUri,
required ConstantContext constantContext,
required List<Initializer> initializers,
}) {
_InitializerBuilder initializerBuilder = new _InitializerBuilder(
compilerContext: compilerContext,
problemReporting: problemReporting,
bodyBuilderContext: bodyBuilderContext,
typeInferrer: context.typeInferrer,
coreTypes: _coreTypes,
fileUri: fileUri,
);
initializerBuilder.processInitializers(
libraryBuilder: libraryBuilder,
libraryFeatures: libraryFeatures,
superParameterArguments: superParameterArguments,
initializers: initializers,
asyncMarker: asyncModifier,
asyncModifierFileOffset: body?.fileOffset,
);
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.
bodyBuilderContext.registerNoBodyConstructor();
} 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,
fileOffset: bodyBuilderContext.memberNameOffset,
length: noLength,
);
}
}
void _finishFunction({
required _ResolverContext context,
required CompilerContext compilerContext,
required ProblemReporting problemReporting,
required SourceLibraryBuilder libraryBuilder,
required LibraryFeatures libraryFeatures,
required AsyncMarker asyncMarker,
required Statement? body,
required Uri fileUri,
required BodyBuilderContext bodyBuilderContext,
required VariableDeclaration? thisVariable,
required List<Initializer> initializers,
required ConstantContext constantContext,
required ThisVariable? internalThisVariable,
}) {
const Forest forest = const Forest();
AssignedVariables 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,
);
if (bodyBuilderContext.formals != null) {
// TODO(johnniwinther): Avoid the need for this.
int declaredParameterIndex = 0;
for (FormalParameterBuilder parameter in bodyBuilderContext.formals!) {
if (parameter.isExtensionThis) continue;
Expression? initializer = parameter.variable!.initializer;
bool inferInitializer;
if (parameter.isSuperInitializingFormal) {
// Super-parameters can inherit the default value from the super
// constructor so we only handle explicit default values here.
inferInitializer = parameter.hasImmediatelyDeclaredInitializer;
} else if (initializer != null) {
inferInitializer = true;
} else {
inferInitializer = parameter.isOptional;
}
if (inferInitializer) {
if (!parameter.initializerWasInferred) {
// Coverage-ignore(suite): Not run.
initializer ??= forest.createNullLiteral(
// TODO(ahe): Should store: originParameter.fileOffset
// https://github.com/dart-lang/sdk/issues/32289
noLocation,
);
VariableDeclaration originParameter = parameter.variable!;
initializer = context.typeInferrer.inferParameterInitializer(
fileUri: fileUri,
initializer: initializer,
declaredType: originParameter.type,
hasDeclaredInitializer: parameter.hasDeclaredInitializer,
);
originParameter.initializer = initializer..parent = originParameter;
if (initializer is InvalidExpression) {
originParameter.isErroneouslyInitialized = true;
}
parameter.initializerWasInferred = true;
}
VariableDeclaration? tearOffParameter = bodyBuilderContext
.getTearOffParameter(declaredParameterIndex);
if (tearOffParameter != null) {
Expression tearOffInitializer = _simpleCloner.cloneInContext(
initializer!,
);
tearOffParameter.initializer = tearOffInitializer
..parent = tearOffParameter;
tearOffParameter.isErroneouslyInitialized =
parameter.variable!.isErroneouslyInitialized;
}
}
declaredParameterIndex++;
}
}
if (bodyBuilderContext.isConstructor) {
_finishConstructor(
context: context,
compilerContext: compilerContext,
problemReporting: problemReporting,
libraryBuilder: libraryBuilder,
libraryFeatures: libraryFeatures,
bodyBuilderContext: bodyBuilderContext,
asyncModifier: asyncMarker,
body: body,
superParameterArguments: superParameterArguments,
fileUri: fileUri,
constantContext: constantContext,
initializers: initializers,
);
}
DartType returnType = bodyBuilderContext.returnTypeContext;
if (bodyBuilderContext.returnTypeBuilder is! OmittedTypeBuilder) {
problemReporting.checkAsyncReturnType(
libraryBuilder: libraryBuilder,
typeEnvironment: context.typeInferrer.typeSchemaEnvironment,
asyncMarker: asyncMarker,
returnType: returnType,
returnTypeBuilder: bodyBuilderContext.returnTypeBuilder,
fileUri: fileUri,
);
}
InferredFunctionBody? inferredFunctionBody;
if (body != null) {
inferredFunctionBody = context.typeInferrer.inferFunctionBody(
fileUri: fileUri,
fileOffset: bodyBuilderContext.memberNameOffset,
returnType: returnType,
asyncMarker: asyncMarker,
body: body,
parameters: <VariableDeclaration>[
for (FormalParameterBuilder formal
in bodyBuilderContext.formals ?? [])
formal.variable!,
],
internalThisVariable: internalThisVariable,
);
body = inferredFunctionBody.body;
} else {
// Normalize abstract members markers to sync.
asyncMarker = AsyncMarker.Sync;
}
// No-such-method forwarders get their bodies injected during outline
// building, so we should skip them here.
bool isNoSuchMethodForwarder = bodyBuilderContext.isNoSuchMethodForwarder;
if (body != null) {
if (bodyBuilderContext.isExternalFunction || isNoSuchMethodForwarder) {
body = new Block(<Statement>[
new ExpressionStatement(
problemReporting.buildProblem(
compilerContext: compilerContext,
message: diag.externalMethodWithBody,
fileUri: fileUri,
fileOffset: body.fileOffset,
length: noLength,
),
)..fileOffset = body.fileOffset,
body,
])..fileOffset = body.fileOffset;
}
}
DartType? emittedValueType = inferredFunctionBody?.emittedValueType;
assert(
!(asyncMarker == AsyncMarker.Sync && emittedValueType != null),
"Unexpected emitted value type for sync function.",
);
assert(
!(asyncMarker != AsyncMarker.Sync && emittedValueType == null),
"Missing emitted value type for non-sync function.",
);
bodyBuilderContext.registerFunctionBody(
body: body,
scopeProviderInfo: inferredFunctionBody?.scopeProviderInfo,
asyncMarker: asyncMarker,
emittedValueType: emittedValueType,
);
}
}