[cfe] Add _ImplicitType to handle field and enum element inference
Change-Id: I00bb0817c6504de0f970d58abfaac294c16209e9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/405003
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/front_end/lib/src/fragment/enum_element.dart b/pkg/front_end/lib/src/fragment/enum_element.dart
index 9303fa0..3f9301c 100644
--- a/pkg/front_end/lib/src/fragment/enum_element.dart
+++ b/pkg/front_end/lib/src/fragment/enum_element.dart
@@ -20,12 +20,22 @@
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;
@@ -38,7 +48,8 @@
required this.nameOffset,
required this.fileUri,
required this.constructorReferenceBuilder,
- required this.argumentsBeginToken});
+ required Token? argumentsBeginToken})
+ : _argumentsBeginToken = argumentsBeginToken;
@override
SourcePropertyBuilder get builder {
@@ -53,6 +64,29 @@
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;
@@ -125,8 +159,8 @@
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;
@@ -174,8 +208,8 @@
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
@@ -185,7 +219,6 @@
arguments.positional.insertAll(0, enumSyntheticArguments);
arguments.argumentsOriginalOrder?.insertAll(0, enumSyntheticArguments);
- argumentsBeginToken = null;
} else {
arguments = new ArgumentsImpl(enumSyntheticArguments);
}
diff --git a/pkg/front_end/lib/src/fragment/field.dart b/pkg/front_end/lib/src/fragment/field.dart
index b4c46ca..5b9f2a0 100644
--- a/pkg/front_end/lib/src/fragment/field.dart
+++ b/pkg/front_end/lib/src/fragment/field.dart
@@ -66,6 +66,10 @@
}
}
+ /// 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.
@@ -73,7 +77,12 @@
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.
@@ -173,13 +182,63 @@
} 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;
@@ -240,13 +299,13 @@
// 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(
@@ -255,18 +314,17 @@
? 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
diff --git a/pkg/front_end/lib/src/fragment/fragment.dart b/pkg/front_end/lib/src/fragment/fragment.dart
index 4eda6be..41515c6 100644
--- a/pkg/front_end/lib/src/fragment/fragment.dart
+++ b/pkg/front_end/lib/src/fragment/fragment.dart
@@ -58,6 +58,7 @@
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';
diff --git a/pkg/front_end/lib/src/kernel/implicit_field_type.dart b/pkg/front_end/lib/src/kernel/implicit_field_type.dart
index 08f6420..c0ccb6a 100644
--- a/pkg/front_end/lib/src/kernel/implicit_field_type.dart
+++ b/pkg/front_end/lib/src/kernel/implicit_field_type.dart
@@ -10,13 +10,9 @@
import '../base/constant_context.dart';
import '../base/problems.dart' show unsupported;
-import '../builder/declaration_builders.dart';
import '../builder/inferable_type_builder.dart';
import '../builder/type_builder.dart';
import '../codes/cfe_codes.dart';
-import '../fragment/fragment.dart';
-import '../source/source_class_builder.dart';
-import '../source/source_enum_builder.dart';
import '../source/source_field_builder.dart';
import '../source/source_library_builder.dart';
import '../type_inference/type_inferrer.dart';
@@ -33,13 +29,16 @@
SourceFieldBuilder fieldBuilder, Token? initializerToken) =
_ImplicitFieldTypeRoot;
- factory InferredType.fromFieldFragmentInitializer(
- FieldFragment fieldFragment, Token? initializerToken) =
- _ImplicitFieldFragmentTypeRoot;
-
- factory InferredType.fromEnumElementInitializer(
- EnumElementFragment enumElementFragment) =
- _ImplicitEnumElementFragmentType;
+ factory InferredType(
+ {required SourceLibraryBuilder libraryBuilder,
+ required TypeBuilder typeBuilder,
+ required InferTypeFunction inferType,
+ required ComputeTypeFunction computeType,
+ required Uri fileUri,
+ required String name,
+ required int nameOffset,
+ required int nameLength,
+ required Token? token}) = _ImplicitType;
factory InferredType.fromInferableTypeUse(InferableTypeUse inferableTypeUse) =
_InferredTypeUse;
@@ -196,174 +195,99 @@
String toString() => 'ImplicitFieldType(${toStringInternal()})';
}
-class _ImplicitFieldFragmentTypeRoot extends InferredType {
- final FieldFragment _fieldFragment;
+/// Signature for function called to trigger the inference of the type of
+/// [_ImplicitType], if it hasn't already been computed.
+typedef InferTypeFunction = DartType Function(ClassHierarchyBase hierarchy);
- Token? initializerToken;
+/// Signature for function called to compute the type for [_ImplicitType]
+typedef ComputeTypeFunction = DartType Function(
+ ClassHierarchyBase hierarchy, Token? token);
+
+/// [InferredType] implementation that infers the type of [_typeBuilder] using
+/// [_computeType] and [_token].
+class _ImplicitType extends InferredType {
+ final SourceLibraryBuilder _libraryBuilder;
+ final TypeBuilder _typeBuilder;
+ final InferTypeFunction _inferType;
+ final ComputeTypeFunction _computeType;
+ final Uri _fileUri;
+ final String _name;
+ final int _nameOffset;
+ final int _nameLength;
+ Token? _token;
+
bool isStarted = false;
- _ImplicitFieldFragmentTypeRoot(this._fieldFragment, this.initializerToken)
- : super._();
+ _ImplicitType(
+ {required SourceLibraryBuilder libraryBuilder,
+ required TypeBuilder typeBuilder,
+ required InferTypeFunction inferType,
+ required ComputeTypeFunction computeType,
+ required Uri fileUri,
+ required String name,
+ required int nameOffset,
+ required int nameLength,
+ required Token? token})
+ : _libraryBuilder = libraryBuilder,
+ _typeBuilder = typeBuilder,
+ _inferType = inferType,
+ _computeType = computeType,
+ _fileUri = fileUri,
+ _name = name,
+ _nameOffset = nameOffset,
+ _nameLength = nameLength,
+ _token = token,
+ super._();
@override
// Coverage-ignore(suite): Not run.
- Uri get fileUri => _fieldFragment.fileUri;
+ Uri get fileUri => _fileUri;
@override
// Coverage-ignore(suite): Not run.
- int get charOffset => _fieldFragment.nameOffset;
+ int get charOffset => _nameOffset;
@override
DartType inferType(ClassHierarchyBase hierarchy) {
- return _fieldFragment.inferType(hierarchy);
+ return _inferType(hierarchy);
}
@override
DartType computeType(ClassHierarchyBase hierarchy) {
if (isStarted) {
- _fieldFragment.builder.libraryBuilder.addProblem(
- templateCantInferTypeDueToCircularity
- .withArguments(_fieldFragment.name),
- _fieldFragment.nameOffset,
- _fieldFragment.name.length,
- _fieldFragment.fileUri);
+ _libraryBuilder.addProblem(
+ templateCantInferTypeDueToCircularity.withArguments(_name),
+ _nameOffset,
+ _nameLength,
+ _fileUri);
DartType type = const InvalidType();
- _fieldFragment.type.registerInferredType(type);
+ _typeBuilder.registerInferredType(type);
return type;
}
isStarted = true;
- DartType? inferredType;
- SourceLibraryBuilder libraryBuilder = _fieldFragment.builder.libraryBuilder;
- DeclarationBuilder? declarationBuilder =
- _fieldFragment.builder.declarationBuilder;
- if (initializerToken != null) {
- InterfaceType? enclosingClassThisType = declarationBuilder
- is SourceClassBuilder
- ? libraryBuilder.loader.typeInferenceEngine.coreTypes
- .thisInterfaceType(
- declarationBuilder.cls, libraryBuilder.library.nonNullable)
- : null;
- TypeInferrer typeInferrer =
- libraryBuilder.loader.typeInferenceEngine.createTopLevelTypeInferrer(
- _fieldFragment.fileUri,
- enclosingClassThisType,
- libraryBuilder,
- _fieldFragment
- .builder
- .dataForTesting
- // Coverage-ignore(suite): Not run.
- ?.inferenceData);
- BodyBuilderContext bodyBuilderContext =
- _fieldFragment.createBodyBuilderContext();
- BodyBuilder bodyBuilder = libraryBuilder.loader.createBodyBuilderForField(
- libraryBuilder,
- bodyBuilderContext,
- declarationBuilder?.scope ?? libraryBuilder.scope,
- typeInferrer,
- _fieldFragment.fileUri);
- bodyBuilder.constantContext = _fieldFragment.modifiers.isConst
- ? ConstantContext.inferred
- : ConstantContext.none;
- bodyBuilder.inFieldInitializer = true;
- bodyBuilder.inLateFieldInitializer = _fieldFragment.modifiers.isLate;
- Expression initializer =
- bodyBuilder.parseFieldInitializer(initializerToken!);
- initializerToken = null;
-
- inferredType =
- typeInferrer.inferImplicitFieldType(bodyBuilder, initializer);
- } else {
- inferredType = const DynamicType();
- }
- return inferredType;
+ Token? token = _token;
+ _token = null;
+ return _computeType(hierarchy, token);
}
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
- printer.write('<implicit-field-type:$_fieldFragment>');
+ printer.write('<implicit-type:$_name>');
}
@override
// Coverage-ignore(suite): Not run.
bool equals(Object other, Assumptions? assumptions) {
if (identical(this, other)) return true;
- return other is _ImplicitFieldFragmentTypeRoot &&
- _fieldFragment == other._fieldFragment;
+ return other is _ImplicitType && _typeBuilder == other._typeBuilder;
}
@override
- int get hashCode => _fieldFragment.hashCode;
+ int get hashCode => _typeBuilder.hashCode;
@override
- String toString() => 'ImplicitFieldType(${toStringInternal()})';
-}
-
-class _ImplicitEnumElementFragmentType extends InferredType {
- final EnumElementFragment _enumElementFragment;
-
- bool isStarted = false;
-
- _ImplicitEnumElementFragmentType(this._enumElementFragment) : super._();
-
- @override
- // Coverage-ignore(suite): Not run.
- Uri get fileUri => _enumElementFragment.fileUri;
-
- @override
- // Coverage-ignore(suite): Not run.
- int get charOffset => _enumElementFragment.nameOffset;
-
- @override
- DartType inferType(ClassHierarchyBase hierarchy) {
- return _enumElementFragment.inferType(hierarchy);
- }
-
- @override
- DartType computeType(ClassHierarchyBase hierarchy) {
- if (isStarted) {
- // Coverage-ignore-block(suite): Not run.
- _enumElementFragment.builder.libraryBuilder.addProblem(
- templateCantInferTypeDueToCircularity
- .withArguments(_enumElementFragment.name),
- _enumElementFragment.nameOffset,
- _enumElementFragment.name.length,
- _enumElementFragment.fileUri);
- DartType type = const InvalidType();
- _enumElementFragment.type.registerInferredType(type);
- return type;
- }
- isStarted = true;
- SourceLibraryBuilder libraryBuilder =
- _enumElementFragment.builder.libraryBuilder;
- SourceEnumBuilder sourceEnumBuilder =
- _enumElementFragment.builder.declarationBuilder as SourceEnumBuilder;
- _enumElementFragment.buildElement(
- sourceEnumBuilder,
- sourceEnumBuilder.selfType.build(libraryBuilder, TypeUse.enumSelfType),
- libraryBuilder.loader.coreTypes);
- return _enumElementFragment.fieldType;
- }
-
- @override
- // Coverage-ignore(suite): Not run.
- void toTextInternal(AstPrinter printer) {
- printer.write('<implicit-field-type:$_enumElementFragment>');
- }
-
- @override
- // Coverage-ignore(suite): Not run.
- bool equals(Object other, Assumptions? assumptions) {
- if (identical(this, other)) return true;
- return other is _ImplicitEnumElementFragmentType &&
- _enumElementFragment == other._enumElementFragment;
- }
-
- @override
- int get hashCode => _enumElementFragment.hashCode;
-
- @override
- String toString() => 'ImplicitFieldType(${toStringInternal()})';
+ String toString() => '_ImplicitType(${toStringInternal()})';
}
class _InferredTypeUse extends InferredType {
diff --git a/pkg/front_end/test/coverage_suite_expected.dart b/pkg/front_end/test/coverage_suite_expected.dart
index b5b6fc4..7962768 100644
--- a/pkg/front_end/test/coverage_suite_expected.dart
+++ b/pkg/front_end/test/coverage_suite_expected.dart
@@ -490,7 +490,7 @@
),
// 100.0%.
"package:front_end/src/fragment/enum_element.dart": (
- hitCount: 224,
+ hitCount: 242,
missCount: 0,
),
// 100.0%.
@@ -510,7 +510,7 @@
),
// 100.0%.
"package:front_end/src/fragment/field.dart": (
- hitCount: 259,
+ hitCount: 302,
missCount: 0,
),
// 100.0%.
@@ -700,7 +700,7 @@
),
// 100.0%.
"package:front_end/src/kernel/implicit_field_type.dart": (
- hitCount: 93,
+ hitCount: 25,
missCount: 0,
),
// 100.0%.
@@ -925,7 +925,7 @@
),
// 100.0%.
"package:front_end/src/source/source_enum_builder.dart": (
- hitCount: 335,
+ hitCount: 331,
missCount: 0,
),
// 100.0%.
@@ -961,7 +961,7 @@
),
// 100.0%.
"package:front_end/src/source/source_loader.dart": (
- hitCount: 1868,
+ hitCount: 1855,
missCount: 0,
),
// 100.0%.