Skip to content

Commit

Permalink
[cfe] Add _ImplicitType to handle field and enum element inference
Browse files Browse the repository at this point in the history
Change-Id: I00bb0817c6504de0f970d58abfaac294c16209e9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/405003
Reviewed-by: Chloe Stefantsova <[email protected]>
Commit-Queue: Johnni Winther <[email protected]>
  • Loading branch information
johnniwinther authored and Commit Queue committed Jan 17, 2025
1 parent 39d2653 commit 3f90ef6
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 164 deletions.
49 changes: 41 additions & 8 deletions pkg/front_end/lib/src/fragment/enum_element.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,22 @@ class EnumElementFragment
final Uri fileUri;

final ConstructorReferenceBuilder? constructorReferenceBuilder;
Token? argumentsBeginToken;
Token? _argumentsBeginToken;

SourcePropertyBuilder? _builder;

Field? _field;
late DartType _type = new InferredType.fromEnumElementInitializer(this);

late DartType _type = new InferredType(
libraryBuilder: builder.libraryBuilder,
typeBuilder: type,
inferType: inferType,
computeType: _computeType,
fileUri: fileUri,
name: name,
nameOffset: nameOffset,
nameLength: name.length,
token: argumentsBeginToken);

late final int elementIndex;

Expand All @@ -38,7 +48,8 @@ class EnumElementFragment
required this.nameOffset,
required this.fileUri,
required this.constructorReferenceBuilder,
required this.argumentsBeginToken});
required Token? argumentsBeginToken})
: _argumentsBeginToken = argumentsBeginToken;

@override
SourcePropertyBuilder get builder {
Expand All @@ -53,6 +64,29 @@ class EnumElementFragment
type.registerInferredTypeListener(this);
}

/// Returns the token for begin of the constructor arguments of this enum
/// element, if any.
///
/// This can only be called once and will hand over the responsibility of
/// the token to the caller.
Token? get argumentsBeginToken {
Token? token = _argumentsBeginToken;
_argumentsBeginToken = null;
return token;
}

DartType _computeType(ClassHierarchyBase hierarchy, Token? token) {
SourceLibraryBuilder libraryBuilder = builder.libraryBuilder;
SourceEnumBuilder sourceEnumBuilder =
builder.declarationBuilder as SourceEnumBuilder;
_buildElement(
sourceEnumBuilder,
sourceEnumBuilder.selfType.build(libraryBuilder, TypeUse.enumSelfType),
libraryBuilder.loader.coreTypes,
token);
return fieldType;
}

@override
bool get isEnumElement => true;

Expand Down Expand Up @@ -125,8 +159,8 @@ class EnumElementFragment
f(member: _field!, kind: BuiltMemberKind.Field);
}

void buildElement(SourceEnumBuilder sourceEnumBuilder, DartType selfType,
CoreTypes coreTypes) {
void _buildElement(SourceEnumBuilder sourceEnumBuilder, DartType selfType,
CoreTypes coreTypes, Token? token) {
SourceLibraryBuilder libraryBuilder = sourceEnumBuilder.libraryBuilder;
DartType inferredFieldType = selfType;

Expand Down Expand Up @@ -174,8 +208,8 @@ class EnumElementFragment
fileUri);
bodyBuilder.constantContext = ConstantContext.inferred;

if (argumentsBeginToken != null) {
arguments = bodyBuilder.parseArguments(argumentsBeginToken!);
if (token != null) {
arguments = bodyBuilder.parseArguments(token);
// We pass `true` for [allowFurtherDelays] here because the members of
// the enums are built before the inference, and the resolution of the
// redirecting factories can't be completed at this moment and
Expand All @@ -185,7 +219,6 @@ class EnumElementFragment

arguments.positional.insertAll(0, enumSyntheticArguments);
arguments.argumentsOriginalOrder?.insertAll(0, enumSyntheticArguments);
argumentsBeginToken = null;
} else {
arguments = new ArgumentsImpl(enumSyntheticArguments);
}
Expand Down
76 changes: 67 additions & 9 deletions pkg/front_end/lib/src/fragment/field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,23 @@ class FieldFragment
}
}

/// Returns the token for the initializer of this field, if any.
///
/// This can only be called once and will hand over the responsibility of
/// the token to the caller.
Token? get initializerToken {
Token? result = _initializerToken;
// Ensure that we don't hold onto the token.
_initializerToken = null;
return result;
}

