mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 03:17:55 +00:00
Add type inference for super method invocations.
I implemented the correct logic for both SuperMethodInvocation and DirectMethodInvocation, since there are TODO comments in the code indicating that the former will be replaced by the latter when possible. R=scheglov@google.com Review-Url: https://codereview.chromium.org/2954403002 .
This commit is contained in:
parent
2e55f22810
commit
e24eab66d9
|
@ -897,13 +897,15 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
|||
if (!target.isAccessor) {
|
||||
if (areArgumentsCompatible(target.function, node.arguments)) {
|
||||
Expression result = new KernelDirectMethodInvocation(
|
||||
new ThisExpression()..fileOffset = node.fileOffset,
|
||||
new KernelThisExpression()..fileOffset = node.fileOffset,
|
||||
target,
|
||||
node.arguments);
|
||||
node.arguments)
|
||||
..fileOffset = node.fileOffset;
|
||||
// TODO(ahe): Use [DirectMethodInvocation] when possible, that is,
|
||||
// remove the next line:
|
||||
result =
|
||||
new KernelSuperMethodInvocation(node.name, node.arguments, null);
|
||||
new KernelSuperMethodInvocation(node.name, node.arguments, target)
|
||||
..fileOffset = node.fileOffset;
|
||||
return result;
|
||||
} else {
|
||||
isNoSuchMethod = true;
|
||||
|
@ -915,7 +917,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
|||
node.name.name, node.arguments, node.fileOffset);
|
||||
}
|
||||
Expression receiver = new KernelDirectPropertyGet(
|
||||
new ThisExpression()..fileOffset = node.fileOffset, target);
|
||||
new KernelThisExpression()..fileOffset = node.fileOffset, target);
|
||||
// TODO(ahe): Use [DirectPropertyGet] when possible, that is, remove the
|
||||
// next line:
|
||||
receiver = new KernelSuperPropertyGet(node.name, target);
|
||||
|
@ -992,7 +994,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
|||
noSuchMethodName,
|
||||
new Arguments(<Expression>[
|
||||
library.loader.instantiateInvocation(
|
||||
new ThisExpression()..fileOffset = charOffset,
|
||||
new KernelThisExpression()..fileOffset = charOffset,
|
||||
name,
|
||||
arguments,
|
||||
charOffset,
|
||||
|
|
|
@ -761,7 +761,8 @@ class SuperPropertyAccessor extends kernel.SuperPropertyAccessor
|
|||
isConstantExpression: true,
|
||||
isImplicitCall: true);
|
||||
} else {
|
||||
return new DirectMethodInvocation(new ThisExpression(), getter, arguments)
|
||||
return new DirectMethodInvocation(
|
||||
new KernelThisExpression(), getter, arguments)
|
||||
..fileOffset = offset;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -511,7 +511,7 @@ class ThisIndexAccessor extends Accessor {
|
|||
: super(helper, token);
|
||||
|
||||
Expression _makeSimpleRead() {
|
||||
return new KernelMethodInvocation(new ThisExpression(), indexGetName,
|
||||
return new KernelMethodInvocation(new KernelThisExpression(), indexGetName,
|
||||
new KernelArguments(<Expression>[index]),
|
||||
interfaceTarget: getter);
|
||||
}
|
||||
|
@ -519,8 +519,8 @@ class ThisIndexAccessor extends Accessor {
|
|||
Expression _makeSimpleWrite(Expression value, bool voidContext,
|
||||
KernelComplexAssignment complexAssignment) {
|
||||
if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
|
||||
var write = new KernelMethodInvocation(new ThisExpression(), indexSetName,
|
||||
new KernelArguments(<Expression>[index, value]),
|
||||
var write = new KernelMethodInvocation(new KernelThisExpression(),
|
||||
indexSetName, new KernelArguments(<Expression>[index, value]),
|
||||
interfaceTarget: setter)
|
||||
..fileOffset = offsetForToken(token);
|
||||
complexAssignment?.write = write;
|
||||
|
@ -533,8 +533,8 @@ class ThisIndexAccessor extends Accessor {
|
|||
}
|
||||
|
||||
Expression _makeRead(KernelComplexAssignment complexAssignment) {
|
||||
var read = new KernelMethodInvocation(new ThisExpression(), indexGetName,
|
||||
new KernelArguments(<Expression>[indexAccess()]),
|
||||
var read = new KernelMethodInvocation(new KernelThisExpression(),
|
||||
indexGetName, new KernelArguments(<Expression>[indexAccess()]),
|
||||
interfaceTarget: getter)
|
||||
..fileOffset = offsetForToken(token);
|
||||
complexAssignment?.read = read;
|
||||
|
@ -544,8 +544,8 @@ class ThisIndexAccessor extends Accessor {
|
|||
Expression _makeWrite(Expression value, bool voidContext,
|
||||
KernelComplexAssignment complexAssignment) {
|
||||
if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
|
||||
var write = new KernelMethodInvocation(new ThisExpression(), indexSetName,
|
||||
new KernelArguments(<Expression>[indexAccess(), value]),
|
||||
var write = new KernelMethodInvocation(new KernelThisExpression(),
|
||||
indexSetName, new KernelArguments(<Expression>[indexAccess(), value]),
|
||||
interfaceTarget: setter)
|
||||
..fileOffset = offsetForToken(token);
|
||||
complexAssignment?.write = write;
|
||||
|
@ -556,7 +556,7 @@ class ThisIndexAccessor extends Accessor {
|
|||
Expression value, KernelComplexAssignment complexAssignment) {
|
||||
var valueVariable = new VariableDeclaration.forValue(value);
|
||||
var write = new KernelMethodInvocation(
|
||||
new ThisExpression(),
|
||||
new KernelThisExpression(),
|
||||
indexSetName,
|
||||
new KernelArguments(
|
||||
<Expression>[indexAccess(), new VariableGet(valueVariable)]),
|
||||
|
|
|
@ -530,21 +530,23 @@ class KernelDirectMethodInvocation extends DirectMethodInvocation
|
|||
Expression receiver, Procedure target, Arguments arguments)
|
||||
: super(receiver, target, arguments);
|
||||
|
||||
KernelDirectMethodInvocation.byReference(
|
||||
Expression receiver, Reference targetReference, Arguments arguments)
|
||||
: super.byReference(receiver, targetReference, arguments);
|
||||
|
||||
@override
|
||||
void _collectDependencies(KernelDependencyCollector collector) {
|
||||
// TODO(paulberry): Determine the right thing to do here.
|
||||
throw 'TODO(paulberry)';
|
||||
// DirectMethodInvocation can only occur as a result of a use of `super`,
|
||||
// and `super` can't appear inside a field initializer. So this code should
|
||||
// never be reached.
|
||||
internalError(
|
||||
'Unexpected call to _collectDependencies for DirectMethodInvocation');
|
||||
}
|
||||
|
||||
@override
|
||||
DartType _inferExpression(
|
||||
KernelTypeInferrer inferrer, DartType typeContext, bool typeNeeded) {
|
||||
// TODO(scheglov): implement.
|
||||
return typeNeeded ? const DynamicType() : null;
|
||||
inferrer.instrumentation?.record(Uri.parse(inferrer.uri), fileOffset,
|
||||
'target', new InstrumentationValueForMember(target));
|
||||
return inferrer.inferMethodInvocation(
|
||||
this, receiver, fileOffset, false, typeContext, typeNeeded,
|
||||
interfaceMember: target, methodName: target.name, arguments: arguments);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1286,8 +1288,9 @@ class KernelMethodInvocation extends MethodInvocation
|
|||
@override
|
||||
DartType _inferExpression(
|
||||
KernelTypeInferrer inferrer, DartType typeContext, bool typeNeeded) {
|
||||
return inferrer.inferMethodInvocation(this, receiver, fileOffset, this,
|
||||
_isImplicitCall, typeContext, typeNeeded);
|
||||
return inferrer.inferMethodInvocation(
|
||||
this, receiver, fileOffset, _isImplicitCall, typeContext, typeNeeded,
|
||||
desugaredInvocation: this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1341,11 +1344,11 @@ class KernelNullAwareMethodInvocation extends Let implements KernelExpression {
|
|||
this,
|
||||
variable.initializer,
|
||||
fileOffset,
|
||||
_desugaredInvocation,
|
||||
false,
|
||||
typeContext,
|
||||
typeNeeded || inferrer.strongMode,
|
||||
receiverVariable: variable);
|
||||
receiverVariable: variable,
|
||||
desugaredInvocation: _desugaredInvocation);
|
||||
if (inferrer.strongMode) {
|
||||
body.staticType = inferredType;
|
||||
}
|
||||
|
@ -1807,8 +1810,13 @@ class KernelSuperMethodInvocation extends SuperMethodInvocation
|
|||
@override
|
||||
DartType _inferExpression(
|
||||
KernelTypeInferrer inferrer, DartType typeContext, bool typeNeeded) {
|
||||
// TODO(scheglov): implement.
|
||||
return typeNeeded ? const DynamicType() : null;
|
||||
inferrer.instrumentation?.record(Uri.parse(inferrer.uri), fileOffset,
|
||||
'target', new InstrumentationValueForMember(interfaceTarget));
|
||||
return inferrer.inferMethodInvocation(this, new KernelThisExpression(),
|
||||
fileOffset, false, typeContext, typeNeeded,
|
||||
interfaceMember: interfaceTarget,
|
||||
methodName: name,
|
||||
arguments: arguments);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -780,11 +780,14 @@ abstract class TypeInferrerImpl extends TypeInferrer {
|
|||
Expression expression,
|
||||
Expression receiver,
|
||||
int fileOffset,
|
||||
MethodInvocation desugaredInvocation,
|
||||
bool isImplicitCall,
|
||||
DartType typeContext,
|
||||
bool typeNeeded,
|
||||
{VariableDeclaration receiverVariable}) {
|
||||
{VariableDeclaration receiverVariable,
|
||||
MethodInvocation desugaredInvocation,
|
||||
Member interfaceMember,
|
||||
Name methodName,
|
||||
Arguments arguments}) {
|
||||
typeNeeded =
|
||||
listener.methodInvocationEnter(expression, typeContext) || typeNeeded;
|
||||
// First infer the receiver so we can look up the method that was invoked.
|
||||
|
@ -793,31 +796,32 @@ abstract class TypeInferrerImpl extends TypeInferrer {
|
|||
receiverVariable?.type = receiverType;
|
||||
}
|
||||
bool isOverloadedArithmeticOperator = false;
|
||||
Member interfaceMember =
|
||||
interfaceMember ??=
|
||||
findMethodInvocationMember(receiverType, desugaredInvocation);
|
||||
methodName ??= desugaredInvocation.name;
|
||||
arguments ??= desugaredInvocation.arguments;
|
||||
if (interfaceMember is Procedure) {
|
||||
isOverloadedArithmeticOperator = typeSchemaEnvironment
|
||||
.isOverloadedArithmeticOperatorAndType(interfaceMember, receiverType);
|
||||
}
|
||||
var calleeType = getCalleeFunctionType(interfaceMember, receiverType,
|
||||
desugaredInvocation.name, !isImplicitCall);
|
||||
var calleeType = getCalleeFunctionType(
|
||||
interfaceMember, receiverType, methodName, !isImplicitCall);
|
||||
bool forceArgumentInference = false;
|
||||
if (isDryRun) {
|
||||
if (_isUserDefinableOperator(desugaredInvocation.name.name)) {
|
||||
if (_isUserDefinableOperator(methodName.name)) {
|
||||
// If this is an overloadable arithmetic operator, then type inference
|
||||
// might depend on the RHS, so conservatively assume it does.
|
||||
forceArgumentInference =
|
||||
isOverloadableArithmeticOperator(desugaredInvocation.name.name);
|
||||
isOverloadableArithmeticOperator(methodName.name);
|
||||
} else {
|
||||
// If no type arguments were given, then type inference might depend on
|
||||
// the arguments (because the called method might be generic), so
|
||||
// conservatively assume it does.
|
||||
forceArgumentInference =
|
||||
getExplicitTypeArguments(desugaredInvocation.arguments) == null;
|
||||
forceArgumentInference = getExplicitTypeArguments(arguments) == null;
|
||||
}
|
||||
}
|
||||
var inferredType = inferInvocation(typeContext, typeNeeded, fileOffset,
|
||||
calleeType, calleeType.returnType, desugaredInvocation.arguments,
|
||||
calleeType, calleeType.returnType, arguments,
|
||||
isOverloadedArithmeticOperator: isOverloadedArithmeticOperator,
|
||||
receiverType: receiverType,
|
||||
forceArgumentInference: forceArgumentInference);
|
||||
|
|
|
@ -20,7 +20,7 @@ class B extends self::A {
|
|||
;
|
||||
method method() → dynamic {
|
||||
core::print("B.method x: ${this.x} y: ${this.y}");
|
||||
super.method();
|
||||
super.{self::A::method}();
|
||||
}
|
||||
}
|
||||
static method main() → dynamic {
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) 2017, 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.
|
||||
|
||||
/*@testedFeatures=inference*/
|
||||
library test;
|
||||
|
||||
class C {
|
||||
int f() => 0;
|
||||
}
|
||||
|
||||
class D extends C {
|
||||
void g() {
|
||||
var /*@type=int*/ x = super. /*@target=C::f*/ f();
|
||||
}
|
||||
}
|
||||
|
||||
main() {}
|
|
@ -0,0 +1,20 @@
|
|||
library test;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
class C extends core::Object {
|
||||
constructor •() → void
|
||||
: super core::Object::•()
|
||||
;
|
||||
method f() → core::int
|
||||
return 0;
|
||||
}
|
||||
class D extends self::C {
|
||||
constructor •() → void
|
||||
: super self::C::•()
|
||||
;
|
||||
method g() → void {
|
||||
dynamic x = super.f();
|
||||
}
|
||||
}
|
||||
static method main() → dynamic {}
|
|
@ -0,0 +1,20 @@
|
|||
library test;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
class C extends core::Object {
|
||||
constructor •() → void
|
||||
: super core::Object::•()
|
||||
;
|
||||
method f() → core::int
|
||||
return 0;
|
||||
}
|
||||
class D extends self::C {
|
||||
constructor •() → void
|
||||
: super self::C::•()
|
||||
;
|
||||
method g() → void {
|
||||
dynamic x = super.{self::C::f}();
|
||||
}
|
||||
}
|
||||
static method main() → dynamic {}
|
|
@ -0,0 +1,18 @@
|
|||
library test;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
class C extends core::Object {
|
||||
constructor •() → void
|
||||
;
|
||||
method f() → core::int
|
||||
;
|
||||
}
|
||||
class D extends self::C {
|
||||
constructor •() → void
|
||||
;
|
||||
method g() → void
|
||||
;
|
||||
}
|
||||
static method main() → dynamic
|
||||
;
|
|
@ -0,0 +1,20 @@
|
|||
library test;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
class C extends core::Object {
|
||||
constructor •() → void
|
||||
: super core::Object::•()
|
||||
;
|
||||
method f() → core::int
|
||||
return 0;
|
||||
}
|
||||
class D extends self::C {
|
||||
constructor •() → void
|
||||
: super self::C::•()
|
||||
;
|
||||
method g() → void {
|
||||
core::int x = super.{self::C::f}();
|
||||
}
|
||||
}
|
||||
static method main() → dynamic {}
|
|
@ -360,6 +360,7 @@ inference/simple_literal_null: Crash
|
|||
inference/static_method_tear_off: Crash
|
||||
inference/string_literal: Crash
|
||||
inference/subexpressions_of_explicitly_typed_fields: Crash
|
||||
inference/super_method_invocation: RuntimeError
|
||||
inference/this_reference: Crash
|
||||
inference/top_level_return_and_yield: Crash
|
||||
inference/toplevel_inference_toplevel_var: Crash
|
||||
|
|
|
@ -9,7 +9,7 @@ class C extends core::Object {
|
|||
operator ==(dynamic other) → dynamic
|
||||
return throw "x";
|
||||
method test() → dynamic {
|
||||
super.==(null);
|
||||
super.{core::Object::==}(null);
|
||||
}
|
||||
}
|
||||
static method main() → dynamic {
|
||||
|
|
|
@ -17,7 +17,7 @@ class Foo extends self::Object&Mixin {
|
|||
: super core::Object::•()
|
||||
;
|
||||
method foo() → dynamic
|
||||
return super.foo();
|
||||
return super.{self::Mixin::foo}();
|
||||
method bar() → dynamic
|
||||
return super.{self::Mixin::field};
|
||||
}
|
||||
|
|
|
@ -45,14 +45,14 @@ class C extends self::B {
|
|||
: super self::B::•()
|
||||
;
|
||||
method test() → dynamic {
|
||||
super.~();
|
||||
self::use(super.~());
|
||||
super.unary-();
|
||||
self::use(super.unary-());
|
||||
super.==(87);
|
||||
self::use(super.==(87));
|
||||
!super.==(87);
|
||||
self::use(!super.==(87));
|
||||
super.{self::A::~}();
|
||||
self::use(super.{self::A::~}());
|
||||
super.{self::A::unary-}();
|
||||
self::use(super.{self::A::unary-}());
|
||||
super.{self::A::==}(87);
|
||||
self::use(super.{self::A::==}(87));
|
||||
!super.{self::A::==}(87);
|
||||
self::use(!super.{self::A::==}(87));
|
||||
super.{self::A::a};
|
||||
self::use(super.{self::A::a});
|
||||
super.{self::B::b};
|
||||
|
@ -139,10 +139,10 @@ class C extends self::B {
|
|||
self::use(super.{self::A::i}.call());
|
||||
super.{self::A::[]}(87).call();
|
||||
self::use(super.{self::A::[]}(87).call());
|
||||
super.m();
|
||||
self::use(super.m());
|
||||
super.m(87);
|
||||
self::use(super.m(87));
|
||||
super.{self::A::m}();
|
||||
self::use(super.{self::A::m}());
|
||||
super.{self::A::m}(87);
|
||||
self::use(super.{self::A::m}(87));
|
||||
super.a = 42;
|
||||
self::use(super.a = 42);
|
||||
super.b = 42;
|
||||
|
|
Loading…
Reference in a new issue