[vm/aot] Keep pragmas on VariableDeclaration nodes in tree shaker

VM can use pragmas on local functions, which are actually put on
VariableDeclaration nodes. This change teaches TFA tree shaker to
keep such pragmas.

TEST=pkg/vm/testcases/transformations/type_flow/transformer/pragmas.dart
Issue: https://github.com/dart-lang/sdk/issues/45987
Change-Id: Ic2db375a93b539a131eca2431bef0e317a4d1b2b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/199520
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Alexander Markov 2021-05-14 19:20:28 +00:00 committed by commit-bot@chromium.org
parent b1c961233d
commit d39e794cc3
4 changed files with 69 additions and 5 deletions

View file

@ -774,8 +774,6 @@ class SummaryCollector extends RecursiveResultVisitor<TypeExpr> {
_summary.result = _returnValue;
}
// Visit annotations on members, classes and libraries.
// Other nodes currently do not have annotations used by the VM.
member.annotations.forEach(_visit);
member.enclosingClass?.annotations?.forEach(_visit);
member.enclosingLibrary?.annotations?.forEach(_visit);
@ -2136,6 +2134,7 @@ class SummaryCollector extends RecursiveResultVisitor<TypeExpr> {
@override
TypeExpr visitFunctionDeclaration(FunctionDeclaration node) {
// TODO(alexmarkov): support function types.
node.variable.annotations.forEach(_visit);
_declareVariableWithStaticType(node.variable);
_handleNestedFunctionNode(node.function);
return null;
@ -2248,6 +2247,7 @@ class SummaryCollector extends RecursiveResultVisitor<TypeExpr> {
@override
TypeExpr visitVariableDeclaration(VariableDeclaration node) {
node.annotations.forEach(_visit);
final TypeExpr initialValue =
node.initializer == null ? _nullType : _visit(node.initializer);
_declareVariable(node, initialValue);

View file

@ -122,8 +122,8 @@ Component transformComponent(
}
// Pass which removes all annotations except @ExternalName and @pragma
// on members, classes and libraries. May also keep @TagNumber which is used
// by protobuf handler.
// on variables, members, classes and libraries.
// May also keep @TagNumber which is used by protobuf handler.
class CleanupAnnotations extends RecursiveVisitor {
final Class externalNameClass;
final Class pragmaClass;
@ -152,7 +152,10 @@ class CleanupAnnotations extends RecursiveVisitor {
}
void _cleanupAnnotations(Node node, List<Expression> annotations) {
if (node is Member || node is Class || node is Library) {
if (node is VariableDeclaration ||
node is Member ||
node is Class ||
node is Library) {
annotations.removeWhere((a) => !_keepAnnotation(a));
} else {
annotations.clear();

View file

@ -0,0 +1,33 @@
// Copyright (c) 2021, 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.
class A {
final int x;
const A(this.x);
}
class B {
final int y;
const B(this.y);
}
class C {
final int z;
const C(this.z);
}
@pragma("test1", A(10))
class Foo {
@pragma("test2", {3: B(11), 4: 'hey'})
void bar() {
@pragma("test3", C(12))
void bazz() {}
bazz();
}
}
main() {
Foo().bar();
}

View file

@ -0,0 +1,28 @@
library #lib;
import self as self;
import "dart:core" as core;
class A extends core::Object /*hasConstConstructor*/ {
[@vm.inferred-type.metadata=dart.core::_Smi (value: 10)] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:1] [@vm.unboxing-info.metadata=()->i] final field core::int* x;
}
class B extends core::Object /*hasConstConstructor*/ {
[@vm.inferred-type.metadata=dart.core::_Smi (value: 11)] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:2] [@vm.unboxing-info.metadata=()->i] final field core::int* y;
}
class C extends core::Object /*hasConstConstructor*/ {
[@vm.inferred-type.metadata=dart.core::_Smi (value: 12)] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:3] [@vm.unboxing-info.metadata=()->i] final field core::int* z;
}
@#C4
class Foo extends core::Object {
synthetic constructor •() → self::Foo*
: super core::Object::•()
;
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:4,getterSelectorId:5] @#C13
method bar() → void {
@#C17
function bazz() → void {}
[@vm.call-site-attributes.metadata=receiverType:void Function()*] bazz.call();
}
}
static method main() → dynamic {
[@vm.direct-call.metadata=#lib::Foo.bar] [@vm.inferred-type.metadata=!? (skip check)] new self::Foo::•().{self::Foo::bar}();
}