// Coverage-ignore(suite): Not run.
/// Returns the token for the initializer of this field, if any. This is the
/// same as [initializerToken] but is used to signal that the initializer
/// needs to be computed for outline expressions.
///
/// This can only be called once and will hand over the responsibility of
/// the token to the caller.
Token? get constInitializerToken {
Token? result = _constInitializerToken;
// Ensure that we don't hold onto the token.
Expand Down Expand Up @@ -173,13 +182,63 @@ class FieldFragment
} else {
// A field with no type and initializer or an instance field without
// type and initializer need to have the type inferred.
_encoding.type =
new InferredType.fromFieldFragmentInitializer(this, token);
_encoding.type = new InferredType(
libraryBuilder: libraryBuilder,
typeBuilder: type,
inferType: inferType,
computeType: _computeInferredType,
fileUri: fileUri,
name: name,
nameOffset: nameOffset,
nameLength: name.length,
token: token);
type.registerInferable(this);
}
}
}

DartType _computeInferredType(
ClassHierarchyBase classHierarchy, Token? token) {
DartType? inferredType;
SourceLibraryBuilder libraryBuilder = builder.libraryBuilder;
DeclarationBuilder? declarationBuilder = builder.declarationBuilder;
if (token != null) {
InterfaceType? enclosingClassThisType = declarationBuilder
is SourceClassBuilder
? libraryBuilder.loader.typeInferenceEngine.coreTypes
.thisInterfaceType(
declarationBuilder.cls, libraryBuilder.library.nonNullable)
: null;
TypeInferrer typeInferrer =
libraryBuilder.loader.typeInferenceEngine.createTopLevelTypeInferrer(
fileUri,
enclosingClassThisType,
libraryBuilder,
builder
.dataForTesting
// Coverage-ignore(suite): Not run.
?.inferenceData);
BodyBuilderContext bodyBuilderContext = createBodyBuilderContext();
BodyBuilder bodyBuilder = libraryBuilder.loader.createBodyBuilderForField(
libraryBuilder,
bodyBuilderContext,
declarationBuilder?.scope ?? libraryBuilder.scope,
typeInferrer,
fileUri);
bodyBuilder.constantContext =
modifiers.isConst ? ConstantContext.inferred : ConstantContext.none;
bodyBuilder.inFieldInitializer = true;
bodyBuilder.inLateFieldInitializer = modifiers.isLate;
Expression initializer = bodyBuilder.parseFieldInitializer(token);

inferredType =
typeInferrer.inferImplicitFieldType(bodyBuilder, initializer);
} else {
inferredType = const DynamicType();
}
return inferredType;
}

@override
bool get isEnumElement => false;

Expand Down Expand Up @@ -240,13 +299,13 @@ class FieldFragment
// For modular compilation we need to include initializers of all const
// fields and all non-static final fields in classes with const constructors
// into the outline.
Token? token = constInitializerToken;
if ((modifiers.isConst ||
(isFinal &&
isClassInstanceMember &&
(declarationBuilder as SourceClassBuilder)
.declaresConstConstructor)) &&
_constInitializerToken != null) {
Token initializerToken = _constInitializerToken!;
token != null) {
LookupScope scope = declarationBuilder?.scope ?? libraryBuilder.scope;
BodyBuilder bodyBuilder = libraryBuilder.loader
.createBodyBuilderForOutlineExpression(
Expand All @@ -255,18 +314,17 @@ class FieldFragment
? ConstantContext.inferred
: ConstantContext.required;
Expression initializer = bodyBuilder.typeInferrer
.inferFieldInitializer(bodyBuilder, fieldType,
bodyBuilder.parseFieldInitializer(initializerToken))
.inferFieldInitializer(
bodyBuilder, fieldType, bodyBuilder.parseFieldInitializer(token))
.expression;
buildBody(classHierarchy.coreTypes, initializer);
bodyBuilder.performBacklogComputations();
if (computeSharedExpressionForTesting) {
// Coverage-ignore-block(suite): Not run.
_initializerExpression = parseFieldInitializer(libraryBuilder.loader,
initializerToken, libraryBuilder.importUri, fileUri, scope);
token, libraryBuilder.importUri, fileUri, scope);
}
}
_constInitializerToken = null;
}

@override
Expand Down
1 change: 1 addition & 0 deletions pkg/front_end/lib/src/fragment/fragment.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import '../source/source_type_alias_builder.dart';
import '../source/type_parameter_scope_builder.dart';
import '../type_inference/inference_results.dart';
import '../type_inference/type_inference_engine.dart';
import '../type_inference/type_inferrer.dart';
import '../type_inference/type_schema.dart';

part 'class.dart';
Expand Down
Loading

0 comments on commit 3f90ef6

Please sign in to comment.