mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 08:44:27 +00:00
Add CFE support for noSuchMethod forwarders
Bug: https://github.com/dart-lang/sdk/issues/31424 Change-Id: Iaf3a8d6b090bda667a9a01c2d8413f8d5dd6d5a8 Reviewed-on: https://dart-review.googlesource.com/47780 Reviewed-by: Samir Jindel <sjindel@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com> Commit-Queue: Dmitry Stefantsov <dmitryas@google.com>
This commit is contained in:
parent
014bd821e6
commit
4989976a81
6 changed files with 103 additions and 1 deletions
|
@ -27,7 +27,9 @@ import 'package:kernel/ast.dart'
|
|||
|
||||
import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
|
||||
|
||||
import 'package:kernel/type_algebra.dart' show Substitution;
|
||||
import 'package:kernel/clone.dart' show CloneWithoutBody;
|
||||
|
||||
import 'package:kernel/type_algebra.dart' show Substitution, getSubstitutionMap;
|
||||
|
||||
import 'package:kernel/type_environment.dart' show TypeEnvironment;
|
||||
|
||||
|
@ -51,6 +53,8 @@ import '../fasta_codes.dart'
|
|||
templateOverrideTypeVariablesMismatch,
|
||||
templateRedirectionTargetNotFound;
|
||||
|
||||
import '../names.dart' show noSuchMethodName;
|
||||
|
||||
import '../problems.dart' show unexpected, unhandled, unimplemented;
|
||||
|
||||
import '../type_inference/type_schema.dart' show UnknownType;
|
||||
|
@ -284,6 +288,72 @@ abstract class KernelClassBuilder
|
|||
});
|
||||
}
|
||||
|
||||
// TODO(dmitryas): Find a better place for this routine.
|
||||
static bool hasUserDefinedNoSuchMethod(
|
||||
Class klass, ClassHierarchy hierarchy) {
|
||||
Member noSuchMethod = hierarchy.getDispatchTarget(klass, noSuchMethodName);
|
||||
// `Object` doesn't have a superclass reference.
|
||||
return noSuchMethod != null &&
|
||||
noSuchMethod.enclosingClass.superclass != null;
|
||||
}
|
||||
|
||||
void addNoSuchMethodForwarderForProcedure(
|
||||
Procedure procedure, ClassHierarchy hierarchy) {
|
||||
CloneWithoutBody cloner = new CloneWithoutBody(
|
||||
typeSubstitution: getSubstitutionMap(
|
||||
hierarchy.getClassAsInstanceOf(cls, procedure.enclosingClass)));
|
||||
Procedure cloned = cloner.clone(procedure);
|
||||
cloned.isAbstract = true;
|
||||
cloned.isNoSuchMethodForwarder = true;
|
||||
|
||||
String name = cloned.name.name;
|
||||
cls.procedures.add(cloned);
|
||||
cloned.parent = cls;
|
||||
DillMemberBuilder memberBuilder = new DillMemberBuilder(cloned, this);
|
||||
memberBuilder.next = scopeBuilder[name];
|
||||
scopeBuilder.addMember(name, memberBuilder);
|
||||
}
|
||||
|
||||
void addNoSuchMethodForwarders(ClassHierarchy hierarchy) {
|
||||
if (!hasUserDefinedNoSuchMethod(cls, hierarchy)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Set<Name> existingForwardersNames = new Set<Name>();
|
||||
if (cls.superclass != null &&
|
||||
hasUserDefinedNoSuchMethod(cls.superclass, hierarchy)) {
|
||||
List<Member> concrete = hierarchy.getDispatchTargets(cls.superclass);
|
||||
for (Member member in hierarchy.getInterfaceMembers(cls.superclass)) {
|
||||
if (ClassHierarchy.findMemberByName(concrete, member.name) == null) {
|
||||
existingForwardersNames.add(member.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cls.mixedInClass != null &&
|
||||
hasUserDefinedNoSuchMethod(cls.mixedInClass, hierarchy)) {
|
||||
List<Member> concrete = hierarchy.getDispatchTargets(cls.mixedInClass);
|
||||
for (Member member in hierarchy.getInterfaceMembers(cls.mixedInClass)) {
|
||||
if (ClassHierarchy.findMemberByName(concrete, member.name) == null) {
|
||||
existingForwardersNames.add(member.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<Member> concrete = hierarchy.getDispatchTargets(cls);
|
||||
List<Member> declared = hierarchy.getDeclaredMembers(cls);
|
||||
for (Member member in hierarchy.getInterfaceMembers(cls)) {
|
||||
if (ClassHierarchy.findMemberByName(concrete, member.name) == null &&
|
||||
!existingForwardersNames.contains(member.name)) {
|
||||
if (ClassHierarchy.findMemberByName(declared, member.name) != null) {
|
||||
Procedure procedure = member;
|
||||
procedure.isNoSuchMethodForwarder = true;
|
||||
} else {
|
||||
addNoSuchMethodForwarderForProcedure(member, hierarchy);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Uri _getMemberUri(Member member) {
|
||||
if (member is Field) return member.fileUri;
|
||||
if (member is Procedure) return member.fileUri;
|
||||
|
|
|
@ -264,6 +264,9 @@ class KernelTarget extends TargetImplementation {
|
|||
loader.performTopLevelInference(myClasses);
|
||||
}
|
||||
loader.checkOverrides(myClasses);
|
||||
if (backendTarget.enableNoSuchMethodForwarders) {
|
||||
loader.addNoSuchMethodForwarders(myClasses);
|
||||
}
|
||||
} on deprecated_InputError catch (e) {
|
||||
ticker.logMs("Got deprecated_InputError");
|
||||
handleInputError(e, isFullComponent: false);
|
||||
|
|
|
@ -632,6 +632,15 @@ class SourceLoader<L> extends Loader<L> {
|
|||
ticker.logMs("Checked overrides");
|
||||
}
|
||||
|
||||
void addNoSuchMethodForwarders(List<SourceClassBuilder> sourceClasses) {
|
||||
for (SourceClassBuilder builder in sourceClasses) {
|
||||
if (builder.library.loader == this) {
|
||||
builder.addNoSuchMethodForwarders(hierarchy);
|
||||
}
|
||||
}
|
||||
ticker.logMs("Added noSuchMethod forwarders");
|
||||
}
|
||||
|
||||
void createTypeInferenceEngine() {
|
||||
typeInferenceEngine =
|
||||
new ShadowTypeInferenceEngine(instrumentation, target.strongMode);
|
||||
|
|
|
@ -76,6 +76,15 @@ abstract class Target {
|
|||
/// promotion do not slow down compilation too much.
|
||||
bool get disableTypeInference => false;
|
||||
|
||||
/// A derived class may change this to `true` to enable forwarders to
|
||||
/// user-defined `noSuchMethod` that are generated for each abstract member
|
||||
/// if such `noSuchMethod` is present.
|
||||
///
|
||||
/// The forwarders are abstract [Procedure]s with [isNoSuchMethodForwarder]
|
||||
/// bit set. The implementation of the behavior of such forwarders is up
|
||||
/// for the target backend.
|
||||
bool get enableNoSuchMethodForwarders => false;
|
||||
|
||||
/// A derived class may change this to `true` to enable Flutter specific
|
||||
/// "super-mixins" semantics.
|
||||
///
|
||||
|
|
|
@ -25,6 +25,9 @@ class VmTarget extends Target {
|
|||
@override
|
||||
bool get strongMode => flags.strongMode;
|
||||
|
||||
@override
|
||||
bool get enableNoSuchMethodForwarders => true;
|
||||
|
||||
@override
|
||||
String get name => 'vm';
|
||||
|
||||
|
|
|
@ -52,6 +52,9 @@ class B extends self::A {
|
|||
method noSuchMethod(core::Invocation invocation) → dynamic {
|
||||
return new self::T1::•();
|
||||
}
|
||||
abstract no-such-method-forwarder get bar() → dynamic;
|
||||
abstract no-such-method-forwarder method foo() → dynamic;
|
||||
abstract no-such-method-forwarder method bazz(dynamic a1, dynamic a2, dynamic a3, [dynamic a4, dynamic a5]) → dynamic;
|
||||
}
|
||||
class C extends core::Object {
|
||||
synthetic constructor •() → void
|
||||
|
@ -65,6 +68,9 @@ class D extends self::C implements self::A {
|
|||
synthetic constructor •() → void
|
||||
: super self::C::•()
|
||||
;
|
||||
abstract no-such-method-forwarder get bar() → dynamic;
|
||||
abstract no-such-method-forwarder method foo() → dynamic;
|
||||
abstract no-such-method-forwarder method bazz(dynamic a1, dynamic a2, dynamic a3, [dynamic a4, dynamic a5]) → dynamic;
|
||||
}
|
||||
class E extends core::Object implements self::A {
|
||||
synthetic constructor •() → void
|
||||
|
@ -75,6 +81,8 @@ class E extends core::Object implements self::A {
|
|||
method noSuchMethod(core::Invocation invocation) → dynamic {
|
||||
return new self::T4::•();
|
||||
}
|
||||
abstract no-such-method-forwarder get bar() → dynamic;
|
||||
abstract no-such-method-forwarder method bazz(dynamic a1, dynamic a2, dynamic a3, [dynamic a4, dynamic a5]) → dynamic;
|
||||
}
|
||||
class F extends core::Object {
|
||||
synthetic constructor •() → void
|
||||
|
|
Loading…
Reference in a new issue