Implement type inference of static invocations.
R=scheglov@google.com Review-Url: https://codereview.chromium.org/2885963002 .
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
+31
@@ -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
-2
@@ -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);
|
||||
}
|
||||
|
||||
+10
-10
@@ -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 {}
|
||||
|
||||
+10
@@ -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]);
|
||||
}
|
||||
+11
@@ -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() {}
|
||||
|
||||
+20
@@ -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 {}
|
||||
+4
@@ -10,3 +10,7 @@ D<T> f<T>() => null;
|
||||
class D<T> {}
|
||||
|
||||
var /*@topType=D<int>*/ g = f<int>();
|
||||
|
||||
main() {
|
||||
g;
|
||||
}
|
||||
|
||||
+15
@@ -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;
|
||||
}
|
||||
+4
@@ -10,3 +10,7 @@ var /*@topType=List<dynamic>*/ v = f<dynamic>(
|
||||
/*@returnType=int*/ () {
|
||||
return 1;
|
||||
});
|
||||
|
||||
main() {
|
||||
v;
|
||||
}
|
||||
|
||||
+12
@@ -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;
|
||||
}
|
||||
+4
@@ -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;
|
||||
}
|
||||
|
||||
+12
@@ -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;
|
||||
}
|
||||
+11
@@ -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()];
|
||||
+11
@@ -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;
|
||||
Reference in New Issue
Block a user