From 4c9d7e54cb844eaa051aceaea67f491ee867d7e5 Mon Sep 17 00:00:00 2001 From: Alexander Markov Date: Tue, 12 May 2026 06:03:11 -0700 Subject: [PATCH] [vm,compiler] Fix inlining of generic functions with optional parameters When checking number of arguments passed by the caller against number of parameters in the callee, inliner was not taking "type arguments" argument into account which resulted in the rejected inline if all optional parameters are passed. TEST=runtime/tests/vm/dart/inline_generic_functions_il_test.dart Change-Id: I38d1fd2a1a4aadfb0196e5a472d224e3da3a1562 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/502800 Commit-Queue: Alexander Markov Reviewed-by: Slava Egorov --- .../inline_generic_functions_il_test.dart | 98 +++++++++++++++++++ runtime/vm/compiler/backend/inliner.cc | 12 ++- 2 files changed, 105 insertions(+), 5 deletions(-) create mode 100644 runtime/tests/vm/dart/inline_generic_functions_il_test.dart diff --git a/runtime/tests/vm/dart/inline_generic_functions_il_test.dart b/runtime/tests/vm/dart/inline_generic_functions_il_test.dart new file mode 100644 index 00000000000..a1b2f1b6cf0 --- /dev/null +++ b/runtime/tests/vm/dart/inline_generic_functions_il_test.dart @@ -0,0 +1,98 @@ +// Copyright (c) 2026, 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. + +// Verifies that compiler can inline generic functions with optional +// parameters. + +import 'package:vm/testing/il_matchers.dart'; + +@pragma('vm:never-inline') +void foo(int x) { + print(x); +} + +@pragma('vm:prefer-inline') +void callee1() { + foo(10); +} + +@pragma('vm:testing:print-flow-graph') +@pragma('vm:never-inline') +void test1() { + callee1(); +} + +void matchCallFoo(FlowGraph graph) { + graph.dump(); + graph.match([ + match.block('Graph', ['v0' << match.Constant(value: null)]), + match.block('Function', [ + match.CheckStackOverflow(), + match.StaticCall(function: 'foo'), + match.DartReturn('v0'), + ]), + ]); +} + +void matchIL$test1(FlowGraph graph) { + matchCallFoo(graph); +} + +@pragma('vm:prefer-inline') +void callee2(int a0, [int a1 = 0]) { + foo(a0 + a1); +} + +@pragma('vm:testing:print-flow-graph') +@pragma('vm:never-inline') +void test2a() { + callee2(10); +} + +void matchIL$test2a(FlowGraph graph) { + matchCallFoo(graph); +} + +@pragma('vm:testing:print-flow-graph') +@pragma('vm:never-inline') +void test2b() { + callee2(20, 30); +} + +void matchIL$test2b(FlowGraph graph) { + matchCallFoo(graph); +} + +@pragma('vm:prefer-inline') +void callee3(int a0, {int a1 = 0}) { + foo(a0 + a1); +} + +@pragma('vm:testing:print-flow-graph') +@pragma('vm:never-inline') +void test3a() { + callee3(10); +} + +void matchIL$test3a(FlowGraph graph) { + matchCallFoo(graph); +} + +@pragma('vm:testing:print-flow-graph') +@pragma('vm:never-inline') +void test3b() { + callee3(20, a1: 30); +} + +void matchIL$test3b(FlowGraph graph) { + matchCallFoo(graph); +} + +void main() { + test1(); + test2a(); + test2b(); + test3a(); + test3b(); +} diff --git a/runtime/vm/compiler/backend/inliner.cc b/runtime/vm/compiler/backend/inliner.cc index d8315a833f6..d2012d51244 100644 --- a/runtime/vm/compiler/backend/inliner.cc +++ b/runtime/vm/compiler/backend/inliner.cc @@ -1250,9 +1250,10 @@ class CallSiteInliner : public ValueObject { if ((function.HasOptionalPositionalParameters() || function.HasOptionalNamedParameters()) && - !function.AreValidArguments(function.NumTypeParameters(), - arguments->length(), argument_names, - nullptr)) { + !function.AreValidArguments( + function.NumTypeParameters(), + arguments->length() - call_data->first_arg_index, argument_names, + nullptr)) { TRACE_INLINING(THR_Print(" Bailout: optional arg mismatch\n")); PRINT_INLINING_TREE("Optional arg mismatch", &call_data->caller, &function, call_data->call); @@ -1858,9 +1859,10 @@ class CallSiteInliner : public ValueObject { // Arguments mismatch: Caller supplied unsupported named argument. ASSERT(argument_names_count == 0); // Create a stub for each optional positional parameters with an actual. - for (intptr_t i = first_arg_index + fixed_param_count; i < arg_count; + for (intptr_t i = fixed_param_count; i < arg_count - first_arg_index; ++i) { - param_stubs->Add(CreateParameterStub(i, (*arguments)[i], callee_graph)); + param_stubs->Add(CreateParameterStub( + i, (*arguments)[first_arg_index + i], callee_graph)); } ASSERT(function.NumOptionalPositionalParameters() == (param_count - fixed_param_count));