[dart2js] Fix record tracing w.r.t to closures.
We were losing track of records (and their contents) when they flowed into a closure. Now we correctly bailout when we encounter this situation. This matches the behavior we have for tracing other collection objects. Change-Id: I2b0945f9ab9732e3f460cefee451c7b853316ad5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/478780 Commit-Queue: Nate Biggs <natebiggs@google.com> Reviewed-by: Sigmund Cherem <sigmund@google.com>
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
// Copyright (c) 2023, 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.
|
||||
import '../common/names.dart';
|
||||
import '../elements/entities.dart';
|
||||
|
||||
import 'node_tracer.dart';
|
||||
import 'type_graph_nodes.dart';
|
||||
|
||||
@@ -16,4 +19,34 @@ class RecordTracerVisitor extends TracerVisitor {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
void visitClosureCallSiteTypeInformation(
|
||||
ClosureCallSiteTypeInformation info,
|
||||
) {
|
||||
bailout('Passed to a closure');
|
||||
}
|
||||
|
||||
@override
|
||||
void visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) {
|
||||
super.visitStaticCallSiteTypeInformation(info);
|
||||
MemberEntity called = info.calledElement;
|
||||
if (inferrer.closedWorld.commonElements.isForeign(called) &&
|
||||
called.name == Identifiers.js) {
|
||||
bailout('Used in JS ${info.debugName}');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void visitDynamicCallSiteTypeInformation(
|
||||
DynamicCallSiteTypeInformation info,
|
||||
) {
|
||||
super.visitDynamicCallSiteTypeInformation(info);
|
||||
final selector = info.selector!;
|
||||
if (selector.isCall &&
|
||||
(info.hasClosureCallTargets || dynamicCallTargetsNonFunction(info))) {
|
||||
bailout('Passed to a closure');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
// 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.
|
||||
|
||||
typedef F<T> = void Function(T chunk);
|
||||
typedef A<T> = ({F<T> sendChunk, int whatever});
|
||||
|
||||
class M {
|
||||
final List<String> content;
|
||||
M({required this.content});
|
||||
}
|
||||
|
||||
class G {
|
||||
final M _chunk;
|
||||
G(this._chunk);
|
||||
|
||||
String get text => _chunk.content.join('');
|
||||
}
|
||||
|
||||
void produceIt(A<M> ctx) {
|
||||
int base(A<M> b) {
|
||||
b.sendChunk(M(content: ["content-value"]));
|
||||
return 1;
|
||||
}
|
||||
|
||||
final composeModel = _values.fold(
|
||||
base,
|
||||
(next, mw) =>
|
||||
(c) => mw.f(c, next),
|
||||
);
|
||||
composeModel((
|
||||
whatever: 1,
|
||||
sendChunk: (c) => ctx.sendChunk(M(content: c.content)),
|
||||
));
|
||||
}
|
||||
|
||||
void useIt(G g) {
|
||||
print(g.text);
|
||||
}
|
||||
|
||||
class Wrapper {
|
||||
int f(A<M> c, int Function(A<M>) next) {
|
||||
return next(c);
|
||||
}
|
||||
}
|
||||
|
||||
List<Wrapper> _values = [Wrapper(), Wrapper(), Wrapper()];
|
||||
|
||||
void main() {
|
||||
produceIt((
|
||||
whatever: 2,
|
||||
sendChunk: (c) {
|
||||
useIt(G(c));
|
||||
},
|
||||
));
|
||||
}
|
||||
Reference in New Issue
Block a user