blob: 78e06d865670b4cd9c7279452346ccf8ac80b937 [file] [log] [blame]
// Copyright (c) 2022, 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:kernel/ast.dart';
import 'package:kernel/class_hierarchy.dart';
import '../kernel/implicit_field_type.dart';
import '../source/source_library_builder.dart';
import 'library_builder.dart';
import 'named_type_builder.dart';
import 'nullability_builder.dart';
import 'type_builder.dart';
import 'type_declaration_builder.dart';
abstract class OmittedTypeBuilder extends TypeBuilder {
const OmittedTypeBuilder();
@override
Supertype? buildMixedInType(LibraryBuilder library) {
throw new UnsupportedError('$runtimeType.buildMixedInType');
}
@override
Supertype? buildSupertype(LibraryBuilder library) {
throw new UnsupportedError('$runtimeType.buildSupertype');
}
@override
int? get charOffset => null;
@override
TypeBuilder clone(
List<NamedTypeBuilder> newTypes,
SourceLibraryBuilder contextLibrary,
TypeParameterScopeBuilder contextDeclaration) {
return this;
}
@override
Uri? get fileUri => null;
@override
bool get isVoidType => false;
@override
Object? get name => null;
@override
NullabilityBuilder get nullabilityBuilder =>
const NullabilityBuilder.omitted();
@override
TypeBuilder withNullabilityBuilder(NullabilityBuilder nullabilityBuilder) {
return this;
}
bool get hasType;
DartType get type;
}
class ImplicitTypeBuilder extends OmittedTypeBuilder {
const ImplicitTypeBuilder();
@override
DartType build(LibraryBuilder library, TypeUse typeUse,
{ClassHierarchyBase? hierarchy}) =>
type;
@override
DartType buildAliased(LibraryBuilder library, TypeUse typeUse,
ClassHierarchyBase? hierarchy) =>
type;
@override
String get debugName => 'ImplicitTypeBuilder';
@override
StringBuffer printOn(StringBuffer buffer) => buffer;
@override
bool get isExplicit => true;
@override
bool get hasType => true;
@override
DartType get type => const DynamicType();
}
class InferableTypeBuilder extends OmittedTypeBuilder
with InferableTypeBuilderMixin
implements InferableType {
@override
DartType build(LibraryBuilder library, TypeUse typeUse,
{ClassHierarchyBase? hierarchy}) {
if (hierarchy != null) {
inferType(hierarchy);
return type;
} else {
InferableTypeUse inferableTypeUse =
new InferableTypeUse(library as SourceLibraryBuilder, this, typeUse);
library.registerInferableType(inferableTypeUse);
return new InferredType.fromInferableTypeUse(inferableTypeUse);
}
}
@override
DartType buildAliased(
LibraryBuilder library, TypeUse typeUse, ClassHierarchyBase? hierarchy) {
if (hierarchy != null) {
inferType(hierarchy);
return type;
}
throw new UnsupportedError('$runtimeType.buildAliased');
}
@override
bool get isExplicit => false;
@override
void registerInferredType(DartType type) {
registerType(type);
}
Inferable? _inferable;
Inferable? get inferable => _inferable;
@override
void registerInferable(Inferable inferable) {
assert(
_inferable == null,
"Inferable $_inferable has already been register, "
"trying to register $inferable.");
_inferable = inferable;
}
/// Triggers inference of this type.
///
/// If an [Inferable] has been register, this is called to infer the type of
/// this builder. Otherwise the type is inferred to be `dynamic`.
@override
DartType inferType(ClassHierarchyBase hierarchy) {
if (!hasType) {
Inferable? inferable = _inferable;
if (inferable != null) {
inferable.inferTypes(hierarchy);
} else {
registerInferredType(const DynamicType());
}
assert(hasType);
}
return type;
}
@override
String get debugName => 'InferredTypeBuilder';
@override
StringBuffer printOn(StringBuffer buffer) {
buffer.write('(inferable=');
buffer.write(inferable);
buffer.write(')');
return buffer;
}
}
/// A type defined in terms of another omitted type.
///
/// This is used in macro generated code to create type annotations from
/// inferred types in the original code.
class DependentTypeBuilder extends OmittedTypeBuilder
with InferableTypeBuilderMixin
implements InferredTypeListener {
final OmittedTypeBuilder typeBuilder;
DependentTypeBuilder(this.typeBuilder) {
typeBuilder.registerInferredTypeListener(this);
}
@override
void onInferredType(DartType type) {
registerType(type);
}
@override
DartType build(LibraryBuilder library, TypeUse typeUse,
{ClassHierarchyBase? hierarchy}) {
if (hasType) {
return type;
}
if (hierarchy != null) {
return typeBuilder.build(library, typeUse, hierarchy: hierarchy);
} else {
InferableTypeUse inferableTypeUse =
new InferableTypeUse(library as SourceLibraryBuilder, this, typeUse);
library.registerInferableType(inferableTypeUse);
return new InferredType.fromInferableTypeUse(inferableTypeUse);
}
}
@override
DartType buildAliased(
LibraryBuilder library, TypeUse typeUse, ClassHierarchyBase? hierarchy) {
return typeBuilder.buildAliased(library, typeUse, hierarchy);
}
@override
bool get isExplicit => false;
@override
String get debugName => 'DependentTypeBuilder';
@override
StringBuffer printOn(StringBuffer buffer) {
buffer.write('(dependency=');
buffer.write(typeBuilder);
buffer.write(')');
return buffer;
}
}
/// Listener for the late computation of an inferred type.
abstract class InferredTypeListener {
/// Called when the type of an [InferableTypeBuilder] has been computed.
void onInferredType(DartType type);
}
/// Interface for builders that can infer the type of an [InferableTypeBuilder].
abstract class Inferable {
/// Triggers the inference of the types of one or more
/// [InferableTypeBuilder]s.
void inferTypes(ClassHierarchyBase hierarchy);
}
/// [TypeDeclaration] wrapper for an [OmittedTypeBuilder].
///
/// This is used in macro generated code to create type annotations from
/// inferred types in the original code.
class OmittedTypeDeclarationBuilder extends TypeDeclarationBuilderImpl {
OmittedTypeBuilder omittedTypeBuilder;
OmittedTypeDeclarationBuilder(
String name, this.omittedTypeBuilder, SourceLibraryBuilder parent)
: super(null, 0, name, parent, TreeNode.noOffset);
@override
DartType buildAliasedType(
LibraryBuilder library,
NullabilityBuilder nullabilityBuilder,
List<TypeBuilder>? arguments,
TypeUse typeUse,
Uri fileUri,
int charOffset,
ClassHierarchyBase? hierarchy,
{required bool hasExplicitTypeArguments}) {
// TODO(johnniwinther): This should probably be an error case.
throw new UnimplementedError('${runtimeType}.buildAliasedType');
}
@override
DartType buildAliasedTypeWithBuiltArguments(
LibraryBuilder library,
Nullability nullability,
List<DartType> arguments,
TypeUse typeUse,
Uri fileUri,
int charOffset,
{required bool hasExplicitTypeArguments}) {
// TODO(johnniwinther): This should probably be an error case.
throw new UnimplementedError(
'${runtimeType}.buildAliasedTypeWithBuiltArguments');
}
@override
String get debugName => 'OmittedTypeDeclarationBuilder';
@override
Uri? get fileUri => parent!.fileUri;
}