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

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

Issue 1677423002: Revert "Fix super noSuchMethod handling." (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 4 years, 10 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
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of js_backend; 5 part of js_backend;
6 6
7 /** 7 /**
8 * Categorizes `noSuchMethod` implementations. 8 * Categorizes `noSuchMethod` implementations.
9 * 9 *
10 * If user code includes `noSuchMethod` implementations, type inference is 10 * If user code includes `noSuchMethod` implementations, type inference is
11 * hindered because (for instance) any selector where the type of the 11 * hindered because (for instance) any selector where the type of the
12 * receiver is not known all implementations of `noSuchMethod` must be taken 12 * receiver is not known all implementations of `noSuchMethod` must be taken
13 * into account when inferring the return type. 13 * into account when inferring the return type.
14 * 14 *
15 * The situation can be ameliorated with some heuristics for disregarding some 15 * The situation can be ameliorated with some heuristics for disregarding some
16 * `noSuchMethod` implementations during type inference. We can partition 16 * `noSuchMethod` implementations during type inference. We can partition
17 * `noSuchMethod` implementations into 4 categories. 17 * `noSuchMethod` implementations into 3 categories.
18 * 18 *
19 * Implementations in category A are the default implementations 19 * Implementations in category A are the default implementations
20 * `Object.noSuchMethod` and `Interceptor.noSuchMethod`. 20 * `Object.noSuchMethod` and `Interceptor.noSuchMethod`.
21 * 21 *
22 * Implementations in category B syntactically immediately throw, for example: 22 * Implementations in category B syntactically immediately throw, for example:
23 * 23 *
24 * noSuchMethod(x) => throw 'not implemented' 24 * noSuchMethod(x) => throw 'not implemented'
25 * 25 *
26 * Implementations in category C are not applicable, for example: 26 * Implementations that do not fall into category A or B are in category C. They
27 * 27 * are the only category of implementation that are considered during type
28 * noSuchMethod() { /* missing parameter */ }
29 * noSuchMethod(a, b) { /* too many parameters */ }
30 *
31 * Implementations that do not fall into category A, B or C are in category D.
32 * They are the only category of implementation that are considered during type
33 * inference. 28 * inference.
34 * 29 *
35 * Implementations that syntactically just forward to the super implementation, 30 * Implementations that syntactically just forward to the super implementation,
36 * for example: 31 * for example:
37 * 32 *
38 * noSuchMethod(x) => super.noSuchMethod(x); 33 * noSuchMethod(x) => super.noSuchMethod(x);
39 * 34 *
40 * are in the same category as the superclass implementation. This covers a 35 * are in the same category as the superclass implementation. This covers a
41 * common case, where users implement `noSuchMethod` with these dummy 36 * common case, where users implement `noSuchMethod` with these dummy
42 * implementations to avoid warnings. 37 * implementations to avoid warnings.
43 */ 38 */
44 class NoSuchMethodRegistry { 39 class NoSuchMethodRegistry {
45 /// The implementations that fall into category A, described above. 40 /// The implementations that fall into category A, described above.
46 final Set<FunctionElement> defaultImpls = new Set<FunctionElement>(); 41 final Set<FunctionElement> defaultImpls = new Set<FunctionElement>();
47 /// The implementations that fall into category B, described above. 42 /// The implementations that fall into category B, described above.
48 final Set<FunctionElement> throwingImpls = new Set<FunctionElement>(); 43 final Set<FunctionElement> throwingImpls = new Set<FunctionElement>();
49 /// The implementations that fall into category C, described above. 44 /// The implementations that fall into category C, described above.
50 final Set<FunctionElement> notApplicableImpls = new Set<FunctionElement>();
51 /// The implementations that fall into category D, described above.
52 final Set<FunctionElement> otherImpls = new Set<FunctionElement>(); 45 final Set<FunctionElement> otherImpls = new Set<FunctionElement>();
53 46
54 /// The implementations that fall into category D1 47 /// The implementations that fall into category C1
55 final Set<FunctionElement> complexNoReturnImpls = new Set<FunctionElement>(); 48 final Set<FunctionElement> complexNoReturnImpls = new Set<FunctionElement>();
56 /// The implementations that fall into category D2 49 /// The implementations that fall into category C2
57 final Set<FunctionElement> complexReturningImpls = new Set<FunctionElement>(); 50 final Set<FunctionElement> complexReturningImpls = new Set<FunctionElement>();
58 51
59 /// The implementations that have not yet been categorized. 52 /// The implementations that have not yet been categorized.
60 final Set<FunctionElement> _uncategorizedImpls = new Set<FunctionElement>(); 53 final Set<FunctionElement> _uncategorizedImpls = new Set<FunctionElement>();
61 54
62 final JavaScriptBackend _backend; 55 final JavaScriptBackend _backend;
63 final Compiler _compiler; 56 final Compiler _compiler;
64 57
65 NoSuchMethodRegistry(JavaScriptBackend backend) 58 NoSuchMethodRegistry(JavaScriptBackend backend)
66 : this._backend = backend, 59 : this._backend = backend,
67 this._compiler = backend.compiler; 60 this._compiler = backend.compiler;
68 61
69 DiagnosticReporter get reporter => _compiler.reporter; 62 DiagnosticReporter get reporter => _compiler.reporter;
70 63
71 bool get hasThrowingNoSuchMethod => throwingImpls.isNotEmpty; 64 bool get hasThrowingNoSuchMethod => throwingImpls.isNotEmpty;
72 bool get hasComplexNoSuchMethod => otherImpls.isNotEmpty; 65 bool get hasComplexNoSuchMethod => otherImpls.isNotEmpty;
73 66
74 void registerNoSuchMethod(FunctionElement noSuchMethodElement) { 67 void registerNoSuchMethod(FunctionElement noSuchMethodElement) {
75 _uncategorizedImpls.add(noSuchMethodElement); 68 _uncategorizedImpls.add(noSuchMethodElement);
76 } 69 }
77 70
78 void onQueueEmpty() { 71 void onQueueEmpty() {
79 _uncategorizedImpls.forEach(_categorizeImpl); 72 _uncategorizedImpls.forEach(_categorizeImpl);
80 _uncategorizedImpls.clear(); 73 _uncategorizedImpls.clear();
81 } 74 }
82 75
83 /// Now that type inference is complete, split category D into two 76 /// Now that type inference is complete, split category C into two
84 /// subcategories: D1, those that have no return type, and D2, those 77 /// subcategories: C1, those that have no return type, and C2, those
85 /// that have a return type. 78 /// that have a return type.
86 void onTypeInferenceComplete() { 79 void onTypeInferenceComplete() {
87 otherImpls.forEach(_subcategorizeOther); 80 otherImpls.forEach(_subcategorizeOther);
88 } 81 }
89 82
90 /// Emits a diagnostic 83 /// Emits a diagnostic
91 void emitDiagnostic() { 84 void emitDiagnostic() {
92 throwingImpls.forEach((e) { 85 throwingImpls.forEach((e) {
93 if (!_hasForwardingSyntax(e)) { 86 if (!_hasForwardingSyntax(e)) {
94 reporter.reportHintMessage( 87 reporter.reportHintMessage(
95 e, MessageKind.DIRECTLY_THROWING_NSM); 88 e, MessageKind.DIRECTLY_THROWING_NSM);
96 } 89 }
97 }); 90 });
98 complexNoReturnImpls.forEach((e) { 91 complexNoReturnImpls.forEach((e) {
99 if (!_hasForwardingSyntax(e)) { 92 if (!_hasForwardingSyntax(e)) {
100 reporter.reportHintMessage( 93 reporter.reportHintMessage(
101 e, MessageKind.COMPLEX_THROWING_NSM); 94 e, MessageKind.COMPLEX_THROWING_NSM);
102 } 95 }
103 }); 96 });
104 complexReturningImpls.forEach((e) { 97 complexReturningImpls.forEach((e) {
105 if (!_hasForwardingSyntax(e)) { 98 if (!_hasForwardingSyntax(e)) {
106 reporter.reportHintMessage( 99 reporter.reportHintMessage(
107 e, MessageKind.COMPLEX_RETURNING_NSM); 100 e, MessageKind.COMPLEX_RETURNING_NSM);
108 } 101 }
109 }); 102 });
110 } 103 }
111 104
112 /// Returns [true] if the given element is a complex [noSuchMethod] 105 /// Returns [true] if the given element is a complex [noSuchMethod]
113 /// implementation. An implementation is complex if it falls into 106 /// implementation. An implementation is complex if it falls into
114 /// category D, as described above. 107 /// category C, as described above.
115 bool isComplex(FunctionElement element) { 108 bool isComplex(FunctionElement element) {
116 assert(element.name == Identifiers.noSuchMethod_); 109 assert(element.name == Identifiers.noSuchMethod_);
117 return otherImpls.contains(element); 110 return otherImpls.contains(element);
118 } 111 }
119 112
120 _subcategorizeOther(FunctionElement element) { 113 _subcategorizeOther(FunctionElement element) {
121 TypeMask returnType = 114 TypeMask returnType =
122 _compiler.typesTask.getGuaranteedReturnTypeOfElement(element); 115 _compiler.typesTask.getGuaranteedReturnTypeOfElement(element);
123 if (returnType == const TypeMask.nonNullEmpty()) { 116 if (returnType == const TypeMask.nonNullEmpty()) {
124 complexNoReturnImpls.add(element); 117 complexNoReturnImpls.add(element);
125 } else { 118 } else {
126 complexReturningImpls.add(element); 119 complexReturningImpls.add(element);
127 } 120 }
128 } 121 }
129 122
130 NsmCategory _categorizeImpl(FunctionElement element) { 123 NsmCategory _categorizeImpl(FunctionElement element) {
131 assert(element.name == Identifiers.noSuchMethod_); 124 assert(element.name == Identifiers.noSuchMethod_);
132 if (defaultImpls.contains(element)) { 125 if (defaultImpls.contains(element)) {
133 return NsmCategory.DEFAULT; 126 return NsmCategory.DEFAULT;
134 } 127 }
135 if (throwingImpls.contains(element)) { 128 if (throwingImpls.contains(element)) {
136 return NsmCategory.THROWING; 129 return NsmCategory.THROWING;
137 } 130 }
138 if (otherImpls.contains(element)) { 131 if (otherImpls.contains(element)) {
139 return NsmCategory.OTHER; 132 return NsmCategory.OTHER;
140 } 133 }
141 if (notApplicableImpls.contains(element)) {
142 return NsmCategory.NOT_APPLICABLE;
143 }
144 if (!Selectors.noSuchMethod_.signatureApplies(element)) { 134 if (!Selectors.noSuchMethod_.signatureApplies(element)) {
145 notApplicableImpls.add(element); 135 otherImpls.add(element);
146 return NsmCategory.NOT_APPLICABLE; 136 return NsmCategory.OTHER;
147 } 137 }
148 if (_isDefaultNoSuchMethodImplementation(element)) { 138 if (_isDefaultNoSuchMethodImplementation(element)) {
149 defaultImpls.add(element); 139 defaultImpls.add(element);
150 return NsmCategory.DEFAULT; 140 return NsmCategory.DEFAULT;
151 } else if (_hasForwardingSyntax(element)) { 141 } else if (_hasForwardingSyntax(element)) {
152 // If the implementation is 'noSuchMethod(x) => super.noSuchMethod(x);' 142 // If the implementation is 'noSuchMethod(x) => super.noSuchMethod(x);'
153 // then it is in the same category as the super call. 143 // then it is in the same category as the super call.
154 Element superCall = 144 Element superCall = element.enclosingClass
155 element.enclosingClass.lookupSuperByName(Names.noSuchMethod_); 145 .lookupSuperByName(Selectors.noSuchMethod_.memberName);
156 NsmCategory category = _categorizeImpl(superCall); 146 NsmCategory category = _categorizeImpl(superCall);
157 switch(category) { 147 switch(category) {
158 case NsmCategory.DEFAULT: 148 case NsmCategory.DEFAULT:
159 defaultImpls.add(element); 149 defaultImpls.add(element);
160 break; 150 break;
161 case NsmCategory.THROWING: 151 case NsmCategory.THROWING:
162 throwingImpls.add(element); 152 throwingImpls.add(element);
163 break; 153 break;
164 case NsmCategory.OTHER: 154 case NsmCategory.OTHER:
165 otherImpls.add(element); 155 otherImpls.add(element);
166 break; 156 break;
167 case NsmCategory.NOT_APPLICABLE:
168 // If the super method is not applicable, the call is redirected to
169 // `Object.noSuchMethod`.
170 defaultImpls.add(element);
171 category = NsmCategory.DEFAULT;
172 break;
173 } 157 }
174 return category; 158 return category;
175 } else if (_hasThrowingSyntax(element)) { 159 } else if (_hasThrowingSyntax(element)) {
176 throwingImpls.add(element); 160 throwingImpls.add(element);
177 return NsmCategory.THROWING; 161 return NsmCategory.THROWING;
178 } else { 162 } else {
179 otherImpls.add(element); 163 otherImpls.add(element);
180 return NsmCategory.OTHER; 164 return NsmCategory.OTHER;
181 } 165 }
182 } 166 }
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
233 body.statements.nodes.tail.isEmpty) { 217 body.statements.nodes.tail.isEmpty) {
234 if (body.statements.nodes.head is ExpressionStatement) { 218 if (body.statements.nodes.head is ExpressionStatement) {
235 ExpressionStatement stmt = body.statements.nodes.head; 219 ExpressionStatement stmt = body.statements.nodes.head;
236 return stmt.expression is Throw; 220 return stmt.expression is Throw;
237 } 221 }
238 } 222 }
239 return false; 223 return false;
240 } 224 }
241 } 225 }
242 226
243 enum NsmCategory { 227 enum NsmCategory { DEFAULT, THROWING, OTHER }
244 DEFAULT,
245 THROWING,
246 NOT_APPLICABLE,
247 OTHER,
248 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/js_backend/js_backend.dart ('k') | pkg/compiler/lib/src/resolution/semantic_visitor.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698