diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart index fc66b07cfe8..f320b69d7ab 100644 --- a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart +++ b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart @@ -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); + }); } } diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inference_listener.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inference_listener.dart index 8c40097e56b..914b96bc0ce 100644 --- a/pkg/front_end/lib/src/fasta/type_inference/type_inference_listener.dart +++ b/pkg/front_end/lib/src/fasta/type_inference/type_inference_listener.dart @@ -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); diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart index de8c2a95184..38fda54600e 100644 --- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart +++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart @@ -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 explicitTypeArguments, + void forEachArgument(void callback(String name, Expression expression)), + void setInferredTypeArguments(List 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.filled( + calleeTypeParameters.length, const DynamicType())); } int i = 0; forEachArgument((name, expression) { diff --git a/pkg/front_end/test/fasta/strong.status b/pkg/front_end/test/fasta/strong.status index 3f0a33cd0a4..909b6e38d73 100644 --- a/pkg/front_end/test/fasta/strong.status +++ b/pkg/front_end/test/fasta/strong.status @@ -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 diff --git a/pkg/front_end/testcases/inference/downwards_inference_on_function_arguments_infer_downwards.dart.strong.expect b/pkg/front_end/testcases/inference/downwards_inference_on_function_arguments_infer_downwards.dart.strong.expect new file mode 100644 index 00000000000..e6642f5ce37 --- /dev/null +++ b/pkg/front_end/testcases/inference/downwards_inference_on_function_arguments_infer_downwards.dart.strong.expect @@ -0,0 +1,31 @@ +library test; +import self as self; +import "dart:core" as core; + +static method f0(core::List a) → void {} +static method f1({core::List a = null}) → void {} +static method f2(core::Iterable a) → void {} +static method f3(core::Iterable> a) → void {} +static method f4({core::Iterable> a = null}) → void {} +static method main() → void { + self::f0([]); + self::f0([3]); + self::f0(["hello"]); + self::f0(["hello", 3]); + self::f1(a: []); + self::f1(a: [3]); + self::f1(a: ["hello"]); + self::f1(a: ["hello", 3]); + self::f2([]); + self::f2([3]); + self::f2(["hello"]); + self::f2(["hello", 3]); + self::f3(>[]); + self::f3(>[[3]]); + self::f3(>[["hello"]]); + self::f3(>[["hello"], [3]]); + self::f4(a: >[]); + self::f4(a: >[[3]]); + self::f4(a: >[["hello"]]); + self::f4(a: >[["hello"], [3]]); +} diff --git a/pkg/front_end/testcases/inference/generic_methods_basic_downward_inference.dart.strong.expect b/pkg/front_end/testcases/inference/generic_methods_basic_downward_inference.dart.strong.expect index a4c31b6f12f..904e54d8b25 100644 --- a/pkg/front_end/testcases/inference/generic_methods_basic_downward_inference.dart.strong.expect +++ b/pkg/front_end/testcases/inference/generic_methods_basic_downward_inference.dart.strong.expect @@ -2,9 +2,9 @@ library test; import self as self; import "dart:core" as core; -static method f(dynamic s) → dynamic +static method f(self::f::S s) → self::f::T return null; static method main() → dynamic { - core::String x = self::f(42); + core::String x = self::f(42); core::String y = self::f.call(42); } diff --git a/pkg/front_end/testcases/inference/generic_methods_dart_math_min_max.dart.strong.expect b/pkg/front_end/testcases/inference/generic_methods_dart_math_min_max.dart.strong.expect index a320bc0069c..ebbd34b800f 100644 --- a/pkg/front_end/testcases/inference/generic_methods_dart_math_min_max.dart.strong.expect +++ b/pkg/front_end/testcases/inference/generic_methods_dart_math_min_max.dart.strong.expect @@ -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(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(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(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(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")); } static method main() → dynamic {} diff --git a/pkg/front_end/testcases/inference/generic_methods_downwards_inference_affects_arguments.dart.strong.expect b/pkg/front_end/testcases/inference/generic_methods_downwards_inference_affects_arguments.dart.strong.expect new file mode 100644 index 00000000000..3b697541325 --- /dev/null +++ b/pkg/front_end/testcases/inference/generic_methods_downwards_inference_affects_arguments.dart.strong.expect @@ -0,0 +1,10 @@ +library test; +import self as self; +import "dart:core" as core; + +static method f(core::List s) → self::f::T + return null; +static method main() → dynamic { + core::String x = self::f(["hi"]); + core::String y = self::f([42]); +} diff --git a/pkg/front_end/testcases/inference/generic_methods_uses_greatest_lower_bound.dart.strong.expect b/pkg/front_end/testcases/inference/generic_methods_uses_greatest_lower_bound.dart.strong.expect new file mode 100644 index 00000000000..08690570615 --- /dev/null +++ b/pkg/front_end/testcases/inference/generic_methods_uses_greatest_lower_bound.dart.strong.expect @@ -0,0 +1,11 @@ +library test; +import self as self; +import "dart:core" as core; + +typedef F = (core::int) → core::Iterable; +typedef G = (core::double) → core::List; +static method generic((self::generic::T) → dynamic a, (self::generic::T) → dynamic b) → self::generic::T + return null; +static method main() → dynamic { + (core::num) → core::List v = self::generic<(core::num) → core::List>(((core::int) → core::Iterable f) → dynamic => null, ((core::double) → core::List g) → dynamic => null); +} diff --git a/pkg/front_end/testcases/inference/infer_variable_void.dart b/pkg/front_end/testcases/inference/infer_variable_void.dart index 09af55333cd..3e54630bc25 100644 --- a/pkg/front_end/testcases/inference/infer_variable_void.dart +++ b/pkg/front_end/testcases/inference/infer_variable_void.dart @@ -7,3 +7,7 @@ library test; void f() {} var /*@topType=void*/ x = /*info:USE_OF_VOID_RESULT*/ f(); + +main() { + x; +} diff --git a/pkg/front_end/testcases/inference/infer_variable_void.dart.strong.expect b/pkg/front_end/testcases/inference/infer_variable_void.dart.strong.expect new file mode 100644 index 00000000000..3bfd2e6d02b --- /dev/null +++ b/pkg/front_end/testcases/inference/infer_variable_void.dart.strong.expect @@ -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; +} diff --git a/pkg/front_end/testcases/inference/inferred_type_invoke_method.dart b/pkg/front_end/testcases/inference/inferred_type_invoke_method.dart index dfde4911611..ec5825acb74 100644 --- a/pkg/front_end/testcases/inference/inferred_type_invoke_method.dart +++ b/pkg/front_end/testcases/inference/inferred_type_invoke_method.dart @@ -11,3 +11,5 @@ class C { C f() => null; var /*@topType=bool*/ x = f(). /*@target=C::g*/ g(); + +main() {} diff --git a/pkg/front_end/testcases/inference/inferred_type_invoke_method.dart.strong.expect b/pkg/front_end/testcases/inference/inferred_type_invoke_method.dart.strong.expect new file mode 100644 index 00000000000..548a7db22df --- /dev/null +++ b/pkg/front_end/testcases/inference/inferred_type_invoke_method.dart.strong.expect @@ -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 {} diff --git a/pkg/front_end/testcases/inference/inferred_type_invoke_method_via_interface.dart b/pkg/front_end/testcases/inference/inferred_type_invoke_method_via_interface.dart index 4f4adc755d5..f28fb58ba64 100644 --- a/pkg/front_end/testcases/inference/inferred_type_invoke_method_via_interface.dart +++ b/pkg/front_end/testcases/inference/inferred_type_invoke_method_via_interface.dart @@ -13,3 +13,5 @@ abstract class C implements I {} C f() => null; var /*@topType=bool*/ x = f(). /*@target=I::g*/ g(); + +main() {} diff --git a/pkg/front_end/testcases/inference/inferred_type_invoke_method_via_interface.dart.strong.expect b/pkg/front_end/testcases/inference/inferred_type_invoke_method_via_interface.dart.strong.expect new file mode 100644 index 00000000000..8a046f40e34 --- /dev/null +++ b/pkg/front_end/testcases/inference/inferred_type_invoke_method_via_interface.dart.strong.expect @@ -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 {} diff --git a/pkg/front_end/testcases/inference/method_call_with_type_arguments_top_level_function.dart b/pkg/front_end/testcases/inference/method_call_with_type_arguments_top_level_function.dart index 1aaa5246de3..afc98117b80 100644 --- a/pkg/front_end/testcases/inference/method_call_with_type_arguments_top_level_function.dart +++ b/pkg/front_end/testcases/inference/method_call_with_type_arguments_top_level_function.dart @@ -10,3 +10,7 @@ D f() => null; class D {} var /*@topType=D*/ g = f(); + +main() { + g; +} diff --git a/pkg/front_end/testcases/inference/method_call_with_type_arguments_top_level_function.dart.strong.expect b/pkg/front_end/testcases/inference/method_call_with_type_arguments_top_level_function.dart.strong.expect new file mode 100644 index 00000000000..84f00752139 --- /dev/null +++ b/pkg/front_end/testcases/inference/method_call_with_type_arguments_top_level_function.dart.strong.expect @@ -0,0 +1,15 @@ +library test; +import self as self; +import "dart:core" as core; + +class D extends core::Object { + constructor •() → void + : super core::Object::•() + ; +} +static field self::D g = self::f(); +static method f() → self::D + return null; +static method main() → dynamic { + self::g; +} diff --git a/pkg/front_end/testcases/inference/unsafe_block_closure_inference_function_call_explicit_dynamic_param.dart b/pkg/front_end/testcases/inference/unsafe_block_closure_inference_function_call_explicit_dynamic_param.dart index 4d0cc72d28f..27638af53d1 100644 --- a/pkg/front_end/testcases/inference/unsafe_block_closure_inference_function_call_explicit_dynamic_param.dart +++ b/pkg/front_end/testcases/inference/unsafe_block_closure_inference_function_call_explicit_dynamic_param.dart @@ -10,3 +10,7 @@ var /*@topType=List*/ v = f( /*@returnType=int*/ () { return 1; }); + +main() { + v; +} diff --git a/pkg/front_end/testcases/inference/unsafe_block_closure_inference_function_call_explicit_dynamic_param.dart.strong.expect b/pkg/front_end/testcases/inference/unsafe_block_closure_inference_function_call_explicit_dynamic_param.dart.strong.expect new file mode 100644 index 00000000000..f6d3d93c015 --- /dev/null +++ b/pkg/front_end/testcases/inference/unsafe_block_closure_inference_function_call_explicit_dynamic_param.dart.strong.expect @@ -0,0 +1,12 @@ +library test; +import self as self; +import "dart:core" as core; + +static field core::List v = self::f(() → dynamic { + return 1; +}); +static method f(() → self::f::T g) → core::List + return [g.call()]; +static method main() → dynamic { + self::v; +} diff --git a/pkg/front_end/testcases/inference/unsafe_block_closure_inference_function_call_explicit_type_param.dart b/pkg/front_end/testcases/inference/unsafe_block_closure_inference_function_call_explicit_type_param.dart index 3804be11999..cd0d3ba4616 100644 --- a/pkg/front_end/testcases/inference/unsafe_block_closure_inference_function_call_explicit_type_param.dart +++ b/pkg/front_end/testcases/inference/unsafe_block_closure_inference_function_call_explicit_type_param.dart @@ -9,3 +9,7 @@ List f(T g()) => [g()]; var /*@topType=List*/ v = f(/*@returnType=int*/ () { return 1; }); + +main() { + v; +} diff --git a/pkg/front_end/testcases/inference/unsafe_block_closure_inference_function_call_explicit_type_param.dart.strong.expect b/pkg/front_end/testcases/inference/unsafe_block_closure_inference_function_call_explicit_type_param.dart.strong.expect new file mode 100644 index 00000000000..dcf4f804ca7 --- /dev/null +++ b/pkg/front_end/testcases/inference/unsafe_block_closure_inference_function_call_explicit_type_param.dart.strong.expect @@ -0,0 +1,12 @@ +library test; +import self as self; +import "dart:core" as core; + +static field core::List v = self::f(() → dynamic { + return 1; +}); +static method f(() → self::f::T g) → core::List + return [g.call()]; +static method main() → dynamic { + self::v; +} diff --git a/pkg/front_end/testcases/inference/unsafe_block_closure_inference_function_call_implicit_type_param.dart.strong.expect b/pkg/front_end/testcases/inference/unsafe_block_closure_inference_function_call_implicit_type_param.dart.strong.expect new file mode 100644 index 00000000000..27f92d87927 --- /dev/null +++ b/pkg/front_end/testcases/inference/unsafe_block_closure_inference_function_call_implicit_type_param.dart.strong.expect @@ -0,0 +1,11 @@ +library test; +import self as self; +import "dart:core" as core; + +static method main() → dynamic { + core::List v = self::f(() → core::int { + return 1; + }); +} +static method f(() → self::f::T g) → core::List + return [g.call()]; diff --git a/pkg/front_end/testcases/inference/unsafe_block_closure_inference_function_call_no_type_param.dart.strong.expect b/pkg/front_end/testcases/inference/unsafe_block_closure_inference_function_call_no_type_param.dart.strong.expect new file mode 100644 index 00000000000..1094b0c4e94 --- /dev/null +++ b/pkg/front_end/testcases/inference/unsafe_block_closure_inference_function_call_no_type_param.dart.strong.expect @@ -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;