Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(164)

Side by Side Diff: pkg/compiler/lib/src/js_backend/no_such_method_registry.dart

Issue 1020853004: Don't generate invocation mirror code if all noSuchMethods forward to (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: add test Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 part of js_backend;
6
7 /**
8 * Categorizes `noSuchMethod` implementations.
9 *
10 * If user code includes `noSuchMethod` implementations, type inference is
11 * hindered because (for instance) any selector where the type of the
12 * receiver is not known all implementations of `noSuchMethod` must be taken
13 * into account when inferring the return type.
14 *
15 * The situation can be ameliorated with some heuristics for disregarding some
16 * `noSuchMethod` implementations during type inference. We can partition
17 * `noSuchMethod` implementations into 3 categories.
18 *
19 * Implementations in category A are the default implementations
20 * `Object.noSuchMethod` and `Interceptor.noSuchMethod`.
21 *
22 * Implementations in category B syntactically immediately throw, for example:
23 *
24 * noSuchMethod(x) => throw 'not implemented'
25 *
26 * Implementations that do not fall into category A or B are in category C. They
27 * are the only category of implementation that are considered during type
28 * inference.
29 *
30 * Implementations that syntactically just forward to the super implementation,
31 * for example:
32 *
33 * noSuchMethod(x) => super.noSuchMethod(x);
34 *
35 * are in the same category as the superclass implementation. This covers a
36 * common case, where users implement `noSuchMethod` with these dummy
37 * implementations to avoid warnings.
38 */
39 class NoSuchMethodRegistry {
40 /// The implementations that fall into category A, described above.
41 final Set<FunctionElement> defaultImpls = new Set<FunctionElement>();
42 /// The implementations that fall into category B, described above.
43 final Set<FunctionElement> throwingImpls = new Set<FunctionElement>();
44 /// The implementations that fall into category C, described above.
45 final Set<Element> otherImpls = new Set<Element>();
46
47 /// The implementations that have not yet been categorized.
48 final Set<Element> uncategorizedImpls = new Set<Element>();
49
50 final JavaScriptBackend backend;
51 final Compiler compiler;
52
53 NoSuchMethodRegistry(JavaScriptBackend backend)
54 : this.backend = backend,
55 this.compiler = backend.compiler;
56
57 bool get hasThrowingNoSuchMethod => throwingImpls.isNotEmpty;
58 bool get hasComplexNoSuchMethod => otherImpls.isNotEmpty;
59
60 void registerNoSuchMethod(Element noSuchMethodElement) {
61 uncategorizedImpls.add(noSuchMethodElement);
62 }
63
64 void onQueueEmpty() {
65 uncategorizedImpls.forEach(_categorizeImpl);
66 uncategorizedImpls.clear();
67 }
68
69 NsmCategory _categorizeImpl(Element noSuchMethodElement) {
70 assert(noSuchMethodElement.name == Compiler.NO_SUCH_METHOD);
71 if (defaultImpls.contains(noSuchMethodElement)) {
72 return NsmCategory.DEFAULT;
73 }
74 if (throwingImpls.contains(noSuchMethodElement)) {
75 return NsmCategory.THROWING;
76 }
77 if (otherImpls.contains(noSuchMethodElement)) {
78 return NsmCategory.OTHER;
79 }
80 if (noSuchMethodElement is! FunctionElement ||
81 !compiler.noSuchMethodSelector.signatureApplies(noSuchMethodElement)) {
82 otherImpls.add(noSuchMethodElement);
83 return NsmCategory.OTHER;
84 }
85 FunctionElement noSuchMethodFunc = noSuchMethodElement as FunctionElement;
86 if (backend.isDefaultNoSuchMethodImplementation(noSuchMethodFunc)) {
87 defaultImpls.add(noSuchMethodFunc);
88 return NsmCategory.DEFAULT;
89 } else if (hasForwardingSyntax(noSuchMethodFunc)) {
90 // If the implementation is 'noSuchMethod(x) => super.noSuchMethod(x);'
91 // then it is in the same category as the super call.
92 Element superCall = noSuchMethodFunc.enclosingClass
93 .lookupSuperSelector(compiler.noSuchMethodSelector);
94 NsmCategory category = _categorizeImpl(superCall);
95 switch(category) {
96 case NsmCategory.DEFAULT:
97 defaultImpls.add(noSuchMethodFunc);
98 break;
99 case NsmCategory.THROWING:
100 throwingImpls.add(noSuchMethodFunc);
101 break;
102 case NsmCategory.OTHER:
103 otherImpls.add(noSuchMethodFunc);
104 break;
105 }
106 return category;
107 } else if (isThrowing(noSuchMethodFunc)) {
108 throwingImpls.add(noSuchMethodFunc);
109 return NsmCategory.THROWING;
110 } else {
111 otherImpls.add(noSuchMethodFunc);
112 return NsmCategory.OTHER;
113 }
114 }
115
116 bool hasForwardingSyntax(FunctionElement element) {
117 // At this point we know that this is signature-compatible with
118 // Object.noSuchMethod, but it may have more than one argument as long as
119 // it only has one required argument.
120 String param = element.parameters.first.name;
121 Statement body = element.node.body;
122 Expression expr;
123 if (body is Return && body.isArrowBody) {
124 expr = body.expression;
125 } else if (body is Block &&
126 !body.statements.isEmpty &&
127 body.statements.nodes.tail.isEmpty) {
128 Statement stmt = body.statements.nodes.head;
129 if (stmt is Return && stmt.hasExpression) {
130 expr = stmt.expression;
131 }
132 }
133 if (expr is Send &&
134 expr.isSuperCall &&
135 expr.selector is Identifier &&
136 (expr.selector as Identifier).source == Compiler.NO_SUCH_METHOD) {
137 var arg = expr.arguments.head;
138 if (expr.arguments.tail.isEmpty &&
139 arg is Send &&
140 arg.argumentsNode == null &&
141 arg.receiver == null &&
142 arg.selector is Identifier &&
143 arg.selector.source == param) {
144 return true;
145 }
146 }
147 return false;
148 }
149
150 bool isThrowing(FunctionElement element) {
151 Statement body = element.node.body;
152 if (body is Return && body.isArrowBody) {
153 if (body.expression is Throw) {
154 return true;
155 }
156 } else if (body is Block &&
157 !body.statements.isEmpty &&
158 body.statements.nodes.tail.isEmpty) {
159 if (body.statements.nodes.head is Throw) {
160 return true;
161 }
162 }
163 return false;
164 }
165 }
166
167 enum NsmCategory { DEFAULT, THROWING, OTHER }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/js_backend/js_backend.dart ('k') | pkg/compiler/lib/src/js_emitter/old_emitter/class_emitter.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698