blob: 54d2a6a6ff6cd938eddf8fb6ec0bd2d83d5dd6db [file] [log] [blame]
// Copyright (c) 2017, 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.function_type_builder;
import 'package:kernel/ast.dart'
show
DartType,
DynamicType,
FunctionType,
NamedType,
Supertype,
TypeParameter,
TypedefType;
import '../fasta_codes.dart' show messageSupertypeIsFunction, noLength;
import '../source/source_library_builder.dart';
import 'formal_parameter_builder.dart';
import 'library_builder.dart';
import 'nullability_builder.dart';
import 'type_builder.dart';
import 'type_variable_builder.dart';
class FunctionTypeBuilder extends TypeBuilder {
final TypeBuilder? returnType;
final List<TypeVariableBuilder>? typeVariables;
final List<FormalParameterBuilder>? formals;
final NullabilityBuilder nullabilityBuilder;
final Uri? fileUri;
final int charOffset;
FunctionTypeBuilder(this.returnType, this.typeVariables, this.formals,
this.nullabilityBuilder, this.fileUri, this.charOffset);
@override
String? get name => null;
@override
String get debugName => "Function";
bool get isVoidType => false;
@override
StringBuffer printOn(StringBuffer buffer) {
if (typeVariables != null) {
buffer.write("<");
bool isFirst = true;
for (TypeVariableBuilder t in typeVariables!) {
if (!isFirst) {
buffer.write(", ");
} else {
isFirst = false;
}
buffer.write(t.name);
}
buffer.write(">");
}
buffer.write("(");
if (formals != null) {
bool isFirst = true;
for (FormalParameterBuilder t in formals!) {
if (!isFirst) {
buffer.write(", ");
} else {
isFirst = false;
}
buffer.write(t.fullNameForErrors);
}
}
buffer.write(") ->");
nullabilityBuilder.writeNullabilityOn(buffer);
buffer.write(" ");
buffer.write(returnType?.fullNameForErrors);
return buffer;
}
FunctionType build(LibraryBuilder library,
{TypedefType? origin, bool? nonInstanceContext}) {
DartType builtReturnType =
returnType?.build(library, nonInstanceContext: nonInstanceContext) ??
const DynamicType();
List<DartType> positionalParameters = <DartType>[];
List<NamedType>? namedParameters;
int requiredParameterCount = 0;
if (formals != null) {
for (FormalParameterBuilder formal in formals!) {
DartType type = formal.type
?.build(library, nonInstanceContext: nonInstanceContext) ??
const DynamicType();
if (formal.isPositional) {
positionalParameters.add(type);
if (formal.isRequired) requiredParameterCount++;
} else if (formal.isNamed) {
namedParameters ??= <NamedType>[];
namedParameters.add(new NamedType(formal.name, type,
isRequired: formal.isNamedRequired));
}
}
if (namedParameters != null) {
namedParameters.sort();
}
}
List<TypeParameter>? typeParameters;
if (typeVariables != null) {
typeParameters = <TypeParameter>[];
for (TypeVariableBuilder t in typeVariables!) {
typeParameters.add(t.parameter);
// Build the bound to detect cycles in typedefs.
t.bound?.build(library, origin: origin);
}
}
return new FunctionType(positionalParameters, builtReturnType,
nullabilityBuilder.build(library),
namedParameters: namedParameters ?? const <NamedType>[],
typeParameters: typeParameters ?? const <TypeParameter>[],
requiredParameterCount: requiredParameterCount,
typedefType: origin);
}
Supertype? buildSupertype(
LibraryBuilder library, int charOffset, Uri fileUri) {
library.addProblem(
messageSupertypeIsFunction, charOffset, noLength, fileUri);
return null;
}
Supertype? buildMixedInType(
LibraryBuilder library, int charOffset, Uri fileUri) {
return buildSupertype(library, charOffset, fileUri);
}
FunctionTypeBuilder clone(
List<TypeBuilder> newTypes,
SourceLibraryBuilder contextLibrary,
TypeParameterScopeBuilder contextDeclaration) {
List<TypeVariableBuilder>? clonedTypeVariables;
if (typeVariables != null) {
clonedTypeVariables =
contextLibrary.copyTypeVariables(typeVariables!, contextDeclaration);
}
List<FormalParameterBuilder>? clonedFormals;
if (formals != null) {
clonedFormals =
new List<FormalParameterBuilder>.generate(formals!.length, (int i) {
FormalParameterBuilder formal = formals![i];
return formal.clone(newTypes, contextLibrary, contextDeclaration);
}, growable: false);
}
FunctionTypeBuilder newType = new FunctionTypeBuilder(
returnType?.clone(newTypes, contextLibrary, contextDeclaration),
clonedTypeVariables,
clonedFormals,
nullabilityBuilder,
fileUri,
charOffset);
newTypes.add(newType);
return newType;
}
FunctionTypeBuilder withNullabilityBuilder(
NullabilityBuilder nullabilityBuilder) {
return new FunctionTypeBuilder(returnType, typeVariables, formals,
nullabilityBuilder, fileUri, charOffset);
}
}