blob: 61ca4ad7b76716533eb31bc5bf2012ad58eb0574 [file] [log] [blame]
// Copyright (c) 2019, 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 'package:kernel/type_environment.dart';
import '../base/messages.dart';
import '../base/problems.dart';
import '../base/scope.dart';
import '../builder/builder.dart';
import '../builder/builder_mixins.dart';
import '../builder/declaration_builders.dart';
import '../builder/library_builder.dart';
import '../builder/member_builder.dart';
import '../builder/metadata_builder.dart';
import '../builder/name_iterator.dart';
import '../builder/procedure_builder.dart';
import '../builder/type_builder.dart';
import '../kernel/body_builder_context.dart';
import '../kernel/kernel_helper.dart';
import 'source_constructor_builder.dart';
import 'source_field_builder.dart';
import 'source_library_builder.dart';
import 'source_loader.dart';
import 'source_member_builder.dart';
import 'source_procedure_builder.dart';
abstract class SourceDeclarationBuilder implements IDeclarationBuilder {
void buildScopes(LibraryBuilder coreLibrary);
}
mixin SourceDeclarationBuilderMixin
implements DeclarationBuilderMixin, SourceDeclarationBuilder {
@override
SourceLibraryBuilder get libraryBuilder;
@override
Uri get fileUri;
/// Returns the [Annotatable] node that holds the annotations declared on
/// this declaration or its augmentations.
Annotatable get annotatable;
/// Builds the [Extension] for this extension build and inserts the members
/// into the [Library] of [libraryBuilder].
///
/// [addMembersToLibrary] is `true` if the extension members should be added
/// to the library. This is `false` if the extension is in conflict with
/// another library member. In this case, the extension member should not be
/// added to the library to avoid name clashes with other members in the
/// library.
void buildInternal(LibraryBuilder coreLibrary,
{required bool addMembersToLibrary}) {
SourceLibraryBuilder.checkMemberConflicts(libraryBuilder, nameSpace,
checkForInstanceVsStaticConflict: true,
checkForMethodVsSetterConflict: true);
ClassBuilder objectClassBuilder =
coreLibrary.lookupLocalMember('Object', required: true) as ClassBuilder;
void buildBuilders(String name, Builder declaration) {
Builder? objectGetter = objectClassBuilder.lookupLocalMember(name);
Builder? objectSetter =
objectClassBuilder.lookupLocalMember(name, setter: true);
if (objectGetter != null && !objectGetter.isStatic ||
// Coverage-ignore(suite): Not run.
objectSetter != null && !objectSetter.isStatic) {
addProblem(
// TODO(johnniwinther): Use a different error message for extension
// type declarations.
templateExtensionMemberConflictsWithObjectMember
.withArguments(name),
declaration.charOffset,
name.length);
}
if (declaration.parent != this) {
// Coverage-ignore-block(suite): Not run.
if (fileUri != declaration.parent!.fileUri) {
unexpected("$fileUri", "${declaration.parent!.fileUri}", charOffset,
fileUri);
} else {
unexpected(fullNameForErrors, declaration.parent!.fullNameForErrors,
charOffset, fileUri);
}
} else if (declaration is SourceMemberBuilder) {
SourceMemberBuilder memberBuilder = declaration;
memberBuilder.buildOutlineNodes((
{required Member member,
Member? tearOff,
required BuiltMemberKind kind}) {
_buildMember(memberBuilder, member, tearOff, kind,
addMembersToLibrary: addMembersToLibrary);
});
} else {
unhandled("${declaration.runtimeType}", "buildBuilders",
declaration.charOffset, declaration.fileUri);
}
}
nameSpace.unfilteredNameIterator.forEach(buildBuilders);
nameSpace.unfilteredConstructorNameIterator.forEach(buildBuilders);
}
int buildBodyNodes({required bool addMembersToLibrary}) {
int count = 0;
Iterator<SourceMemberBuilder> iterator = nameSpace
.filteredIterator<SourceMemberBuilder>(
parent: this, includeDuplicates: false, includeAugmentations: true)
.join(nameSpace.filteredConstructorIterator<SourceMemberBuilder>(
parent: this,
includeDuplicates: false,
includeAugmentations: true));
while (iterator.moveNext()) {
SourceMemberBuilder declaration = iterator.current;
count += declaration.buildBodyNodes(
// Coverage-ignore(suite): Not run.
(
{required Member member,
Member? tearOff,
required BuiltMemberKind kind}) {
_buildMember(declaration, member, tearOff, kind,
addMembersToLibrary: addMembersToLibrary);
});
}
return count;
}
void checkTypesInOutline(TypeEnvironment typeEnvironment) {
forEach((String name, Builder builder) {
if (builder is SourceFieldBuilder) {
// Check fields.
libraryBuilder.checkTypesInField(builder, typeEnvironment);
} else if (builder is SourceProcedureBuilder) {
// Check procedures
libraryBuilder.checkTypesInFunctionBuilder(builder, typeEnvironment);
if (builder.isGetter) {
Builder? setterDeclaration =
nameSpace.lookupLocalMember(builder.name, setter: true);
if (setterDeclaration != null) {
libraryBuilder.checkGetterSetterTypes(builder,
setterDeclaration as ProcedureBuilder, typeEnvironment);
}
}
}
// Coverage-ignore(suite): Not run.
else if (builder is SourceConstructorBuilder) {
builder.checkTypes(libraryBuilder, typeEnvironment);
} else {
assert(false, "Unexpected member: $builder.");
}
});
}
BodyBuilderContext createBodyBuilderContext(
{required bool inOutlineBuildingPhase,
required bool inMetadata,
required bool inConstFields});
void buildOutlineExpressions(ClassHierarchy classHierarchy,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {
MetadataBuilder.buildAnnotations(
annotatable,
metadata,
createBodyBuilderContext(
inOutlineBuildingPhase: true,
inMetadata: true,
inConstFields: false),
libraryBuilder,
fileUri,
libraryBuilder.scope);
if (typeParameters != null) {
for (int i = 0; i < typeParameters!.length; i++) {
typeParameters![i].buildOutlineExpressions(
libraryBuilder,
createBodyBuilderContext(
inOutlineBuildingPhase: true,
inMetadata: true,
inConstFields: false),
classHierarchy,
typeParameterScope);
}
}
Iterator<SourceMemberBuilder> iterator = nameSpace.filteredIterator(
parent: this, includeDuplicates: false, includeAugmentations: true);
while (iterator.moveNext()) {
iterator.current
.buildOutlineExpressions(classHierarchy, delayedDefaultValueCloners);
}
}
void _buildMember(SourceMemberBuilder memberBuilder, Member member,
Member? tearOff, BuiltMemberKind memberKind,
{required bool addMembersToLibrary}) {
if (!memberBuilder.isAugmenting &&
!memberBuilder.isDuplicate &&
!memberBuilder.isConflictingSetter) {
if (memberKind == BuiltMemberKind.ExtensionTypeRepresentationField) {
addMemberInternal(memberBuilder, memberKind, member, tearOff);
} else {
if (addMembersToLibrary) {
Reference addMember(Member member) {
if (member is Field) {
libraryBuilder.library.addField(member);
return member.fieldReference;
} else if (member is Procedure) {
libraryBuilder.library.addProcedure(member);
return member.reference;
} else {
unhandled("${member.runtimeType}", "buildBuilders",
member.fileOffset, member.fileUri);
}
}
Reference memberReference = addMember(member);
Reference? tearOffReference;
if (tearOff != null) {
tearOffReference = addMember(tearOff);
}
addMemberDescriptorInternal(
memberBuilder, memberKind, memberReference, tearOffReference);
}
}
}
}
/// Adds [member] and [tearOff] to this declaration.
void addMemberInternal(SourceMemberBuilder memberBuilder,
BuiltMemberKind memberKind, Member member, Member? tearOff);
/// Adds a descriptor for [member] to this declaration.
void addMemberDescriptorInternal(
SourceMemberBuilder memberBuilder,
BuiltMemberKind memberKind,
Reference memberReference,
Reference? tearOffReference);
/// Type parameters declared.
///
/// This is `null` if the declaration is not generic.
List<NominalVariableBuilder>? get typeParameters;
/// The scope in which the [typeParameters] are declared.
LookupScope get typeParameterScope;
@override
List<DartType> buildAliasedTypeArguments(LibraryBuilder library,
List<TypeBuilder>? arguments, ClassHierarchyBase? hierarchy) {
if (arguments == null && typeParameters == null) {
return <DartType>[];
}
if (arguments == null && typeParameters != null) {
List<DartType> result =
new List<DartType>.generate(typeParameters!.length, (int i) {
if (typeParameters![i].defaultType == null) {
throw 'here';
}
return typeParameters![i].defaultType!.buildAliased(
library, TypeUse.defaultTypeAsTypeArgument, hierarchy);
}, growable: true);
return result;
}
if (arguments != null && arguments.length != typeVariablesCount) {
// Coverage-ignore-block(suite): Not run.
assert(libraryBuilder.loader.assertProblemReportedElsewhere(
"SourceDeclarationBuilderMixin.buildAliasedTypeArguments: "
"the numbers of type parameters and type arguments don't match.",
expectedPhase: CompilationPhaseForProblemReporting.outline));
return unhandled(
templateTypeArgumentMismatch
.withArguments(typeVariablesCount)
.problemMessage,
"buildTypeArguments",
-1,
null);
}
assert(arguments!.length == typeVariablesCount);
List<DartType> result =
new List<DartType>.generate(arguments!.length, (int i) {
return arguments[i]
.buildAliased(library, TypeUse.typeArgument, hierarchy);
}, growable: true);
return result;
}
@override
int get typeVariablesCount => typeParameters?.length ?? 0;
}
mixin SourceTypedDeclarationBuilderMixin implements IDeclarationBuilder {
/// Checks for conflicts between constructors and static members declared
/// in this type declaration.
void checkConstructorStaticConflict() {
NameIterator<MemberBuilder> iterator =
nameSpace.filteredConstructorNameIterator(
includeDuplicates: false, includeAugmentations: true);
while (iterator.moveNext()) {
String name = iterator.name;
MemberBuilder constructor = iterator.current;
Builder? member = nameSpace.lookupLocalMember(name, setter: false);
if (member == null) continue;
if (!member.isStatic) continue;
// TODO(ahe): Revisit these messages. It seems like the last two should
// be `context` parameter to this message.
addProblem(templateConflictsWithMember.withArguments(name),
constructor.charOffset, noLength);
if (constructor.isFactory) {
addProblem(
templateConflictsWithFactory.withArguments("${this.name}.${name}"),
member.charOffset,
noLength);
} else {
addProblem(
templateConflictsWithConstructor
.withArguments("${this.name}.${name}"),
member.charOffset,
noLength);
}
}
nameSpace.forEachLocalSetter((String name, Builder setter) {
Builder? constructor = nameSpace.lookupConstructor(name);
if (constructor == null || !setter.isStatic) return;
// Coverage-ignore-block(suite): Not run.
addProblem(templateConflictsWithConstructor.withArguments(name),
setter.charOffset, noLength);
addProblem(templateConflictsWithSetter.withArguments(name),
constructor.charOffset, noLength);
});
}
}