mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 00:39:49 +00:00
Check that invocations have well-formed targets in kernel verifier.
This also fixes some issues in the frontend and transformers that generated calls without the correct number of type arguments. BUG= R=kmillikin@google.com Review URL: https://codereview.chromium.org/2533793005 .
This commit is contained in:
parent
ddc6af7556
commit
440813c67b
|
@ -1677,6 +1677,15 @@ class ExpressionBuilder
|
|||
return element;
|
||||
}
|
||||
|
||||
/// Forces the list of type arguments to have the specified length. If the
|
||||
/// length was changed, all type arguments are changed to `dynamic`.
|
||||
void _coerceTypeArgumentArity(List<ast.DartType> typeArguments, int arity) {
|
||||
if (typeArguments.length != arity) {
|
||||
typeArguments.length = arity;
|
||||
typeArguments.fillRange(0, arity, const ast.DynamicType());
|
||||
}
|
||||
}
|
||||
|
||||
ast.Expression visitInstanceCreationExpression(
|
||||
InstanceCreationExpression node) {
|
||||
ConstructorElement element = node.staticElement;
|
||||
|
@ -1729,6 +1738,8 @@ class ExpressionBuilder
|
|||
if (classElement.isEnum) {
|
||||
return scope.emitCompileTimeError(CompileTimeErrorCode.INSTANTIATE_ENUM);
|
||||
}
|
||||
_coerceTypeArgumentArity(
|
||||
arguments.types, classElement.typeParameters.length);
|
||||
if (element.isFactory) {
|
||||
ast.Member target = scope.resolveConcreteMethod(element);
|
||||
if (target is ast.Procedure &&
|
||||
|
|
|
@ -528,7 +528,8 @@ abstract class AsyncRewriterBase extends ContinuationRewriterBase {
|
|||
var iteratorVariable = new VariableDeclaration(':for-iterator',
|
||||
initializer: new ConstructorInvocation(
|
||||
helper.streamIteratorConstructor,
|
||||
new Arguments(<Expression>[stmt.iterable])));
|
||||
new Arguments(<Expression>[stmt.iterable],
|
||||
types: [const DynamicType()])));
|
||||
|
||||
// await iterator.moveNext()
|
||||
var condition = new AwaitExpression(new MethodInvocation(
|
||||
|
@ -733,8 +734,8 @@ class AsyncFunctionRewriter extends AsyncRewriterBase {
|
|||
|
||||
// var :completer = new Completer.sync();
|
||||
completerVariable = new VariableDeclaration(":completer",
|
||||
initializer: new StaticInvocation(
|
||||
helper.completerConstructor, new Arguments([])),
|
||||
initializer: new StaticInvocation(helper.completerConstructor,
|
||||
new Arguments([], types: [const DynamicType()])),
|
||||
isFinal: true);
|
||||
statements.add(completerVariable);
|
||||
|
||||
|
@ -746,7 +747,8 @@ class AsyncFunctionRewriter extends AsyncRewriterBase {
|
|||
// new Future.microtask(:async_op);
|
||||
var newMicrotaskStatement = new ExpressionStatement(new StaticInvocation(
|
||||
helper.futureMicrotaskConstructor,
|
||||
new Arguments([new VariableGet(nestedClosureVariable)])));
|
||||
new Arguments([new VariableGet(nestedClosureVariable)],
|
||||
types: [const DynamicType()])));
|
||||
statements.add(newMicrotaskStatement);
|
||||
|
||||
// return :completer.future;
|
||||
|
|
|
@ -311,7 +311,8 @@ class SuperCallResolutionTransformer extends Transformer {
|
|||
return new StaticInvocation(
|
||||
_listFrom,
|
||||
new Arguments([new ListLiteral(list)],
|
||||
named: [new NamedExpression("growable", new BoolLiteral(false))]));
|
||||
named: [new NamedExpression("growable", new BoolLiteral(false))],
|
||||
types: [const DynamicType()]));
|
||||
}
|
||||
|
||||
/// Check that a call to the targetFunction is legal given the arguments.
|
||||
|
|
|
@ -245,6 +245,147 @@ class VerifyingVisitor extends RecursiveVisitor {
|
|||
visitChildren(node);
|
||||
}
|
||||
|
||||
@override
|
||||
visitStaticGet(StaticGet node) {
|
||||
visitChildren(node);
|
||||
if (node.target == null) {
|
||||
throw 'StaticGet without target found in $context.';
|
||||
}
|
||||
if (!node.target.hasGetter) {
|
||||
throw 'StaticGet to ${node.target} without getter found in $context';
|
||||
}
|
||||
if (node.target.isInstanceMember) {
|
||||
throw 'StaticGet to ${node.target} that is not static found in $context';
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
visitStaticSet(StaticSet node) {
|
||||
visitChildren(node);
|
||||
if (node.target == null) {
|
||||
throw 'StaticSet without target found in $context.';
|
||||
}
|
||||
if (!node.target.hasSetter) {
|
||||
throw 'StaticSet to ${node.target} without setter found in $context';
|
||||
}
|
||||
if (node.target.isInstanceMember) {
|
||||
throw 'StaticSet to ${node.target} that is not static found in $context';
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
visitStaticInvocation(StaticInvocation node) {
|
||||
visitChildren(node);
|
||||
if (node.target == null) {
|
||||
throw 'StaticInvocation without target found in $context.';
|
||||
}
|
||||
if (node.target.isInstanceMember) {
|
||||
throw 'StaticInvocation to ${node.target} that is not static found in '
|
||||
'$context';
|
||||
}
|
||||
if (!areArgumentsCompatible(node.arguments, node.target.function)) {
|
||||
throw 'StaticInvocation with incompatible arguments to '
|
||||
'${node.target} found in $context';
|
||||
}
|
||||
if (node.arguments.types.length !=
|
||||
node.target.function.typeParameters.length) {
|
||||
throw 'Wrong number of type arguments provided in StaticInvocation '
|
||||
'to ${node.target} found in $context';
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
visitDirectPropertyGet(DirectPropertyGet node) {
|
||||
visitChildren(node);
|
||||
if (node.target == null) {
|
||||
throw 'DirectPropertyGet without target found in $context.';
|
||||
}
|
||||
if (!node.target.hasGetter) {
|
||||
throw 'DirectPropertyGet to ${node.target} without getter found in '
|
||||
'$context';
|
||||
}
|
||||
if (!node.target.isInstanceMember) {
|
||||
throw 'DirectPropertyGet to ${node.target} that is static found in '
|
||||
'$context';
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
visitDirectPropertySet(DirectPropertySet node) {
|
||||
visitChildren(node);
|
||||
if (node.target == null) {
|
||||
throw 'DirectPropertySet without target found in $context.';
|
||||
}
|
||||
if (!node.target.hasSetter) {
|
||||
throw 'DirectPropertyGet to ${node.target} without setter found in '
|
||||
'$context';
|
||||
}
|
||||
if (!node.target.isInstanceMember) {
|
||||
throw 'DirectPropertySet to ${node.target} that is static found in '
|
||||
'$context';
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
visitDirectMethodInvocation(DirectMethodInvocation node) {
|
||||
visitChildren(node);
|
||||
if (node.target == null) {
|
||||
throw 'DirectMethodInvocation without target found in $context.';
|
||||
}
|
||||
if (!node.target.isInstanceMember) {
|
||||
throw 'DirectMethodInvocation to ${node.target} that is static found in '
|
||||
'$context';
|
||||
}
|
||||
if (!areArgumentsCompatible(node.arguments, node.target.function)) {
|
||||
throw 'DirectMethodInvocation with incompatible arguments to '
|
||||
'${node.target} found in $context';
|
||||
}
|
||||
if (node.arguments.types.length !=
|
||||
node.target.function.typeParameters.length) {
|
||||
throw 'Wrong number of type arguments provided in DirectMethodInvocation '
|
||||
'to ${node.target} found in $context';
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
visitConstructorInvocation(ConstructorInvocation node) {
|
||||
visitChildren(node);
|
||||
if (node.target == null) {
|
||||
throw 'ConstructorInvocation without target found in $context.';
|
||||
}
|
||||
if (node.target.enclosingClass.isAbstract) {
|
||||
throw 'ConstructorInvocation to abstract class found in $context';
|
||||
}
|
||||
if (!areArgumentsCompatible(node.arguments, node.target.function)) {
|
||||
throw 'ConstructorInvocation with incompatible arguments to '
|
||||
'${node.target} found in $context';
|
||||
}
|
||||
if (node.arguments.types.length !=
|
||||
node.target.enclosingClass.typeParameters.length) {
|
||||
throw 'Wrong number of type arguments provided in ConstructorInvocation '
|
||||
'to ${node.target} found in $context';
|
||||
}
|
||||
}
|
||||
|
||||
bool areArgumentsCompatible(Arguments arguments, FunctionNode function) {
|
||||
if (arguments.positional.length < function.requiredParameterCount) {
|
||||
return false;
|
||||
}
|
||||
if (arguments.positional.length > function.positionalParameters.length) {
|
||||
return false;
|
||||
}
|
||||
namedLoop:
|
||||
for (int i = 0; i < arguments.named.length; ++i) {
|
||||
var argument = arguments.named[i];
|
||||
String name = argument.name;
|
||||
for (int j = 0; j < function.namedParameters.length; ++j) {
|
||||
if (function.namedParameters[j].name == name) continue namedLoop;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
defaultMemberReference(Member node) {
|
||||
if (node.transformerFlags & TransformerFlag.seenByVerifier == 0) {
|
||||
|
|
|
@ -125,6 +125,86 @@ main() {
|
|||
procedure.function = new FunctionNode(new EmptyStatement());
|
||||
return procedure;
|
||||
});
|
||||
negativeTest('StaticGet without target', () {
|
||||
return new StaticGet(null);
|
||||
});
|
||||
negativeTest('StaticSet without target', () {
|
||||
return new StaticSet(null, new NullLiteral());
|
||||
});
|
||||
negativeTest('StaticInvocation without target', () {
|
||||
return new StaticInvocation(null, new Arguments.empty());
|
||||
});
|
||||
positiveTest('Correct StaticInvocation', () {
|
||||
var method = new Procedure(new Name('test'), ProcedureKind.Method, null,
|
||||
isStatic: true);
|
||||
method.function = new FunctionNode(
|
||||
new ReturnStatement(
|
||||
new StaticInvocation(method, new Arguments([new NullLiteral()]))),
|
||||
positionalParameters: [new VariableDeclaration('p')])..parent = method;
|
||||
return new Class(
|
||||
name: 'Test',
|
||||
supertype: objectClass.asRawSupertype,
|
||||
procedures: [method]);
|
||||
});
|
||||
negativeTest('StaticInvocation with too many parameters', () {
|
||||
var method = new Procedure(new Name('test'), ProcedureKind.Method, null,
|
||||
isStatic: true);
|
||||
method.function = new FunctionNode(new ReturnStatement(
|
||||
new StaticInvocation(method, new Arguments([new NullLiteral()]))))
|
||||
..parent = method;
|
||||
return new Class(
|
||||
name: 'Test',
|
||||
supertype: objectClass.asRawSupertype,
|
||||
procedures: [method]);
|
||||
});
|
||||
negativeTest('StaticInvocation with too few parameters', () {
|
||||
var method = new Procedure(new Name('test'), ProcedureKind.Method, null,
|
||||
isStatic: true);
|
||||
method.function = new FunctionNode(
|
||||
new ReturnStatement(
|
||||
new StaticInvocation(method, new Arguments.empty())),
|
||||
positionalParameters: [new VariableDeclaration('p')])..parent = method;
|
||||
return new Class(
|
||||
name: 'Test',
|
||||
supertype: objectClass.asRawSupertype,
|
||||
procedures: [method]);
|
||||
});
|
||||
negativeTest('StaticInvocation with unmatched named parameter', () {
|
||||
var method = new Procedure(new Name('test'), ProcedureKind.Method, null,
|
||||
isStatic: true);
|
||||
method.function = new FunctionNode(new ReturnStatement(new StaticInvocation(
|
||||
method,
|
||||
new Arguments([],
|
||||
named: [new NamedExpression('p', new NullLiteral())]))))
|
||||
..parent = method;
|
||||
return new Class(
|
||||
name: 'Test',
|
||||
supertype: objectClass.asRawSupertype,
|
||||
procedures: [method]);
|
||||
});
|
||||
negativeTest('StaticInvocation with missing type argument', () {
|
||||
var method = new Procedure(new Name('test'), ProcedureKind.Method, null,
|
||||
isStatic: true);
|
||||
method.function = new FunctionNode(
|
||||
new ReturnStatement(
|
||||
new StaticInvocation(method, new Arguments.empty())),
|
||||
typeParameters: [makeTypeParameter()])..parent = method;
|
||||
return new Class(
|
||||
name: 'Test',
|
||||
supertype: objectClass.asRawSupertype,
|
||||
procedures: [method]);
|
||||
});
|
||||
negativeTest('ConstructorInvocation with missing type argument', () {
|
||||
var constructor = new Constructor(null);
|
||||
constructor.function = new FunctionNode(new ReturnStatement(
|
||||
new ConstructorInvocation(constructor, new Arguments.empty())))
|
||||
..parent = constructor;
|
||||
return new Class(
|
||||
name: 'Test',
|
||||
typeParameters: [makeTypeParameter()],
|
||||
supertype: objectClass.asRawSupertype,
|
||||
constructors: [constructor]);
|
||||
});
|
||||
}
|
||||
|
||||
checkHasError(Program program) {
|
||||
|
|
Loading…
Reference in a new issue