Implement type inference of static invocations.

R=scheglov@google.com

Review-Url: https://codereview.chromium.org/2885963002 .
This commit is contained in:
Paul Berry
2017-05-16 18:33:21 -07:00
parent 43cea08f6d
commit 72d3fbc85f
23 changed files with 248 additions and 29 deletions
@@ -554,8 +554,17 @@ class KernelStaticInvocation extends StaticInvocation
@override
DartType _inferExpression(
KernelTypeInferrer inferrer, DartType typeContext, bool typeNeeded) {
// TODO(scheglov): implement.
return typeNeeded ? const DynamicType() : null;
return inferrer.inferStaticInvocation(
typeContext,
typeNeeded,
fileOffset,
target,
name,
_getExplicitTypeArguments(arguments),
_forEachArgument(arguments), (types) {
arguments.types.clear();
arguments.types.addAll(types);
});
}
}
@@ -100,6 +100,12 @@ class TypeInferenceListener {
void staticGetExit(DartType inferredType) =>
debugExpressionExit("staticGet", inferredType);
bool staticInvocationEnter(DartType typeContext) =>
debugExpressionEnter("staticInvocation", typeContext);
void staticInvocationExit(DartType inferredType) =>
debugExpressionExit("staticInvocation", inferredType);
bool stringConcatenationEnter(DartType typeContext) =>
debugExpressionEnter("stringConcatenation", typeContext);
@@ -547,8 +547,6 @@ abstract class TypeInferrerImpl extends TypeInferrer {
typeNeeded = listener.methodInvocationEnter(typeContext) || typeNeeded;
// First infer the receiver so we can look up the method that was invoked.
var receiverType = inferExpression(receiver, null, true);
// TODO(paulberry): can we share some of the code below with
// inferConstructorInvocation?
bool isOverloadedArithmeticOperator = false;
Member interfaceMember;
if (receiverType is InterfaceType) {
@@ -618,6 +616,44 @@ abstract class TypeInferrerImpl extends TypeInferrer {
return inferredType;
}
/// Performs the core type inference algorithm for method invocations.
///
/// [typeContext], [typeNeeded], and the return value behave as described in
/// [inferExpression].
///
/// [offset] is the location of the method invocation in the source file.
/// [receiver] is the object whose method is being invoked, and [methodName]
/// is the name of the method. [explicitTypeArguments] is the set of type
/// arguments explicitly provided, or `null` if no type arguments were
/// provided. [forEachArgument] is a callback which can be used to iterate
/// through all invocation arguments (both named and positional).
/// [setInferredTypeArguments] is a callback which can be used to record the
/// inferred type arguments. [setInterfaceTarget] is a callback which can be
/// used to record the method being invoked.
DartType inferStaticInvocation(
DartType typeContext,
bool typeNeeded,
int offset,
Procedure target,
Name methodName,
List<DartType> explicitTypeArguments,
void forEachArgument(void callback(String name, Expression expression)),
void setInferredTypeArguments(List<DartType> types)) {
typeNeeded = listener.staticInvocationEnter(typeContext) || typeNeeded;
var calleeType = target.function.functionType;
var inferredType = _inferInvocation(
typeContext,
typeNeeded,
offset,
calleeType,
calleeType.returnType,
explicitTypeArguments,
forEachArgument,
setInferredTypeArguments);
listener.staticInvocationExit(inferredType);
return inferredType;
}
/// Performs the core type inference algorithm for string concatenations.
///
/// [typeContext], [typeNeeded], and the return value behave as described in
@@ -789,6 +825,11 @@ abstract class TypeInferrerImpl extends TypeInferrer {
calleeTypeParameters.length == explicitTypeArguments.length) {
substitution =
Substitution.fromPairs(calleeTypeParameters, explicitTypeArguments);
} else if (calleeTypeParameters.length != 0) {
substitution = Substitution.fromPairs(
calleeTypeParameters,
new List<DartType>.filled(
calleeTypeParameters.length, const DynamicType()));
}
int i = 0;
forEachArgument((name, expression) {
-13
View File
@@ -90,7 +90,6 @@ inference/downwards_inference_async_await: Fail
inference/downwards_inference_for_each: Fail
inference/downwards_inference_initializing_formal_default_formal: Fail
inference/downwards_inference_inside_top_level: Fail
inference/downwards_inference_on_function_arguments_infer_downwards: Fail
inference/downwards_inference_on_function_expressions: Fail
inference/downwards_inference_on_function_of_t_using_the_t: Fail
inference/downwards_inference_on_generic_function_expressions: Fail
@@ -127,14 +126,10 @@ inference/future_union_downwards_generic_method_with_future_return: Fail
inference/future_union_downwards_generic_method_with_generic_return: Fail
inference/future_union_upwards_generic_methods: Fail
inference/generic_functions_return_typedef: Fail
inference/generic_methods_basic_downward_inference: Fail
inference/generic_methods_dart_math_min_max: Fail
inference/generic_methods_downwards_inference_affects_arguments: Fail
inference/generic_methods_downwards_inference_fold: Fail
inference/generic_methods_infer_js_builtin: Fail
inference/generic_methods_iterable_and_future: Fail
inference/generic_methods_nested_generic_instantiation: Fail
inference/generic_methods_uses_greatest_lower_bound: Fail
inference/infer_assign_to_index: Fail
inference/infer_assign_to_property: Fail
inference/infer_assign_to_property_custom: Fail
@@ -164,14 +159,11 @@ inference/infer_typed_map_literal: Fail
inference/infer_types_on_generic_instantiations_in_library_cycle: Fail
inference/infer_types_on_loop_indices_for_each_loop: Fail
inference/infer_types_on_loop_indices_for_loop_with_inference: Fail
inference/infer_variable_void: Fail
inference/inferred_nonstatic_field_depends_on_static_field_complex: Fail
inference/inferred_type_block_closure_no_args_no_return: Fail
inference/inferred_type_cascade: Fail
inference/inferred_type_extract_method_tear_off: Fail
inference/inferred_type_extract_method_tear_off_via_interface: Fail
inference/inferred_type_invoke_method: Fail
inference/inferred_type_invoke_method_via_interface: Fail
inference/inferred_type_is_typedef: Fail
inference/inferred_type_is_typedef_parameterized: Fail
inference/inferred_type_uses_synthetic_function_type_named_param: Fail
@@ -185,7 +177,6 @@ inference/map_literals_can_infer_null: Fail
inference/map_literals_can_infer_null_top_level: Fail
inference/map_literals_top_level: Fail
inference/method_call_with_type_arguments_static_method: Fail
inference/method_call_with_type_arguments_top_level_function: Fail
inference/null_coalescing_operator: Fail
inference/null_coalescing_operator_2: Fail
inference/null_literal_should_not_infer_as_bottom: Fail
@@ -197,13 +188,9 @@ inference/refine_binary_expression_type_type_parameter_t_t: Fail
inference/type_promotion_stopped_by_access_in_a_closure: Fail
inference/type_promotion_stopped_by_mutation_in_a_closure: Fail
inference/unsafe_block_closure_inference_closure_call: Fail
inference/unsafe_block_closure_inference_function_call_explicit_dynamic_param: Fail
inference/unsafe_block_closure_inference_function_call_explicit_dynamic_param_via_expr1: Fail
inference/unsafe_block_closure_inference_function_call_explicit_type_param: Fail
inference/unsafe_block_closure_inference_function_call_explicit_type_param_via_expr1: Fail
inference/unsafe_block_closure_inference_function_call_implicit_type_param: Fail
inference/unsafe_block_closure_inference_function_call_implicit_type_param_via_expr: Fail
inference/unsafe_block_closure_inference_function_call_no_type_param: Fail
inference/unsafe_block_closure_inference_function_call_no_type_param_via_expr: Fail
inference/unsafe_block_closure_inference_in_map_dynamic: Fail
inference/unsafe_block_closure_inference_in_map_typed: Fail
@@ -0,0 +1,31 @@
library test;
import self as self;
import "dart:core" as core;
static method f0(core::List<core::int> a) → void {}
static method f1({core::List<core::int> a = null}) → void {}
static method f2(core::Iterable<core::int> a) → void {}
static method f3(core::Iterable<core::Iterable<core::int>> a) → void {}
static method f4({core::Iterable<core::Iterable<core::int>> a = null}) → void {}
static method main() → void {
self::f0(<core::int>[]);
self::f0(<core::int>[3]);
self::f0(<core::int>["hello"]);
self::f0(<core::int>["hello", 3]);
self::f1(a: <core::int>[]);
self::f1(a: <core::int>[3]);
self::f1(a: <core::int>["hello"]);
self::f1(a: <core::int>["hello", 3]);
self::f2(<core::int>[]);
self::f2(<core::int>[3]);
self::f2(<core::int>["hello"]);
self::f2(<core::int>["hello", 3]);
self::f3(<core::Iterable<core::int>>[]);
self::f3(<core::Iterable<core::int>>[<core::int>[3]]);
self::f3(<core::Iterable<core::int>>[<core::int>["hello"]]);
self::f3(<core::Iterable<core::int>>[<core::int>["hello"], <core::int>[3]]);
self::f4(a: <core::Iterable<core::int>>[]);
self::f4(a: <core::Iterable<core::int>>[<core::int>[3]]);
self::f4(a: <core::Iterable<core::int>>[<core::int>["hello"]]);
self::f4(a: <core::Iterable<core::int>>[<core::int>["hello"], <core::int>[3]]);
}
@@ -2,9 +2,9 @@ library test;
import self as self;
import "dart:core" as core;
static method f(dynamic s) → dynamic
static method f<S extends core::Object, T extends core::Object>(self::f::S s) → self::f::T
return null;
static method main() → dynamic {
core::String x = self::f(42);
core::String x = self::f<core::int, core::String>(42);
core::String y = self::f.call(42);
}
@@ -8,18 +8,18 @@ static method printInt(core::int x) → void
static method printDouble(core::double x) → void
return core::print(x);
static method myMax(core::num x, core::num y) → core::num
return math::max(x, y);
return math::max<core::num>(x, y);
static method f() → dynamic {
self::printInt(math::max(1, 2));
self::printInt(math::min(1, 2));
self::printDouble(math::max(1.0, 2.0));
self::printDouble(math::min(1.0, 2.0));
self::printInt(math::max<core::int>(1, 2));
self::printInt(math::min<core::int>(1, 2));
self::printDouble(math::max<core::double>(1.0, 2.0));
self::printDouble(math::min<core::double>(1.0, 2.0));
self::printInt(self::myMax(1, 2));
self::printInt(self::myMax(1, 2) as core::int);
self::printInt(math::max(1, 2.0));
self::printInt(math::min(1, 2.0));
self::printDouble(math::max(1, 2.0));
self::printDouble(math::min(1, 2.0));
self::printInt(math::min("hi", "there"));
self::printInt(math::max<core::int>(1, 2.0));
self::printInt(math::min<core::int>(1, 2.0));
self::printDouble(math::max<core::double>(1, 2.0));
self::printDouble(math::min<core::double>(1, 2.0));
self::printInt(math::min<core::int>("hi", "there"));
}
static method main() → dynamic {}
@@ -0,0 +1,10 @@
library test;
import self as self;
import "dart:core" as core;
static method f<T extends core::Object>(core::List<self::f::T> s) → self::f::T
return null;
static method main() → dynamic {
core::String x = self::f<core::String>(<core::String>["hi"]);
core::String y = self::f<core::String>(<core::String>[42]);
}
@@ -0,0 +1,11 @@
library test;
import self as self;
import "dart:core" as core;
typedef F = (core::int) → core::Iterable<core::num>;
typedef G = (core::double) → core::List<core::int>;
static method generic<T extends core::Object>((self::generic::T) → dynamic a, (self::generic::T) → dynamic b) → self::generic::T
return null;
static method main() → dynamic {
(core::num) → core::List<core::int> v = self::generic<(core::num) → core::List<core::int>>(((core::int) → core::Iterable<core::num> f) → dynamic => null, ((core::double) → core::List<core::int> g) → dynamic => null);
}
@@ -7,3 +7,7 @@ library test;
void f() {}
var /*@topType=void*/ x = /*info:USE_OF_VOID_RESULT*/ f();
main() {
x;
}
@@ -0,0 +1,8 @@
library test;
import self as self;
static field void x = self::f();
static method f() → void {}
static method main() → dynamic {
self::x;
}
@@ -11,3 +11,5 @@ class C {
C f() => null;
var /*@topType=bool*/ x = f(). /*@target=C::g*/ g();
main() {}
@@ -0,0 +1,15 @@
library test;
import self as self;
import "dart:core" as core;
class C extends core::Object {
constructor •() → void
: super core::Object::•()
;
method g() → core::bool
return true;
}
static field core::bool x = self::f().g();
static method f() → self::C
return null;
static method main() → dynamic {}
@@ -13,3 +13,5 @@ abstract class C implements I {}
C f() => null;
var /*@topType=bool*/ x = f(). /*@target=I::g*/ g();
main() {}
@@ -0,0 +1,20 @@
library test;
import self as self;
import "dart:core" as core;
class I extends core::Object {
constructor •() → void
: super core::Object::•()
;
method g() → core::bool
return true;
}
abstract class C extends core::Object implements self::I {
constructor •() → void
: super core::Object::•()
;
}
static field core::bool x = self::f().g();
static method f() → self::C
return null;
static method main() → dynamic {}
@@ -10,3 +10,7 @@ D<T> f<T>() => null;
class D<T> {}
var /*@topType=D<int>*/ g = f<int>();
main() {
g;
}
@@ -0,0 +1,15 @@
library test;
import self as self;
import "dart:core" as core;
class D<T extends core::Object> extends core::Object {
constructor •() → void
: super core::Object::•()
;
}
static field self::D<core::int> g = self::f<core::int>();
static method f<T extends core::Object>() → self::D<self::f::T>
return null;
static method main() → dynamic {
self::g;
}
@@ -10,3 +10,7 @@ var /*@topType=List<dynamic>*/ v = f<dynamic>(
/*@returnType=int*/ () {
return 1;
});
main() {
v;
}
@@ -0,0 +1,12 @@
library test;
import self as self;
import "dart:core" as core;
static field core::List<dynamic> v = self::f<dynamic>(() → dynamic {
return 1;
});
static method f<T extends core::Object>(() → self::f::T g) → core::List<self::f::T>
return <self::f::T>[g.call()];
static method main() → dynamic {
self::v;
}
@@ -9,3 +9,7 @@ List<T> f<T>(T g()) => <T>[g()];
var /*@topType=List<int>*/ v = f<int>(/*@returnType=int*/ () {
return 1;
});
main() {
v;
}
@@ -0,0 +1,12 @@
library test;
import self as self;
import "dart:core" as core;
static field core::List<core::int> v = self::f<core::int>(() → dynamic {
return 1;
});
static method f<T extends core::Object>(() → self::f::T g) → core::List<self::f::T>
return <self::f::T>[g.call()];
static method main() → dynamic {
self::v;
}
@@ -0,0 +1,11 @@
library test;
import self as self;
import "dart:core" as core;
static method main() → dynamic {
core::List<core::int> v = self::f<core::int>(() → core::int {
return 1;
});
}
static method f<T extends core::Object>(() → self::f::T g) → core::List<self::f::T>
return <self::f::T>[g.call()];
@@ -0,0 +1,11 @@
library test;
import self as self;
import "dart:core" as core;
static method main() → dynamic {
core::double v = self::f(() → core::int {
return 1;
});
}
static method f(dynamic x) → core::double
return 1.0;