blob: 44e5a9a6916d65d69178bc0b3a318746899990db [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.
library fasta.formal_parameter_builder;
import '../parser.dart' show FormalParameterKind;
import '../parser/formal_parameter_kind.dart'
show
isMandatoryFormalParameterKind,
isOptionalNamedFormalParameterKind,
isOptionalPositionalFormalParameterKind;
import 'builder.dart'
show LibraryBuilder, MetadataBuilder, ModifierBuilder, TypeBuilder;
import 'package:kernel/ast.dart' show VariableDeclaration;
import '../constant_context.dart' show ConstantContext;
import '../modifier.dart' show finalMask, initializingFormalMask, requiredMask;
import '../scanner.dart' show Token;
import '../scope.dart' show Scope;
import '../source/source_library_builder.dart' show SourceLibraryBuilder;
import '../source/source_loader.dart' show SourceLoader;
import '../kernel/body_builder.dart' show BodyBuilder;
import '../kernel/kernel_builder.dart'
show
ClassBuilder,
Builder,
ConstructorBuilder,
FieldBuilder,
LibraryBuilder,
MetadataBuilder,
TypeBuilder;
import '../kernel/kernel_shadow_ast.dart' show VariableDeclarationImpl;
/// A builder for a formal parameter, i.e. a parameter on a method or
/// constructor.
class FormalParameterBuilder extends ModifierBuilder {
/// List of metadata builders for the metadata declared on this parameter.
final List<MetadataBuilder> metadata;
final int modifiers;
final TypeBuilder type;
final String name;
/// The kind of this parameter, i.e. if it's required, positional optional,
/// or named optional.
FormalParameterKind kind = FormalParameterKind.mandatory;
/// The variable declaration created for this formal parameter.
VariableDeclaration variable;
/// The first token of the default value, if any.
///
/// This is stored until outlines have been built through
/// [buildOutlineExpressions].
Token initializerToken;
FormalParameterBuilder(this.metadata, this.modifiers, this.type, this.name,
LibraryBuilder compilationUnit, int charOffset,
[Uri fileUri])
: super(compilationUnit, charOffset, fileUri);
String get debugName => "FormalParameterBuilder";
// TODO(johnniwinther): Cleanup `isRequired` semantics in face of required
// named parameters.
bool get isRequired => isMandatoryFormalParameterKind(kind);
bool get isNamedRequired => (modifiers & requiredMask) != 0;
bool get isPositional {
return isOptionalPositionalFormalParameterKind(kind) ||
isMandatoryFormalParameterKind(kind);
}
bool get isNamed => isOptionalNamedFormalParameterKind(kind);
bool get isOptional => !isRequired;
bool get isLocal => true;
@override
String get fullNameForErrors => name;
VariableDeclaration get target => variable;
VariableDeclaration build(
SourceLibraryBuilder library, int functionNestingLevel) {
if (variable == null) {
variable = new VariableDeclarationImpl(name, functionNestingLevel,
type: type?.build(library),
isFinal: isFinal,
isConst: isConst,
isFieldFormal: isInitializingFormal,
isCovariant: isCovariant,
isRequired: isNamedRequired)
..fileOffset = charOffset;
}
return variable;
}
FormalParameterBuilder clone(List<TypeBuilder> newTypes) {
// TODO(dmitryas): It's not clear how [metadata] is used currently, and
// how it should be cloned. Consider cloning it instead of reusing it.
return new FormalParameterBuilder(metadata, modifiers,
type?.clone(newTypes), name, parent, charOffset, fileUri)
..kind = kind;
}
FormalParameterBuilder forFormalParameterInitializerScope() {
assert(variable != null);
return !isInitializingFormal
? this
: (new FormalParameterBuilder(
metadata,
modifiers | finalMask | initializingFormalMask,
type,
name,
null,
charOffset,
fileUri)
..parent = parent
..variable = variable);
}
void finalizeInitializingFormal() {
Object cls = parent.parent;
if (cls is ClassBuilder) {
Builder fieldBuilder = cls.scope.lookup(name, charOffset, fileUri);
if (fieldBuilder is FieldBuilder) {
variable.type = fieldBuilder.field.type;
}
}
}
/// Builds the default value from this [initializerToken] if this is a
/// formal parameter on a const constructor or instance method.
void buildOutlineExpressions(LibraryBuilder library) {
// For modular compilation we need to include initializers for optional
// and named parameters of const constructors into the outline - to enable
// constant evaluation. Similarly we need to include initializers for
// optional and named parameters of instance methods because these might be
// needed to generated noSuchMethod forwarders.
bool isConstConstructorParameter = false;
if (parent is ConstructorBuilder) {
ConstructorBuilder constructorBuilder = parent;
isConstConstructorParameter = constructorBuilder.constructor.isConst;
}
if ((isConstConstructorParameter || parent.isClassInstanceMember) &&
initializerToken != null) {
final ClassBuilder classBuilder = parent.parent;
Scope scope = classBuilder.scope;
BodyBuilder bodyBuilder = library.loader
.createBodyBuilderForOutlineExpression(
library, classBuilder, this, scope, fileUri);
bodyBuilder.constantContext = ConstantContext.required;
variable.initializer = bodyBuilder.parseFieldInitializer(initializerToken)
..parent = variable;
bodyBuilder.typeInferrer?.inferParameterInitializer(
bodyBuilder, variable.initializer, variable.type);
if (library.loader is SourceLoader) {
SourceLoader loader = library.loader;
loader.transformPostInference(variable,
bodyBuilder.transformSetLiterals, bodyBuilder.transformCollections);
}
bodyBuilder.resolveRedirectingFactoryTargets();
}
initializerToken = null;
}
}