From 98d0122520b1241ea9889b10090db2ea0ee2d9ea Mon Sep 17 00:00:00 2001 From: "Sergey G. Grekhov" Date: Fri, 31 Oct 2025 12:58:03 +0200 Subject: [PATCH 1/2] #3203. Add tests for private named parameters --- VM/private_named_parameters_t01.dart | 114 +++++++++++++++++++++++++++ VM/private_named_parameters_t02.dart | 69 ++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 VM/private_named_parameters_t01.dart create mode 100644 VM/private_named_parameters_t02.dart diff --git a/VM/private_named_parameters_t01.dart b/VM/private_named_parameters_t01.dart new file mode 100644 index 0000000000..b98af1c5de --- /dev/null +++ b/VM/private_named_parameters_t01.dart @@ -0,0 +1,114 @@ +// Copyright (c) 2025, 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. + +/// @assertion We let users use a private name in a named parameter when the +/// parameter also initializes or declares a field. The compiler removes the `_` +/// from the argument name but keeps it for the corresponding field. +/// +/// @description Check that private named parameters can be debugged. +/// @author sgrekhov22@gmail.com + +// SharedOptions=--enable-experiment=declaring-constructors,private-named-parameters + +import 'dart:developer'; +import 'package:vm_service/vm_service.dart'; + +import '../../../../pkg/vm_service/test/common/service_test_common.dart'; +import '../../../../pkg/vm_service/test/common/test_helper.dart'; +import '../Utils/expect.dart'; + +const String shortFile = 'private_named_parameters_t01.dart'; + +// AUTOGENERATED START +// +// Update these constants by running: +// +// dart pkg/vm_service/test/update_line_numbers.dart tests/co19/src/VM/private_named_parameters_t01.dart +// +const LINE_A = 37; +const LINE_B = 41; +const LINE_C = 45; +const LINE_D = 46; +const LINE_E = 47; +// AUTOGENERATED END + +class C1({var String _x}); // LINE_A + +class C2 { + String _x; + C2({this._x}); // LINE_B +} + +void testeeMain() { + debugger(); // LINE_C + C1(x: "xxx"); // LINE_D + C2(x: "yyy"); // LINE_E +} + +final tests = [ + hasStoppedAtBreakpoint, + stoppedAtLine(LINE_C), + stepInto, + stoppedAtLine(LINE_D), + stepInto, + stoppedAtLine(LINE_A), + (VmService service, IsolateRef isolateRef) async { + final isolateId = isolateRef.id!; + final xRef1 = + await service.evaluateInFrame(isolateId, 0, '_x') as InstanceRef; + Expect.equals("null", xRef1.valueAsString); + final xRef2 = + await service.evaluateInFrame(isolateId, 0, 'this._x') as InstanceRef; + Expect.equals("null", xRef2.valueAsString); + }, + stepInto, + (VmService service, IsolateRef isolateRef) async { + final isolateId = isolateRef.id!; + final xRef1 = + await service.evaluateInFrame(isolateId, 0, '_x') as InstanceRef; + Expect.equals('xxx', xRef1.valueAsString); + final xRef2 = + await service.evaluateInFrame(isolateId, 0, 'this._x') as InstanceRef; + Expect.equals('xxx', xRef2.valueAsString); + final xRef3 = await service.evaluateInFrame(isolateId, 0, 'x'); + Expect.isTrue(xRef3 is ErrorRef); + final xRef4 = await service.evaluateInFrame(isolateId, 0, 'this.x'); + Expect.isTrue(xRef4 is ErrorRef); +}, + stepInto, + stoppedAtLine(LINE_E), + stepInto, + stoppedAtLine(LINE_B), + (VmService service, IsolateRef isolateRef) async { + final isolateId = isolateRef.id!; + final xRef1 = + await service.evaluateInFrame(isolateId, 0, '_x') as InstanceRef; + Expect.equals("null", xRef1.valueAsString); + final xRef2 = + await service.evaluateInFrame(isolateId, 0, 'this._x') as InstanceRef; + Expect.equals("null", xRef2.valueAsString); + }, + stepInto, + (VmService service, IsolateRef isolateRef) async { + final isolateId = isolateRef.id!; + final xRef1 = + await service.evaluateInFrame(isolateId, 0, '_x') as InstanceRef; + Expect.equals('yyy', xRef1.valueAsString); + final xRef2 = + await service.evaluateInFrame(isolateId, 0, 'this._x') as InstanceRef; + Expect.equals('yyy', xRef2.valueAsString); + final xRef3 = await service.evaluateInFrame(isolateId, 0, 'x'); + Expect.isTrue(xRef3 is ErrorRef); + final xRef4 = await service.evaluateInFrame(isolateId, 0, 'this.x'); + Expect.isTrue(xRef4 is ErrorRef); + }, +]; + +void main([args = const []]) => runIsolateTests( + args, + tests, + 'private_named_parameters_t01.dart', + pauseOnExit: true, + testeeConcurrent: testeeMain, +); diff --git a/VM/private_named_parameters_t02.dart b/VM/private_named_parameters_t02.dart new file mode 100644 index 0000000000..0cf618b501 --- /dev/null +++ b/VM/private_named_parameters_t02.dart @@ -0,0 +1,69 @@ +// Copyright (c) 2025, 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. + +/// @assertion We let users use a private name in a named parameter when the +/// parameter also initializes or declares a field. The compiler removes the `_` +/// from the argument name but keeps it for the corresponding field. +/// +/// @description Check that private named parameters are allowed in VM +/// expression evaluation. +/// @author sgrekhov22@gmail.com + +// SharedOptions=--enable-experiment=declaring-constructors,private-named-parameters + +import 'dart:developer'; + +import 'package:vm_service/vm_service.dart'; + +import '../../../../pkg/vm_service/test/common/service_test_common.dart'; +import '../../../../pkg/vm_service/test/common/test_helper.dart'; +import '../Utils/expect.dart'; + +class C1({var String _x}); + +class C2 { + String _x; + C2({required this._x}); +} + +void testeeMain() { + final c1 = C1(x: "one"); + final c2 = C2(x: "two"); + debugger(); +} + +final tests = [ + hasStoppedAtBreakpoint, + + // Test interaction of expression evaluation with private named parameters. + (VmService service, IsolateRef isolateRef) async { + final isolateId = isolateRef.id!; + + InstanceRef response = + await service.evaluateInFrame(isolateId, 0, 'c1._x') as InstanceRef; + Expect.equals('one', response.valueAsString); + + response = + await service.evaluateInFrame(isolateId, 0, 'c2._x') as InstanceRef; + Expect.equals('two', response.valueAsString); + + response = + await service.evaluateInFrame(isolateId, 0, 'C1(x: "zero")._x') + as InstanceRef; + Expect.equals('zero', response.valueAsString); + + response = + await service.evaluateInFrame(isolateId, 0, 'C2(x: "0")._x') + as InstanceRef; + Expect.equals('0', response.valueAsString); + }, +]; + +void main([args = const []]) => runIsolateTests( + args, + tests, + 'private_named_parameters_t02.dart', + pauseOnExit: true, + testeeConcurrent: testeeMain, +); From f19fc94db93e4b7eecbd98fd743403cf13e57fd7 Mon Sep 17 00:00:00 2001 From: "Sergey G. Grekhov" Date: Fri, 31 Oct 2025 14:29:14 +0200 Subject: [PATCH 2/2] Add a case with the initializer list --- VM/private_named_parameters_t01.dart | 96 ++++++++++++++++++++++++---- 1 file changed, 85 insertions(+), 11 deletions(-) diff --git a/VM/private_named_parameters_t01.dart b/VM/private_named_parameters_t01.dart index b98af1c5de..567a815035 100644 --- a/VM/private_named_parameters_t01.dart +++ b/VM/private_named_parameters_t01.dart @@ -18,8 +18,6 @@ import '../../../../pkg/vm_service/test/common/service_test_common.dart'; import '../../../../pkg/vm_service/test/common/test_helper.dart'; import '../Utils/expect.dart'; -const String shortFile = 'private_named_parameters_t01.dart'; - // AUTOGENERATED START // // Update these constants by running: @@ -33,25 +31,31 @@ const LINE_D = 46; const LINE_E = 47; // AUTOGENERATED END -class C1({var String _x}); // LINE_A +class C1({var String _x}); // LINE_A class C2 { String _x; - C2({this._x}); // LINE_B + C2({required this._x}); // LINE_B +} + +class C3 { + int _x, _y; + C3({required this._x}) : _y = _x + 1; // LINE_C } void testeeMain() { - debugger(); // LINE_C - C1(x: "xxx"); // LINE_D - C2(x: "yyy"); // LINE_E + debugger(); // LINE_D + C1(x: "xxx"); // LINE_E + C2(x: "yyy"); // LINE_F + C3(x: 1); // LINE_G } final tests = [ hasStoppedAtBreakpoint, - stoppedAtLine(LINE_C), - stepInto, stoppedAtLine(LINE_D), stepInto, + stoppedAtLine(LINE_E), + stepInto, stoppedAtLine(LINE_A), (VmService service, IsolateRef isolateRef) async { final isolateId = isolateRef.id!; @@ -75,9 +79,9 @@ final tests = [ Expect.isTrue(xRef3 is ErrorRef); final xRef4 = await service.evaluateInFrame(isolateId, 0, 'this.x'); Expect.isTrue(xRef4 is ErrorRef); -}, + }, stepInto, - stoppedAtLine(LINE_E), + stoppedAtLine(LINE_F), stepInto, stoppedAtLine(LINE_B), (VmService service, IsolateRef isolateRef) async { @@ -103,6 +107,76 @@ final tests = [ final xRef4 = await service.evaluateInFrame(isolateId, 0, 'this.x'); Expect.isTrue(xRef4 is ErrorRef); }, + + stepInto, + stoppedAtLine(LINE_G), + stepInto, + stoppedAtLine(LINE_C), + (VmService service, IsolateRef isolateRef) async { + final isolateId = isolateRef.id!; + final xRef1 = + await service.evaluateInFrame(isolateId, 0, '_x') as InstanceRef; + Expect.equals("null", xRef1.valueAsString); + final xRef2 = + await service.evaluateInFrame(isolateId, 0, 'this._x') as InstanceRef; + Expect.equals("null", xRef2.valueAsString); + final xRef3 = + await service.evaluateInFrame(isolateId, 0, '_y') as InstanceRef; + Expect.equals("null", xRef3.valueAsString); + final xRef4 = + await service.evaluateInFrame(isolateId, 0, 'this._y') as InstanceRef; + Expect.equals("null", xRef4.valueAsString); + }, + stepInto, + (VmService service, IsolateRef isolateRef) async { + final isolateId = isolateRef.id!; + final xRef1 = + await service.evaluateInFrame(isolateId, 0, '_x') as InstanceRef; + Expect.equals('1', xRef1.valueAsString); + final xRef2 = + await service.evaluateInFrame(isolateId, 0, 'this._x') as InstanceRef; + Expect.equals('1', xRef2.valueAsString); + final xRef3 = + await service.evaluateInFrame(isolateId, 0, '_y') as InstanceRef; + Expect.equals('null', xRef3.valueAsString); + final xRef4 = + await service.evaluateInFrame(isolateId, 0, 'this._y') as InstanceRef; + Expect.equals('null', xRef3.valueAsString); + + final xRef5 = await service.evaluateInFrame(isolateId, 0, 'x'); + Expect.isTrue(xRef5 is ErrorRef); + final xRef6 = await service.evaluateInFrame(isolateId, 0, 'this.x'); + Expect.isTrue(xRef6 is ErrorRef); + final xRef7 = await service.evaluateInFrame(isolateId, 0, 'y'); + Expect.isTrue(xRef7 is ErrorRef); + final xRef8 = await service.evaluateInFrame(isolateId, 0, 'this.y'); + Expect.isTrue(xRef8 is ErrorRef); + }, + stepInto, + (VmService service, IsolateRef isolateRef) async { + final isolateId = isolateRef.id!; + final xRef1 = + await service.evaluateInFrame(isolateId, 0, '_x') as InstanceRef; + Expect.equals('1', xRef1.valueAsString); + final xRef2 = + await service.evaluateInFrame(isolateId, 0, 'this._x') as InstanceRef; + Expect.equals('1', xRef2.valueAsString); + final xRef3 = + await service.evaluateInFrame(isolateId, 0, '_y') as InstanceRef; + Expect.equals('2', xRef3.valueAsString); + final xRef4 = + await service.evaluateInFrame(isolateId, 0, 'this._y') as InstanceRef; + Expect.equals('2', xRef3.valueAsString); + + final xRef5 = await service.evaluateInFrame(isolateId, 0, 'x'); + Expect.isTrue(xRef5 is ErrorRef); + final xRef6 = await service.evaluateInFrame(isolateId, 0, 'this.x'); + Expect.isTrue(xRef6 is ErrorRef); + final xRef7 = await service.evaluateInFrame(isolateId, 0, 'y'); + Expect.isTrue(xRef7 is ErrorRef); + final xRef8 = await service.evaluateInFrame(isolateId, 0, 'this.y'); + Expect.isTrue(xRef8 is ErrorRef); + }, ]; void main([args = const []]) => runIsolateTests(