Introduce ParameterStructure

This is a substructure of FunctionType and FunctionSignature which
doesn't contain type information. This allows us to let FunctionEntity
have a ParameterStructure (which makes sense for both K and J elements)
but not require FunctionEntity to have a type (which K elements have
but J elements might not).

R=efortuna@google.com

Review-Url: https://codereview.chromium.org/2809603002 .
This commit is contained in:
Johnni Winther 2017-04-11 10:19:09 +02:00
parent 4d3c3b9305
commit 21a3455bd6
17 changed files with 126 additions and 32 deletions

View file

@ -867,7 +867,7 @@ class CompileTimeConstantEvaluator extends Visitor<AstConstant> {
target.computeType(resolution);
if (!callStructure.signatureApplies(target.type)) {
if (!callStructure.signatureApplies(target.parameterStructure)) {
String name = Elements.constructorNameForDiagnostics(
target.enclosingClass.name, target.name);
reporter.reportErrorMessage(node,
@ -1114,7 +1114,7 @@ class CompileTimeConstantEvaluator extends Visitor<AstConstant> {
}
assert(invariant(
node,
callStructure.signatureApplies(constructor.type) ||
callStructure.signatureApplies(constructor.parameterStructure) ||
compiler.compilationFailed,
message: "Call structure $callStructure does not apply to constructor "
"$constructor."));

View file

@ -9,6 +9,7 @@ library elements.common;
import '../common/names.dart' show Identifiers, Names, Uris;
import '../common_elements.dart' show CommonElements;
import '../util/util.dart' show Link;
import 'entities.dart';
import 'elements.dart';
import 'resolution_types.dart'
show ResolutionDartType, ResolutionInterfaceType, ResolutionFunctionType;
@ -498,6 +499,8 @@ abstract class ClassElementCommon implements ClassElement {
}
abstract class FunctionSignatureCommon implements FunctionSignature {
ParameterStructure _parameterStructure;
ResolutionDartType get returnType => type.returnType;
void forEachRequiredParameter(void function(Element parameter)) {
@ -555,6 +558,24 @@ abstract class FunctionSignatureCommon implements FunctionSignature {
}
return true;
}
ParameterStructure get parameterStructure {
if (_parameterStructure == null) {
int requiredParameters = requiredParameterCount;
int positionalParameters;
List<String> namedParameters;
if (optionalParametersAreNamed) {
namedParameters = type.namedParameters;
positionalParameters = requiredParameters;
} else {
namedParameters = const <String>[];
positionalParameters = requiredParameters + optionalParameterCount;
}
_parameterStructure = new ParameterStructure(
requiredParameters, positionalParameters, namedParameters);
}
return _parameterStructure;
}
}
abstract class MixinApplicationElementCommon

View file

@ -927,7 +927,7 @@ class Elements {
// TODO(ngeoffray): Should the resolver do it instead?
CallStructure callStructure = new CallStructure(
signature.parameterCount, signature.type.namedParameters);
if (!callStructure.signatureApplies(signature.type)) {
if (!callStructure.signatureApplies(signature.parameterStructure)) {
return false;
}
list.addAll(makeArgumentsList<T>(callStructure, nodes, callee,
@ -1288,6 +1288,8 @@ abstract class FunctionSignature {
void orderedForEachParameter(void function(FormalElement parameter));
bool isCompatibleWith(FunctionSignature constructorSignature);
ParameterStructure get parameterStructure;
}
/// A top level, static or instance method, constructor, local function, or
@ -1317,6 +1319,9 @@ abstract class FunctionElement extends Element
/// `true` if this function is external.
bool get isExternal;
/// The structure of the function parameters.
ParameterStructure get parameterStructure;
}
/// A getter or setter.

View file

@ -119,6 +119,9 @@ abstract class FunctionEntity extends MemberEntity {
/// Whether this function is external, i.e. the body is not defined in terms
/// of Dart code.
bool get isExternal;
/// The structure of the function parameters.
ParameterStructure get parameterStructure;
}
/// Stripped down super interface for constructor like entities.
@ -158,3 +161,26 @@ abstract class Local extends Entity {
/// defined.
MemberEntity get memberContext;
}
/// The structure of function parameters.
class ParameterStructure {
/// The number of required (positional) parameters.
final int requiredParameters;
/// The number of positional parameters.
final int positionalParameters;
/// The named parameters sorted alphabetically.
final List<String> namedParameters;
const ParameterStructure(
this.requiredParameters, this.positionalParameters, this.namedParameters);
const ParameterStructure.getter() : this(0, 0, const <String>[]);
const ParameterStructure.setter() : this(1, 1, const <String>[]);
/// The number of optional parameters (positional or named).
int get optionalParameters =>
positionalParameters - requiredParameters + namedParameters.length;
}

View file

@ -26,6 +26,7 @@ import '../tree/tree.dart';
import '../util/util.dart';
import 'common.dart';
import 'elements.dart';
import 'entities.dart';
import 'resolution_types.dart';
import 'visitor.dart' show ElementVisitor;
@ -245,6 +246,7 @@ class ErroneousElementX extends ElementX
get type => unsupported();
get cachedNode => unsupported();
get functionSignature => unsupported();
get parameterStructure => unsupported();
get parameters => unsupported();
get patch => null;
get origin => this;
@ -433,6 +435,11 @@ class ErroneousConstructorElementX extends ErroneousElementX
throw new UnsupportedError("functionSignature=");
}
@override
get parameterStructure {
throw new UnsupportedError("parameterStructure");
}
@override
get nestedClosures {
throw new UnsupportedError("nestedClosures");
@ -2015,6 +2022,9 @@ abstract class BaseFunctionElementX extends ElementX
return isClassMember && !isConstructor && !isStatic;
}
ParameterStructure get parameterStructure =>
functionSignature.parameterStructure;
bool get hasFunctionSignature => _functionSignatureCache != null;
void _computeSignature(Resolution resolution) {

View file

@ -2324,7 +2324,8 @@ class ElementGraphBuilder extends ast.Visitor<TypeInformation>
// In erroneous code the number of arguments in the selector might not
// match the function element.
// TODO(polux): return nonNullEmpty and check it doesn'TypeInformation break anything
if (target.isMalformed || !callStructure.signatureApplies(target.type)) {
if (target.isMalformed ||
!callStructure.signatureApplies(target.parameterStructure)) {
return types.dynamicType;
}

View file

@ -53,7 +53,8 @@ class ClosureTracerVisitor extends TracerVisitor {
Selector selector = info.selector;
TypeMask mask = info.mask;
tracedElements.forEach((FunctionElement functionElement) {
if (!selector.callStructure.signatureApplies(functionElement.type)) {
if (!selector.callStructure
.signatureApplies(functionElement.parameterStructure)) {
return;
}
inferrer.updateParameterAssignments(

View file

@ -89,9 +89,11 @@ abstract class KMember implements MemberEntity {
}
abstract class KFunction extends KMember implements FunctionEntity {
final ParameterStructure parameterStructure;
final bool isExternal;
KFunction(int memberIndex, KLibrary library, KClass enclosingClass, Name name,
this.parameterStructure,
{bool isStatic: false, this.isExternal: false})
: super(memberIndex, library, enclosingClass, name, isStatic: isStatic);
}
@ -100,8 +102,9 @@ abstract class KConstructor extends KFunction implements ConstructorEntity {
final bool isConst;
KConstructor(int memberIndex, KClass enclosingClass, Name name,
{bool isExternal, this.isConst})
ParameterStructure parameterStructure, {bool isExternal, this.isConst})
: super(memberIndex, enclosingClass.library, enclosingClass, name,
parameterStructure,
isExternal: isExternal);
@override
@ -121,8 +124,8 @@ abstract class KConstructor extends KFunction implements ConstructorEntity {
class KGenerativeConstructor extends KConstructor {
KGenerativeConstructor(int constructorIndex, KClass enclosingClass, Name name,
{bool isExternal, bool isConst})
: super(constructorIndex, enclosingClass, name,
ParameterStructure parameterStructure, {bool isExternal, bool isConst})
: super(constructorIndex, enclosingClass, name, parameterStructure,
isExternal: isExternal, isConst: isConst);
@override
@ -134,8 +137,8 @@ class KGenerativeConstructor extends KConstructor {
class KFactoryConstructor extends KConstructor {
KFactoryConstructor(int memberIndex, KClass enclosingClass, Name name,
{bool isExternal, bool isConst})
: super(memberIndex, enclosingClass, name,
ParameterStructure parameterStructure, {bool isExternal, bool isConst})
: super(memberIndex, enclosingClass, name, parameterStructure,
isExternal: isExternal, isConst: isConst);
@override
@ -149,8 +152,9 @@ class KMethod extends KFunction {
final bool isAbstract;
KMethod(int memberIndex, KLibrary library, KClass enclosingClass, Name name,
ParameterStructure parameterStructure,
{bool isStatic, bool isExternal, this.isAbstract})
: super(memberIndex, library, enclosingClass, name,
: super(memberIndex, library, enclosingClass, name, parameterStructure,
isStatic: isStatic, isExternal: isExternal);
@override
@ -165,6 +169,7 @@ class KGetter extends KFunction {
KGetter(int memberIndex, KLibrary library, KClass enclosingClass, Name name,
{bool isStatic, bool isExternal, this.isAbstract})
: super(memberIndex, library, enclosingClass, name,
const ParameterStructure.getter(),
isStatic: isStatic, isExternal: isExternal);
@override
@ -179,6 +184,7 @@ class KSetter extends KFunction {
KSetter(int memberIndex, KLibrary library, KClass enclosingClass, Name name,
{bool isStatic, bool isExternal, this.isAbstract})
: super(memberIndex, library, enclosingClass, name,
const ParameterStructure.setter(),
isStatic: isStatic, isExternal: isExternal);
@override

View file

@ -193,6 +193,16 @@ class KernelWorldBuilder extends KernelElementAdapterMixin {
});
}
ParameterStructure _getParameterStructure(ir.FunctionNode node) {
// TODO(johnniwinther): Cache the computed function type.
int requiredParameters = node.requiredParameterCount;
int positionalParameters = node.positionalParameters.length;
List<String> namedParameters =
node.namedParameters.map((p) => p.name).toList()..sort();
return new ParameterStructure(
requiredParameters, positionalParameters, namedParameters);
}
KConstructor _getConstructor(ir.Member node) {
return _constructorMap.putIfAbsent(node, () {
int memberIndex = _memberList.length;
@ -200,12 +210,14 @@ class KernelWorldBuilder extends KernelElementAdapterMixin {
KClass enclosingClass = _getClass(node.enclosingClass);
Name name = getName(node.name);
bool isExternal = node.isExternal;
if (node is ir.Constructor) {
constructor = new KGenerativeConstructor(
memberIndex, enclosingClass, name,
constructor = new KGenerativeConstructor(memberIndex, enclosingClass,
name, _getParameterStructure(node.function),
isExternal: isExternal, isConst: node.isConst);
} else if (node is ir.Procedure) {
constructor = new KFactoryConstructor(memberIndex, enclosingClass, name,
_getParameterStructure(node.function),
isExternal: isExternal, isConst: node.isConst);
} else {
// TODO(johnniwinther): Convert `node.location` to a [SourceSpan].
@ -245,6 +257,7 @@ class KernelWorldBuilder extends KernelElementAdapterMixin {
case ir.ProcedureKind.Method:
case ir.ProcedureKind.Operator:
function = new KMethod(memberIndex, library, enclosingClass, name,
_getParameterStructure(node.function),
isStatic: isStatic,
isExternal: isExternal,
isAbstract: isAbstract);

View file

@ -202,7 +202,8 @@ class ClassResolverVisitor extends TypeDefinitionVisitor {
} else {
ConstructorElement superConstructor = superMember;
superConstructor.computeType(resolution);
if (!CallStructure.NO_ARGS.signatureApplies(superConstructor.type)) {
if (!CallStructure.NO_ARGS
.signatureApplies(superConstructor.parameterStructure)) {
MessageKind kind = MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT;
reporter.reportErrorMessage(node, kind);
superMember = new ErroneousElementX(kind, {}, '', element);

View file

@ -275,7 +275,8 @@ class InitializerResolver {
reportAndCreateErroneousConstructor(node, constructorName, kind, {});
} else {
lookedupConstructor.computeType(visitor.resolution);
if (!callStructure.signatureApplies(lookedupConstructor.type)) {
if (!callStructure
.signatureApplies(lookedupConstructor.parameterStructure)) {
MessageKind kind = isImplicitSuperCall
? MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT
: MessageKind.NO_MATCHING_CONSTRUCTOR;

View file

@ -1569,7 +1569,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
case AccessKind.SUPER_METHOD:
MethodElement superMethod = semantics.element;
superMethod.computeType(resolution);
if (!callStructure.signatureApplies(superMethod.type)) {
if (!callStructure.signatureApplies(superMethod.parameterStructure)) {
registry.registerFeature(Feature.THROW_NO_SUCH_METHOD);
registry.registerDynamicUse(new DynamicUse(selector, null));
registry.registerFeature(Feature.SUPER_NO_SUCH_METHOD);
@ -2503,7 +2503,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
case AccessKind.LOCAL_FUNCTION:
LocalFunctionElementX function = semantics.element;
function.computeType(resolution);
if (!callStructure.signatureApplies(function.type)) {
if (!callStructure.signatureApplies(function.parameterStructure)) {
registry.registerFeature(Feature.THROW_NO_SUCH_METHOD);
registry.registerDynamicUse(new DynamicUse(selector, null));
isIncompatibleInvoke = true;
@ -2672,7 +2672,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
case AccessKind.TOPLEVEL_METHOD:
MethodElement method = semantics.element;
method.computeType(resolution);
if (!callStructure.signatureApplies(method.type)) {
if (!callStructure.signatureApplies(method.parameterStructure)) {
registry.registerFeature(Feature.THROW_NO_SUCH_METHOD);
registry.registerDynamicUse(new DynamicUse(selector, null));
isIncompatibleInvoke = true;
@ -3859,7 +3859,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
case ConstructorResultKind.GENERATIVE:
// Ensure that the signature of [constructor] has been computed.
constructor.computeType(resolution);
if (!callStructure.signatureApplies(constructor.type)) {
if (!callStructure.signatureApplies(constructor.parameterStructure)) {
isInvalid = true;
kind = ConstructorAccessKind.INCOMPATIBLE;
registry.registerFeature(Feature.THROW_NO_SUCH_METHOD);
@ -3870,7 +3870,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
case ConstructorResultKind.FACTORY:
// Ensure that the signature of [constructor] has been computed.
constructor.computeType(resolution);
if (!callStructure.signatureApplies(constructor.type)) {
if (!callStructure.signatureApplies(constructor.parameterStructure)) {
// The effective target might still be valid(!) so the is not an
// invalid case in itself. For instance
//

View file

@ -2116,7 +2116,8 @@ class NewInvokeStructure<R, A> extends NewStructure<R, A> {
ConstructorElement effectiveTarget = constructor.effectiveTarget;
ResolutionInterfaceType effectiveTargetType =
constructor.computeEffectiveTargetType(semantics.type);
if (callStructure.signatureApplies(effectiveTarget.type)) {
if (callStructure
.signatureApplies(effectiveTarget.parameterStructure)) {
return visitor.visitRedirectingFactoryConstructorInvoke(
node,
semantics.element,
@ -2136,7 +2137,7 @@ class NewInvokeStructure<R, A> extends NewStructure<R, A> {
arg);
}
}
if (callStructure.signatureApplies(constructor.type)) {
if (callStructure.signatureApplies(constructor.parameterStructure)) {
return visitor.visitFactoryConstructorInvoke(node, constructor,
semantics.type, node.send.argumentsNode, callStructure, arg);
}

View file

@ -16,6 +16,7 @@ import '../constants/expressions.dart';
import '../elements/resolution_types.dart';
import '../elements/common.dart';
import '../elements/elements.dart';
import '../elements/entities.dart';
import '../elements/modelx.dart' show FunctionSignatureX;
import '../elements/visitor.dart';
import '../io/source_file.dart';
@ -850,6 +851,9 @@ abstract class ParametersMixin
}
return _parameters;
}
ParameterStructure get parameterStructure =>
functionSignature.parameterStructure;
}
abstract class FunctionTypedElementMixin
@ -1472,6 +1476,11 @@ class ForwardingConstructorElementZ extends ElementZ
return definingConstructor.functionSignature;
}
@override
ParameterStructure get parameterStructure {
return functionSignature.parameterStructure;
}
@override
bool get hasFunctionSignature {
return _unsupported('hasFunctionSignature');

View file

@ -3374,7 +3374,8 @@ class SsaBuilder extends ast.Visitor
// calling [makeStaticArgumentList].
constructorImplementation = constructor.implementation;
if (constructorImplementation.isMalformed ||
!callStructure.signatureApplies(constructorImplementation.type)) {
!callStructure
.signatureApplies(constructorImplementation.parameterStructure)) {
generateWrongArgumentCountError(send, constructor, send.arguments);
return;
}

View file

@ -5,7 +5,7 @@
library dart2js.call_structure;
import '../common/names.dart' show Names;
import '../elements/types.dart' show FunctionType;
import '../elements/entities.dart' show ParameterStructure;
import '../util/util.dart';
import 'selector.dart' show Selector;
@ -74,15 +74,14 @@ class CallStructure {
return match(other);
}
bool signatureApplies(FunctionType type) {
int requiredParameterCount = type.parameterTypes.length;
int optionalParameterCount =
type.optionalParameterTypes.length + type.namedParameters.length;
bool signatureApplies(ParameterStructure parameters) {
int requiredParameterCount = parameters.requiredParameters;
int optionalParameterCount = parameters.optionalParameters;
int parameterCount = requiredParameterCount + optionalParameterCount;
if (argumentCount > parameterCount) return false;
if (positionalArgumentCount < requiredParameterCount) return false;
if (type.namedParameters.isEmpty) {
if (parameters.namedParameters.isEmpty) {
// We have already checked that the number of arguments are
// not greater than the number of parameters. Therefore the
// number of positional arguments are not greater than the
@ -95,7 +94,7 @@ class CallStructure {
if (namedArgumentCount > optionalParameterCount) return false;
int nameIndex = 0;
List<String> namedParameters = type.namedParameters;
List<String> namedParameters = parameters.namedParameters;
for (String name in getOrderedNamedArguments()) {
bool found = false;
// Note: we start at the existing index because arguments are sorted.

View file

@ -243,8 +243,7 @@ class Selector {
}
bool signatureApplies(MethodElement function) {
if (Elements.isUnresolved(function)) return false;
return callStructure.signatureApplies(function.type);
return callStructure.signatureApplies(function.parameterStructure);
}
bool applies(MemberElement element) {