blob: 70c8c6aca9717b424105434b8197cf344bc2d0b1 [file] [log] [blame]
// Copyright (c) 2018, 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.
library fasta.implicit_type;
import 'package:_fe_analyzer_shared/src/scanner/token.dart' show Token;
import 'package:front_end/src/fasta/source/source_enum_builder.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/class_hierarchy.dart';
import 'package:kernel/src/assumptions.dart';
import 'package:kernel/src/printer.dart';
import '../builder/type_builder.dart';
import '../constant_context.dart';
import '../fasta_codes.dart';
import '../problems.dart' show unsupported;
import '../builder/builder.dart';
import '../source/source_field_builder.dart';
import '../type_inference/type_inferrer.dart';
import 'body_builder.dart';
abstract class InferredType extends DartType {
Uri? get fileUri;
int? get charOffset;
InferredType._();
factory InferredType.fromFieldInitializer(
SourceFieldBuilder fieldBuilder, Token? initializerToken) =
_ImplicitFieldTypeRoot;
factory InferredType.fromInferableTypeUse(InferableTypeUse inferableTypeUse) =
_InferredTypeUse;
@override
Nullability get declaredNullability =>
unsupported("declaredNullability", charOffset ?? -1, fileUri);
@override
Nullability get nullability {
unsupported("nullability", charOffset ?? -1, fileUri);
}
@override
R accept<R>(DartTypeVisitor<R> v) {
throw unsupported("accept", charOffset ?? -1, fileUri);
}
@override
R accept1<R, A>(DartTypeVisitor1<R, A> v, arg) {
throw unsupported("accept1", charOffset ?? -1, fileUri);
}
@override
Never visitChildren(Visitor<dynamic> v) {
unsupported("visitChildren", charOffset ?? -1, fileUri);
}
@override
InferredType withDeclaredNullability(Nullability nullability) {
return unsupported("withNullability", charOffset ?? -1, fileUri);
}
@override
InferredType toNonNull() {
return unsupported("toNonNullable", charOffset ?? -1, fileUri);
}
DartType inferType(ClassHierarchyBase hierarchy);
DartType computeType(ClassHierarchyBase hierarchy);
}
class _ImplicitFieldTypeRoot extends InferredType {
final SourceFieldBuilder fieldBuilder;
Token? initializerToken;
bool isStarted = false;
_ImplicitFieldTypeRoot(this.fieldBuilder, this.initializerToken) : super._();
@override
Uri get fileUri => fieldBuilder.fileUri;
@override
int get charOffset => fieldBuilder.charOffset;
@override
DartType inferType(ClassHierarchyBase hierarchy) {
return fieldBuilder.inferType(hierarchy);
}
@override
DartType computeType(ClassHierarchyBase hierarchy) {
if (isStarted) {
fieldBuilder.libraryBuilder.addProblem(
templateCantInferTypeDueToCircularity
.withArguments(fieldBuilder.name),
fieldBuilder.charOffset,
fieldBuilder.name.length,
fieldBuilder.fileUri);
DartType type = const InvalidType();
fieldBuilder.type.registerInferredType(type);
return type;
}
isStarted = true;
DartType? inferredType;
Builder? parent = fieldBuilder.parent;
if (parent is SourceEnumBuilder &&
parent.elementBuilders.contains(fieldBuilder)) {
inferredType = parent.buildElement(
fieldBuilder, parent.libraryBuilder.loader.coreTypes);
} else if (initializerToken != null) {
InterfaceType? enclosingClassThisType = fieldBuilder.classBuilder == null
? null
: fieldBuilder.libraryBuilder.loader.typeInferenceEngine.coreTypes
.thisInterfaceType(fieldBuilder.classBuilder!.cls,
fieldBuilder.libraryBuilder.library.nonNullable);
TypeInferrer typeInferrer = fieldBuilder
.libraryBuilder.loader.typeInferenceEngine
.createTopLevelTypeInferrer(
fieldBuilder.fileUri,
enclosingClassThisType,
fieldBuilder.libraryBuilder,
fieldBuilder.dataForTesting?.inferenceData);
BodyBuilder bodyBuilder = fieldBuilder.libraryBuilder.loader
.createBodyBuilderForField(fieldBuilder, typeInferrer);
bodyBuilder.constantContext = fieldBuilder.isConst
? ConstantContext.inferred
: ConstantContext.none;
bodyBuilder.inFieldInitializer = true;
bodyBuilder.inLateFieldInitializer = fieldBuilder.isLate;
Expression initializer =
bodyBuilder.parseFieldInitializer(initializerToken!);
initializerToken = null;
inferredType =
typeInferrer.inferImplicitFieldType(bodyBuilder, initializer);
} else {
inferredType = const DynamicType();
}
return inferredType;
}
@override
void toTextInternal(AstPrinter printer) {
printer.write('<implicit-field-type:$fieldBuilder>');
}
@override
bool operator ==(Object other) => equals(other, null);
@override
bool equals(Object other, Assumptions? assumptions) {
if (identical(this, other)) return true;
return other is _ImplicitFieldTypeRoot &&
fieldBuilder == other.fieldBuilder;
}
@override
int get hashCode => fieldBuilder.hashCode;
@override
String toString() => 'ImplicitFieldType(${toStringInternal()})';
}
class _InferredTypeUse extends InferredType {
final InferableTypeUse inferableTypeUse;
_InferredTypeUse(this.inferableTypeUse) : super._();
@override
int? get charOffset => inferableTypeUse.typeBuilder.charOffset;
@override
Uri? get fileUri => inferableTypeUse.typeBuilder.fileUri;
@override
DartType computeType(ClassHierarchyBase hierarchy) {
return inferType(hierarchy);
}
@override
DartType inferType(ClassHierarchyBase hierarchy) {
return inferableTypeUse.inferType(hierarchy);
}
@override
void toTextInternal(AstPrinter printer) {
printer.write('<inferred-type:${inferableTypeUse.typeBuilder}>');
}
@override
bool operator ==(Object other) => equals(other, null);
@override
bool equals(Object other, Assumptions? assumptions) {
if (identical(this, other)) return true;
return other is _InferredTypeUse &&
inferableTypeUse.typeBuilder == other.inferableTypeUse.typeBuilder;
}
@override
int get hashCode => inferableTypeUse.typeBuilder.hashCode;
@override
String toString() => 'InferredTypeUse(${toStringInternal()})';
}