Files
sdk/pkg/vm/lib/transformations/call_site_annotator.dart
T
Vyacheslav Egorov b6e2e158dd [vm/kernel] Make call site annotator transformation more robust
Currently we can't rely on getStaticType due to various issues with
Kernel AST - so we just wrap the invocation in try-catch and swallow
the exception if any.

Fixes https://github.com/dart-lang/sdk/issues/34463

R=alexmarkov@google.com

Change-Id: I48af952c4df4e124a895f0e1b9bf50a50b94a047
Reviewed-on: https://dart-review.googlesource.com/75221
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Vyacheslav Egorov <vegorov@google.com>
2018-09-17 22:48:13 +00:00

108 lines
3.7 KiB
Dart

// Copyright (c) 2018, 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 transformation annotates call sites with the receiver type.
// This is done to avoid reimplementing [Expression.getStaticType] in
// C++.
// We don't annotate all call-sites, but only those where VM could benefit from
// knowing static type of the receiver.
library vm.transformations.call_site_annotator;
import 'package:kernel/ast.dart';
import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
import 'package:kernel/core_types.dart' show CoreTypes;
import 'package:kernel/type_environment.dart' show TypeEnvironment;
import '../metadata/call_site_attributes.dart';
CallSiteAttributesMetadataRepository addRepositoryTo(Component component) {
return component.metadata.putIfAbsent(
CallSiteAttributesMetadataRepository.repositoryTag,
() => new CallSiteAttributesMetadataRepository());
}
void transformLibraries(Component component, List<Library> libraries,
CoreTypes coreTypes, ClassHierarchy hierarchy) {
final transformer =
new AnnotateWithStaticTypes(component, coreTypes, hierarchy);
libraries.forEach(transformer.visitLibrary);
}
class AnnotateWithStaticTypes extends RecursiveVisitor<Null> {
final CallSiteAttributesMetadataRepository _metadata;
final TypeEnvironment env;
AnnotateWithStaticTypes(
Component component, CoreTypes coreTypes, ClassHierarchy hierarchy)
: _metadata = addRepositoryTo(component),
env = new TypeEnvironment(coreTypes, hierarchy, strongMode: true);
@override
visitProcedure(Procedure proc) {
if (!proc.isStatic) {
env.thisType = proc.enclosingClass?.thisType;
}
super.visitProcedure(proc);
env.thisType = null;
}
@override
visitConstructor(Constructor proc) {
env.thisType = proc.enclosingClass?.thisType;
super.visitConstructor(proc);
env.thisType = null;
}
void annotateWithType(TreeNode node, Expression receiver) {
try {
_metadata.mapping[node] = new CallSiteAttributesMetadata(
receiverType: receiver.getStaticType(env));
} catch (e) {
// TODO(dartbug.com/34496) Currently getStaticType is unreliable due to
// various issues with AST welltypedness. As a workaround we just
// swallow the exception.
}
}
@override
visitPropertySet(PropertySet node) {
super.visitPropertySet(node);
if (hasGenericCovariantParameters(node.interfaceTarget)) {
annotateWithType(node, node.receiver);
}
}
@override
visitMethodInvocation(MethodInvocation node) {
super.visitMethodInvocation(node);
// TODO(34162): We don't need to save the type here for calls, just whether
// or not it's a statically-checked call.
if (node.name.name == 'call' ||
hasGenericCovariantParameters(node.interfaceTarget)) {
annotateWithType(node, node.receiver);
}
}
/// Return [true] if the given list of [VariableDeclaration] contains
/// any annotated with generic-covariant-impl.
static bool containsGenericCovariantImpl(List<VariableDeclaration> decls) =>
decls.any((p) => p.isGenericCovariantImpl);
/// Returns [true] if the given [member] has any parameters annotated with
/// generic-covariant-impl attribute.
static bool hasGenericCovariantParameters(Member member) {
if (member is Procedure) {
return containsGenericCovariantImpl(
member.function.positionalParameters) ||
containsGenericCovariantImpl(member.function.namedParameters);
} else if (member is Field) {
return member.isGenericCovariantImpl;
}
return false;
}
}