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

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

Issue 996263002: Don't generate forwarding hooks if all noSuchMethod implementations (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: fix typo 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 String param = element.parameters.single.name;
118 Statement body = element.node.body;
119 Expression expr;
120 if (body is Return && body.isArrowBody) {
121 expr = body.expression;
122 } else if (body is Block &&
123 !body.statements.isEmpty &&
124 body.statements.nodes.tail.isEmpty) {
125 Statement stmt = body.statements.nodes.head;
126 if (stmt is Return && stmt.hasExpression) {
127 expr = stmt.expression;
128 }
129 }
130 if (expr is Send &&
131 expr.isSuperCall &&
132 expr.selector is Identifier &&
133 (expr.selector as Identifier).source == Compiler.NO_SUCH_METHOD) {
134 var arg = expr.arguments.head;
135 if (arg is Send &&
136 arg.argumentsNode == null &&
137 arg.receiver == null &&
138 arg.selector is Identifier &&
139 arg.selector.source == param) {
140 return true;
141 }
142 }
143 return false;
144 }
145
146 bool isThrowing(FunctionElement element) {
147 Statement body = element.node.body;
148 if (body is Return && body.isArrowBody) {
149 if (body.expression is Throw) {
150 return true;
151 }
152 } else if (body is Block &&
153 !body.statements.isEmpty &&
154 body.statements.nodes.tail.isEmpty) {
155 if (body.statements.nodes.head is Throw) {
156 return true;
157 }
158 }
159 return false;
160 }
161 }
162
163 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