blob: db9c9ed98391836e9fc9cef469d6796726dc4490 [file] [log] [blame]
// Copyright (c) 2016, 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.
// @dart = 2.9
library fasta.type_variable_builder;
import 'package:kernel/ast.dart'
show DartType, Nullability, TypeParameter, TypeParameterType;
import 'package:kernel/core_types.dart';
import '../fasta_codes.dart'
show
templateInternalProblemUnfinishedTypeVariable,
templateTypeArgumentsOnTypeVariable;
import '../source/source_library_builder.dart';
import '../util/helpers.dart';
import 'class_builder.dart';
import 'declaration_builder.dart';
import 'library_builder.dart';
import 'member_builder.dart';
import 'metadata_builder.dart';
import 'named_type_builder.dart';
import 'nullability_builder.dart';
import 'type_builder.dart';
import 'type_declaration_builder.dart';
class TypeVariableBuilder extends TypeDeclarationBuilderImpl {
TypeBuilder bound;
TypeBuilder defaultType;
final TypeParameter actualParameter;
TypeVariableBuilder actualOrigin;
final bool isExtensionTypeParameter;
TypeVariableBuilder(String name, SourceLibraryBuilder compilationUnit,
int charOffset, Uri fileUri,
{this.bound,
this.isExtensionTypeParameter: false,
int variableVariance,
List<MetadataBuilder> metadata})
: actualParameter = new TypeParameter(name, null)
..fileOffset = charOffset
..variance = variableVariance,
super(metadata, 0, name, compilationUnit, charOffset, fileUri);
TypeVariableBuilder.fromKernel(
TypeParameter parameter, LibraryBuilder compilationUnit)
: actualParameter = parameter,
// TODO(johnniwinther): Do we need to support synthesized type
// parameters from kernel?
this.isExtensionTypeParameter = false,
super(null, 0, parameter.name, compilationUnit, parameter.fileOffset);
bool get isTypeVariable => true;
String get debugName => "TypeVariableBuilder";
StringBuffer printOn(StringBuffer buffer) {
buffer.write(name);
if (bound != null) {
buffer.write(" extends ");
bound.printOn(buffer);
}
return buffer;
}
String toString() => "${printOn(new StringBuffer())}";
TypeVariableBuilder get origin => actualOrigin ?? this;
/// The [TypeParameter] built by this builder.
TypeParameter get parameter => origin.actualParameter;
int get variance => parameter.variance;
void set variance(int value) {
parameter.variance = value;
}
DartType buildType(LibraryBuilder library,
NullabilityBuilder nullabilityBuilder, List<TypeBuilder> arguments,
[bool notInstanceContext]) {
if (arguments != null) {
int charOffset = -1; // TODO(ahe): Provide these.
Uri fileUri = null; // TODO(ahe): Provide these.
library.addProblem(
templateTypeArgumentsOnTypeVariable.withArguments(name),
charOffset,
name.length,
fileUri);
}
// If the bound is not set yet, the actual value is not important yet as it
// will be set later.
bool needsPostUpdate = false;
Nullability nullability;
if (nullabilityBuilder.isOmitted) {
if (!identical(parameter.bound, TypeParameter.unsetBoundSentinel)) {
nullability = library.isNonNullableByDefault
? TypeParameterType.computeNullabilityFromBound(parameter)
: Nullability.legacy;
} else {
nullability = Nullability.legacy;
needsPostUpdate = true;
}
} else {
nullability = nullabilityBuilder.build(library);
}
DartType type = buildTypesWithBuiltArguments(library, nullability, null);
if (needsPostUpdate) {
if (library is SourceLibraryBuilder) {
library.registerPendingNullability(fileUri, charOffset, type);
} else {
library.addProblem(
templateInternalProblemUnfinishedTypeVariable.withArguments(
name, library?.importUri),
charOffset,
name.length,
fileUri);
}
}
return type;
}
DartType buildTypesWithBuiltArguments(LibraryBuilder library,
Nullability nullability, List<DartType> arguments) {
if (arguments != null) {
int charOffset = -1; // TODO(ahe): Provide these.
Uri fileUri = null; // TODO(ahe): Provide these.
library.addProblem(
templateTypeArgumentsOnTypeVariable.withArguments(name),
charOffset,
name.length,
fileUri);
}
return new TypeParameterType(parameter, nullability);
}
TypeBuilder asTypeBuilder() {
return new NamedTypeBuilder(
name, const NullabilityBuilder.omitted(), null, fileUri, charOffset)
..bind(this);
}
void finish(
LibraryBuilder library, ClassBuilder object, TypeBuilder dynamicType) {
if (isPatch) return;
// TODO(jensj): Provide correct notInstanceContext.
DartType objectType =
object.buildType(library, library.nullableBuilder, null, null);
if (identical(parameter.bound, TypeParameter.unsetBoundSentinel)) {
parameter.bound = bound?.build(library) ?? objectType;
}
// If defaultType is not set, initialize it to dynamic, unless the bound is
// explicitly specified as Object, in which case defaultType should also be
// Object. This makes sure instantiation of generic function types with an
// explicit Object bound results in Object as the instantiated type.
if (identical(
parameter.defaultType, TypeParameter.unsetDefaultTypeSentinel)) {
parameter.defaultType = defaultType?.build(library) ??
(bound != null && parameter.bound == objectType
? objectType
: dynamicType.build(library));
}
}
void applyPatch(covariant TypeVariableBuilder patch) {
patch.actualOrigin = this;
}
TypeVariableBuilder clone(List<TypeBuilder> newTypes) {
// TODO(dmitryas): Figure out if using [charOffset] here is a good idea.
// An alternative is to use the offset of the node the cloned type variable
// is declared on.
return new TypeVariableBuilder(name, parent, charOffset, fileUri,
bound: bound.clone(newTypes), variableVariance: variance);
}
void buildOutlineExpressions(
LibraryBuilder libraryBuilder,
DeclarationBuilder classOrExtensionBuilder,
MemberBuilder memberBuilder,
CoreTypes coreTypes,
List<DelayedActionPerformer> delayedActionPerformers) {
MetadataBuilder.buildAnnotations(parameter, metadata, libraryBuilder,
classOrExtensionBuilder, memberBuilder, fileUri);
}
@override
bool operator ==(Object other) {
return other is TypeVariableBuilder && parameter == other.parameter;
}
@override
int get hashCode => parameter.hashCode;
static List<TypeParameter> typeParametersFromBuilders(
List<TypeVariableBuilder> builders) {
if (builders == null) return null;
List<TypeParameter> result =
new List<TypeParameter>.filled(builders.length, null, growable: true);
for (int i = 0; i < builders.length; i++) {
result[i] = builders[i].parameter;
}
return result;
}
}