blob: 792c92f1a1be40cbae1e90f5fed2b675bd886cb3 [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:kernel/ast.dart';
import 'package:kernel/src/assumptions.dart';
import 'package:kernel/src/legacy_erasure.dart';
import 'package:kernel/src/printer.dart';
import '../constant_context.dart';
import '../fasta_codes.dart';
import '../problems.dart' show unsupported;
import '../source/source_field_builder.dart';
import '../type_inference/type_inferrer.dart';
import '../type_inference/type_schema.dart';
import 'body_builder.dart';
abstract class ImplicitFieldType extends DartType {
SourceFieldBuilder get fieldBuilder;
ImplicitFieldType._();
factory ImplicitFieldType(
SourceFieldBuilder fieldBuilder, Token? initializerToken) =
_ImplicitFieldTypeRoot;
@override
Nullability get declaredNullability => unsupported(
"declaredNullability", fieldBuilder.charOffset, fieldBuilder.fileUri);
@override
Nullability get nullability =>
unsupported("nullability", fieldBuilder.charOffset, fieldBuilder.fileUri);
@override
R accept<R>(DartTypeVisitor<R> v) {
throw unsupported("accept", fieldBuilder.charOffset, fieldBuilder.fileUri);
}
@override
R accept1<R, A>(DartTypeVisitor1<R, A> v, arg) {
throw unsupported("accept1", fieldBuilder.charOffset, fieldBuilder.fileUri);
}
@override
Never visitChildren(Visitor<dynamic> v) {
unsupported("visitChildren", fieldBuilder.charOffset, fieldBuilder.fileUri);
}
@override
ImplicitFieldType withDeclaredNullability(Nullability nullability) {
return unsupported(
"withNullability", fieldBuilder.charOffset, fieldBuilder.fileUri);
}
@override
ImplicitFieldType toNonNull() {
return unsupported(
"toNonNullable", fieldBuilder.charOffset, fieldBuilder.fileUri);
}
@override
void toTextInternal(AstPrinter printer) {
printer.write('<implicit-field-type:$fieldBuilder>');
}
void addOverride(ImplicitFieldType other);
DartType checkInferred(DartType type);
@override
bool operator ==(Object other) => equals(other, null);
@override
bool equals(Object other, Assumptions? assumptions) {
if (identical(this, other)) return true;
return other is ImplicitFieldType && fieldBuilder == other.fieldBuilder;
}
@override
int get hashCode => fieldBuilder.hashCode;
DartType inferType();
DartType computeType();
}
class _ImplicitFieldTypeRoot extends ImplicitFieldType {
@override
final SourceFieldBuilder fieldBuilder;
List<ImplicitFieldType>? _overriddenFields;
Token? initializerToken;
bool isStarted = false;
_ImplicitFieldTypeRoot(this.fieldBuilder, this.initializerToken) : super._();
@override
DartType inferType() {
return fieldBuilder.inferType();
}
@override
DartType computeType() {
if (isStarted) {
fieldBuilder.library.addProblem(
templateCantInferTypeDueToCircularity
.withArguments(fieldBuilder.name),
fieldBuilder.charOffset,
fieldBuilder.name.length,
fieldBuilder.fileUri);
return fieldBuilder.fieldType = const InvalidType();
}
isStarted = true;
DartType? inferredType;
if (_overriddenFields != null) {
for (ImplicitFieldType overridden in _overriddenFields!) {
DartType overriddenType = overridden.inferType();
if (!fieldBuilder.library.isNonNullableByDefault) {
overriddenType = legacyErasure(overriddenType);
}
if (inferredType == null) {
inferredType = overriddenType;
} else if (inferredType != overriddenType) {
inferredType = const InvalidType();
}
}
return inferredType!;
} else if (initializerToken != null) {
InterfaceType? enclosingClassThisType = fieldBuilder.classBuilder == null
? null
: fieldBuilder.library.loader.typeInferenceEngine.coreTypes
.thisInterfaceType(fieldBuilder.classBuilder!.cls,
fieldBuilder.library.library.nonNullable);
TypeInferrer typeInferrer = fieldBuilder
.library.loader.typeInferenceEngine
.createTopLevelTypeInferrer(
fieldBuilder.fileUri,
enclosingClassThisType,
fieldBuilder.library,
fieldBuilder.dataForTesting?.inferenceData);
BodyBuilder bodyBuilder = fieldBuilder.library.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;
ExpressionInferenceResult result = typeInferrer.inferExpression(
initializer, const UnknownType(), true,
isVoidAllowed: true);
inferredType = typeInferrer.inferDeclarationType(result.inferredType);
} else {
inferredType = const DynamicType();
}
return inferredType;
}
@override
void addOverride(ImplicitFieldType other) {
(_overriddenFields ??= []).add(other);
}
@override
DartType checkInferred(DartType type) {
if (_overriddenFields != null) {
for (ImplicitFieldType overridden in _overriddenFields!) {
DartType overriddenType = overridden.inferType();
if (!fieldBuilder.library.isNonNullableByDefault) {
overriddenType = legacyErasure(overriddenType);
}
if (type != overriddenType) {
String name = fieldBuilder.fullNameForErrors;
fieldBuilder.classBuilder!.addProblem(
templateCantInferTypeDueToNoCombinedSignature.withArguments(name),
fieldBuilder.charOffset,
name.length,
wasHandled: true);
return const InvalidType();
}
}
}
return type;
}
@override
String toString() => 'ImplicitFieldType(${toStringInternal()})';
}