blob: d0250bfa2351b2a197da2ab5e3df51077dada93f [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/core_types.dart';
import '../fasta_codes.dart'
show templateInternalProblemNotFoundIn, templateTypeArgumentMismatch;
import '../kernel/kernel_helper.dart';
import '../scope.dart';
import '../source/source_library_builder.dart';
import '../problems.dart';
import '../util/helpers.dart';
import 'builder.dart';
import 'declaration_builder.dart';
import 'library_builder.dart';
import 'member_builder.dart';
import 'metadata_builder.dart';
import 'nullability_builder.dart';
import 'type_builder.dart';
import 'type_variable_builder.dart';
abstract class ExtensionBuilder implements DeclarationBuilder {
/// Type parameters declared on the extension.
///
/// This is `null` if the extension is not generic.
List<TypeVariableBuilder>? get typeParameters;
/// The type of the on-clause of the extension declaration.
TypeBuilder get onType;
/// Return the [Extension] built by this builder.
Extension get extension;
void buildOutlineExpressions(
SourceLibraryBuilder library,
CoreTypes coreTypes,
List<DelayedActionPerformer> delayedActionPerformers,
List<SynthesizedFunctionNode> synthesizedFunctionNodes);
/// Looks up extension member by [name] taking privacy into account.
///
/// If [setter] is `true` the sought member is a setter or assignable field.
/// If [required] is `true` and no member is found an internal problem is
/// reported.
///
/// If the extension member is a duplicate, `null` is returned.
// TODO(johnniwinther): Support [AmbiguousBuilder] here and in instance
// member lookup to avoid reporting that the member doesn't exist when it is
// duplicate.
Builder? lookupLocalMemberByName(Name name,
{bool setter: false, bool required: false});
/// Calls [f] for each member declared in this extension.
void forEach(void f(String name, Builder builder));
}
abstract class ExtensionBuilderImpl extends DeclarationBuilderImpl
implements ExtensionBuilder {
ExtensionBuilderImpl(List<MetadataBuilder>? metadata, int modifiers,
String name, LibraryBuilder parent, int charOffset, Scope scope)
: super(metadata, modifiers, name, parent, charOffset, scope);
/// Lookup a static member of this declaration.
@override
Builder? findStaticBuilder(
String name, int charOffset, Uri fileUri, LibraryBuilder accessingLibrary,
{bool isSetter: false}) {
if (accessingLibrary.nameOriginBuilder.origin !=
library.nameOriginBuilder.origin &&
name.startsWith("_")) {
return null;
}
Builder? declaration = isSetter
? scope.lookupSetter(name, charOffset, fileUri, isInstanceScope: false)
: scope.lookup(name, charOffset, fileUri, isInstanceScope: false);
// TODO(johnniwinther): Handle patched extensions.
return declaration;
}
@override
DartType buildType(LibraryBuilder library,
NullabilityBuilder nullabilityBuilder, List<TypeBuilder>? arguments,
{bool? nonInstanceContext}) {
if (library is SourceLibraryBuilder &&
library.enableExtensionTypesInLibrary) {
return buildTypesWithBuiltArguments(
library,
nullabilityBuilder.build(library),
buildTypeArguments(library, arguments,
nonInstanceContext: nonInstanceContext));
} else {
throw new UnsupportedError("ExtensionBuilder.buildType is not supported"
"in library '${library.importUri}'.");
}
}
@override
DartType buildTypesWithBuiltArguments(LibraryBuilder library,
Nullability nullability, List<DartType> arguments) {
if (library is SourceLibraryBuilder &&
library.enableExtensionTypesInLibrary) {
return new ExtensionType(extension, nullability, arguments);
} else {
throw new UnsupportedError(
"ExtensionBuilder.buildTypesWithBuiltArguments "
"is not supported in library '${library.importUri}'.");
}
}
@override
int get typeVariablesCount => typeParameters?.length ?? 0;
List<DartType> buildTypeArguments(
LibraryBuilder library, List<TypeBuilder>? arguments,
{bool? nonInstanceContext}) {
if (arguments == null && typeParameters == null) {
return <DartType>[];
}
if (arguments == null && typeParameters != null) {
List<DartType> result =
new List<DartType>.generate(typeParameters!.length, (int i) {
return typeParameters![i].defaultType!.build(library);
}, growable: true);
if (library is SourceLibraryBuilder) {
library.inferredTypes.addAll(result);
}
return result;
}
if (arguments != null && arguments.length != typeVariablesCount) {
// That should be caught and reported as a compile-time error earlier.
return unhandled(
templateTypeArgumentMismatch
.withArguments(typeVariablesCount)
.message,
"buildTypeArguments",
-1,
null);
}
assert(arguments!.length == typeVariablesCount);
List<DartType> result =
new List<DartType>.generate(arguments!.length, (int i) {
return arguments[i].build(library);
}, growable: true);
return result;
}
@override
void forEach(void f(String name, Builder builder)) {
scope.forEach(f);
}
@override
bool get isExtension => true;
@override
InterfaceType? get thisType => null;
@override
Builder? lookupLocalMember(String name,
{bool setter: false, bool required: false}) {
// TODO(johnniwinther): Support patching on extensions.
Builder? builder = scope.lookupLocalMember(name, setter: setter);
if (required && builder == null) {
internalProblem(
templateInternalProblemNotFoundIn.withArguments(
name, fullNameForErrors),
-1,
null);
}
return builder;
}
@override
Builder? lookupLocalMemberByName(Name name,
{bool setter: false, bool required: false}) {
Builder? builder =
lookupLocalMember(name.text, setter: setter, required: required);
if (builder != null) {
if (name.isPrivate && library.library != name.library) {
builder = null;
} else if (builder.isDuplicate) {
// Duplicates are not visible in the instance scope.
builder = null;
} else if (builder is MemberBuilder && builder.isConflictingSetter) {
// Conflicting setters are not visible in the instance scope.
// TODO(johnniwinther): Should we return an [AmbiguousBuilder] here and
// above?
builder = null;
}
}
return builder;
}
@override
String get debugName => "ExtensionBuilder";
}