diff --git a/pkg/vm_service/test/regress_48279_test.dart b/pkg/vm_service/test/regress_48279_test.dart new file mode 100644 index 00000000000..d57b0849641 --- /dev/null +++ b/pkg/vm_service/test/regress_48279_test.dart @@ -0,0 +1,45 @@ +// Copyright (c) 2022, 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. + +// This test verifies that generic type argument ('T') can be evaluated +// when stopped on an exception which is thrown during type check in +// the implicit field setter. +// Regression test for https://github.com/dart-lang/sdk/issues/48279. + +import 'package:test/test.dart'; +import 'package:vm_service/vm_service.dart'; + +import 'common/service_test_common.dart'; +import 'common/test_helper.dart'; + +class A { + List foo = []; +} + +testeeMain() { + A object = A(); + object.foo = []; +} + +var tests = [ + hasStoppedWithUnhandledException, + (VmService? service, IsolateRef? isolateRef) async { + print("We stopped!"); + final isolateId = isolateRef!.id!; + final stack = await service!.getStack(isolateId); + final topFrame = stack.frames![0]; + expect(topFrame.function!.name, equals('foo=')); + final result = await service.evaluateInFrame(isolateId, 0, 'T'); + print(result); + expect((result as InstanceRef).name, equals("int")); + } +]; + +main(args) => runIsolateTests( + args, + tests, + 'regress_48279_test.dart', + pause_on_unhandled_exceptions: true, + testeeConcurrent: testeeMain, + ); diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc index 9fd12431cdb..eb4d2c95ca9 100644 --- a/runtime/vm/compiler/frontend/kernel_to_il.cc +++ b/runtime/vm/compiler/frontend/kernel_to_il.cc @@ -1839,13 +1839,14 @@ Fragment FlowGraphBuilder::CheckBoolean(TokenPosition position) { Fragment FlowGraphBuilder::CheckAssignable(const AbstractType& dst_type, const String& dst_name, - AssertAssignableInstr::Kind kind) { + AssertAssignableInstr::Kind kind, + TokenPosition token_pos) { Fragment instructions; if (!dst_type.IsTopTypeForSubtyping()) { LocalVariable* top_of_stack = MakeTemporary(); instructions += LoadLocal(top_of_stack); - instructions += AssertAssignableLoadTypeArguments(TokenPosition::kNoSource, - dst_type, dst_name, kind); + instructions += + AssertAssignableLoadTypeArguments(token_pos, dst_type, dst_name, kind); instructions += Drop(); } return instructions; @@ -3679,7 +3680,8 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfFieldAccessor( setter_value->needs_type_check(); if (needs_type_check) { body += CheckAssignable(setter_value->type(), setter_value->name(), - AssertAssignableInstr::kParameterCheck); + AssertAssignableInstr::kParameterCheck, + field.token_pos()); } body += BuildNullAssertions(); if (field.is_late()) { diff --git a/runtime/vm/compiler/frontend/kernel_to_il.h b/runtime/vm/compiler/frontend/kernel_to_il.h index cb66e59bbb4..f226a12aa66 100644 --- a/runtime/vm/compiler/frontend/kernel_to_il.h +++ b/runtime/vm/compiler/frontend/kernel_to_il.h @@ -243,7 +243,8 @@ class FlowGraphBuilder : public BaseFlowGraphBuilder { Fragment CheckAssignable( const AbstractType& dst_type, const String& dst_name, - AssertAssignableInstr::Kind kind = AssertAssignableInstr::kUnknown); + AssertAssignableInstr::Kind kind = AssertAssignableInstr::kUnknown, + TokenPosition token_pos = TokenPosition::kNoSource); Fragment AssertAssignableLoadTypeArguments( TokenPosition position,