d80cff6b2b
- to isCovariantByDeclaration and isCovariantByClass, respectively. This is done to align the terminology with the spec. TEST=existing Change-Id: I96b2e5d6e05caca431aad2b54545e928aee034e5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/213041 Commit-Queue: Johnni Winther <johnniwinther@google.com> Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
129 lines
4.5 KiB
Dart
129 lines
4.5 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.
|
|
|
|
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 StaticTypeContext, TypeEnvironment;
|
|
|
|
import '../metadata/call_site_attributes.dart';
|
|
|
|
CallSiteAttributesMetadataRepository addRepositoryTo(Component component) {
|
|
return component.metadata.putIfAbsent(
|
|
CallSiteAttributesMetadataRepository.repositoryTag,
|
|
() => new CallSiteAttributesMetadataRepository())
|
|
as 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 {
|
|
final CallSiteAttributesMetadataRepository _metadata;
|
|
final TypeEnvironment env;
|
|
StaticTypeContext? _staticTypeContext;
|
|
|
|
AnnotateWithStaticTypes(
|
|
Component component, CoreTypes coreTypes, ClassHierarchy hierarchy)
|
|
: _metadata = addRepositoryTo(component),
|
|
env = new TypeEnvironment(coreTypes, hierarchy);
|
|
|
|
@override
|
|
defaultMember(Member node) {
|
|
_staticTypeContext = new StaticTypeContext(node, env);
|
|
super.defaultMember(node);
|
|
_staticTypeContext = null;
|
|
}
|
|
|
|
void annotateWithReceiver(TreeNode node, Expression receiver) {
|
|
annotateWithReceiverType(node, receiver.getStaticType(_staticTypeContext!));
|
|
}
|
|
|
|
void annotateWithReceiverType(TreeNode node, DartType receiverType) {
|
|
_metadata.mapping[node] =
|
|
new CallSiteAttributesMetadata(receiverType: receiverType);
|
|
}
|
|
|
|
@override
|
|
visitInstanceSet(InstanceSet node) {
|
|
super.visitInstanceSet(node);
|
|
|
|
if (hasGenericCovariantParameters(node.interfaceTarget)) {
|
|
annotateWithReceiver(node, node.receiver);
|
|
}
|
|
}
|
|
|
|
@override
|
|
visitInstanceInvocation(InstanceInvocation node) {
|
|
super.visitInstanceInvocation(node);
|
|
|
|
final DartType receiverType =
|
|
node.receiver.getStaticType(_staticTypeContext!);
|
|
if (receiverType is FunctionType && node.name.text == 'call') {
|
|
throw 'Node ${node.runtimeType}: $node at ${node.location} has receiver'
|
|
' static type $receiverType and selector \'call\'';
|
|
}
|
|
|
|
// TODO(34162): We don't need to save the type here for calls, just whether
|
|
// or not it's a statically-checked call.
|
|
if (hasGenericCovariantParameters(node.interfaceTarget)) {
|
|
annotateWithReceiverType(node, receiverType);
|
|
}
|
|
}
|
|
|
|
@override
|
|
visitFunctionInvocation(FunctionInvocation node) {
|
|
super.visitFunctionInvocation(node);
|
|
|
|
final DartType receiverType =
|
|
node.receiver.getStaticType(_staticTypeContext!);
|
|
if (receiverType is FunctionType &&
|
|
node.kind == FunctionAccessKind.Function) {
|
|
throw 'Node ${node.runtimeType}: $node at ${node.location} has receiver'
|
|
' static type $receiverType, but kind ${node.kind}';
|
|
}
|
|
}
|
|
|
|
@override
|
|
visitEqualsCall(EqualsCall node) {
|
|
super.visitEqualsCall(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 (hasGenericCovariantParameters(node.interfaceTarget)) {
|
|
annotateWithReceiver(node, node.left);
|
|
}
|
|
}
|
|
|
|
/// 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.isCovariantByClass);
|
|
|
|
/// 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.isCovariantByClass;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|