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

Side by Side Diff: pkg/compiler/lib/src/resolution/send_resolver.dart

Issue 1306143002: Remove SendResolver.computeSendStructure. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Fix handling of invalid this access. Created 5 years, 3 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 library dart2js.semantics_visitor.resolver; 5 library dart2js.semantics_visitor.resolver;
6 6
7 import '../constants/expressions.dart'; 7 import '../constants/expressions.dart';
8 import '../dart_types.dart'; 8 import '../dart_types.dart';
9 import '../diagnostics/invariant.dart' show
10 invariant;
11 import '../diagnostics/messages.dart' show 9 import '../diagnostics/messages.dart' show
12 MessageKind; 10 MessageKind;
13 import '../diagnostics/spannable.dart' show 11 import '../diagnostics/spannable.dart' show
14 Spannable, 12 Spannable,
15 SpannableAssertionFailure; 13 SpannableAssertionFailure;
16 import '../elements/elements.dart'; 14 import '../elements/elements.dart';
17 import '../tree/tree.dart'; 15 import '../tree/tree.dart';
18 import '../universe/universe.dart'; 16 import '../universe/universe.dart';
19 17
20 import 'access_semantics.dart'; 18 import 'access_semantics.dart';
21 import 'operators.dart';
22 import 'semantic_visitor.dart'; 19 import 'semantic_visitor.dart';
23 import 'send_structure.dart'; 20 import 'send_structure.dart';
24 import 'tree_elements.dart'; 21 import 'tree_elements.dart';
25 22
26 enum SendStructureKind {
27 GET,
28 SET,
29 INVOKE,
30 UNARY,
31 NOT,
32 BINARY,
33 EQ,
34 NOT_EQ,
35 COMPOUND,
36 INDEX,
37 INDEX_SET,
38 COMPOUND_INDEX_SET,
39 PREFIX,
40 POSTFIX,
41 INDEX_PREFIX,
42 INDEX_POSTFIX,
43 }
44
45 abstract class SendResolverMixin { 23 abstract class SendResolverMixin {
46 TreeElements get elements; 24 TreeElements get elements;
47 25
48 internalError(Spannable spannable, String message); 26 internalError(Spannable spannable, String message);
49 27
50 AccessSemantics handleCompoundErroneousSetterAccess(
51 Send node,
52 Element setter,
53 Element getter) {
54 assert(invariant(node, Elements.isUnresolved(setter),
55 message: "Unexpected erreneous compound setter: $setter."));
56 if (getter.isStatic) {
57 if (getter.isGetter) {
58 return new CompoundAccessSemantics(
59 CompoundAccessKind.UNRESOLVED_STATIC_SETTER, getter, setter);
60 } else if (getter.isField) {
61 // TODO(johnniwinther): Handle const field separately.
62 assert(invariant(node, getter.isFinal || getter.isConst,
63 message: "Field expected to be final or const."));
64 return new StaticAccess.finalStaticField(getter);
65 } else if (getter.isFunction) {
66 return new StaticAccess.staticMethod(getter);
67 } else {
68 return internalError(node,
69 "Unexpected erroneous static compound: getter=$getter");
70 }
71 } else if (getter.isTopLevel) {
72 if (getter.isGetter) {
73 return new CompoundAccessSemantics(
74 CompoundAccessKind.UNRESOLVED_TOPLEVEL_SETTER, getter, setter);
75 } else if (getter.isField) {
76 // TODO(johnniwinther): Handle const field separately.
77 assert(invariant(node, getter.isFinal || getter.isConst,
78 message: "Field expected to be final or const."));
79 return new StaticAccess.finalTopLevelField(getter);
80 } else if (getter.isFunction) {
81 return new StaticAccess.topLevelMethod(getter);
82 } else {
83 return internalError(node,
84 "Unexpected erroneous top level compound: getter=$getter");
85 }
86 } else if (getter.isParameter) {
87 assert(invariant(node, getter.isFinal,
88 message: "Parameter expected to be final."));
89 return new StaticAccess.finalParameter(getter);
90 } else if (getter.isLocal) {
91 if (getter.isVariable) {
92 // TODO(johnniwinther): Handle const variable separately.
93 assert(invariant(node, getter.isFinal || getter.isConst,
94 message: "Variable expected to be final or const."));
95 return new StaticAccess.finalLocalVariable(getter);
96 } else if (getter.isFunction) {
97 return new StaticAccess.localFunction(getter);
98 } else {
99 return internalError(node,
100 "Unexpected erroneous local compound: getter=$getter");
101 }
102 } else if (getter.isErroneous) {
103 return new StaticAccess.unresolved(getter);
104 } else {
105 return internalError(node,
106 "Unexpected erroneous compound: getter=$getter");
107 }
108 }
109
110 AccessSemantics handleStaticallyResolvedAccess(
111 Send node,
112 Element element,
113 Element getter,
114 {bool isCompound}) {
115 if (element == null) {
116 assert(invariant(node, isCompound, message:
117 "Non-compound static access without element."));
118 assert(invariant(node, getter != null, message:
119 "Compound static access without element."));
120 return handleCompoundErroneousSetterAccess(node, element, getter);
121 }
122 if (element.isErroneous) {
123 if (isCompound) {
124 return handleCompoundErroneousSetterAccess(node, element, getter);
125 }
126 return new StaticAccess.unresolved(element);
127 } else if (element.isParameter) {
128 if (element.isFinal) {
129 return new StaticAccess.finalParameter(element);
130 } else {
131 return new StaticAccess.parameter(element);
132 }
133 } else if (element.isLocal) {
134 if (element.isFunction) {
135 return new StaticAccess.localFunction(element);
136 } else if (element.isFinal || element.isConst) {
137 return new StaticAccess.finalLocalVariable(element);
138 } else {
139 return new StaticAccess.localVariable(element);
140 }
141 } else if (element.isStatic) {
142 if (element.isField) {
143 if (element.isFinal || element.isConst) {
144 // TODO(johnniwinther): Handle const field separately.
145 return new StaticAccess.finalStaticField(element);
146 }
147 return new StaticAccess.staticField(element);
148 } else if (element.isGetter) {
149 if (isCompound) {
150 return new CompoundAccessSemantics(
151 CompoundAccessKind.UNRESOLVED_STATIC_SETTER, element, null);
152 }
153 return new StaticAccess.staticGetter(element);
154 } else if (element.isSetter) {
155 if (getter != null) {
156 CompoundAccessKind accessKind;
157 if (getter.isErroneous) {
158 accessKind = CompoundAccessKind.UNRESOLVED_STATIC_GETTER;
159 } else if (getter.isAbstractField) {
160 AbstractFieldElement abstractField = getter;
161 if (abstractField.getter == null) {
162 accessKind = CompoundAccessKind.UNRESOLVED_STATIC_GETTER;
163 } else {
164 // TODO(johnniwinther): This might be dead code.
165 getter = abstractField.getter;
166 accessKind = CompoundAccessKind.STATIC_GETTER_SETTER;
167 }
168 } else if (getter.isGetter) {
169 accessKind = CompoundAccessKind.STATIC_GETTER_SETTER;
170 } else {
171 accessKind = CompoundAccessKind.STATIC_METHOD_SETTER;
172 }
173 return new CompoundAccessSemantics(
174 accessKind, getter, element);
175 } else {
176 return new StaticAccess.staticSetter(element);
177 }
178 } else {
179 return new StaticAccess.staticMethod(element);
180 }
181 } else if (element.isTopLevel) {
182 if (element.isField) {
183 if (element.isFinal || element.isConst) {
184 // TODO(johnniwinther): Handle const field separately.
185 return new StaticAccess.finalTopLevelField(element);
186 }
187 return new StaticAccess.topLevelField(element);
188 } else if (element.isGetter) {
189 return new StaticAccess.topLevelGetter(element);
190 } else if (element.isSetter) {
191 if (getter != null) {
192 CompoundAccessKind accessKind;
193 if (getter.isErroneous) {
194 accessKind = CompoundAccessKind.UNRESOLVED_TOPLEVEL_GETTER;
195 } else if (getter.isAbstractField) {
196 AbstractFieldElement abstractField = getter;
197 if (abstractField.getter == null) {
198 accessKind = CompoundAccessKind.UNRESOLVED_TOPLEVEL_GETTER;
199 } else {
200 // TODO(johnniwinther): This might be dead code.
201 getter = abstractField.getter;
202 accessKind = CompoundAccessKind.TOPLEVEL_GETTER_SETTER;
203 }
204 } else if (getter.isGetter) {
205 accessKind = CompoundAccessKind.TOPLEVEL_GETTER_SETTER;
206 } else {
207 accessKind = CompoundAccessKind.TOPLEVEL_METHOD_SETTER;
208 }
209 return new CompoundAccessSemantics(
210 accessKind, getter, element);
211 } else {
212 return new StaticAccess.topLevelSetter(element);
213 }
214 } else {
215 return new StaticAccess.topLevelMethod(element);
216 }
217 } else {
218 return internalError(
219 node, "Unhandled resolved property access: $element");
220 }
221 }
222
223 SendStructure computeSendStructure(Send node) {
224 SendStructure sendStructure = elements.getSendStructure(node);
225 if (sendStructure != null) {
226 return sendStructure;
227 }
228
229 if (elements.isAssert(node)) {
230 return internalError(node, "Unexpected assert.");
231 }
232
233 AssignmentOperator assignmentOperator;
234 BinaryOperator binaryOperator;
235 IncDecOperator incDecOperator;
236
237 if (node.isOperator) {
238 String operatorText = node.selector.asOperator().source;
239 if (operatorText == 'is') {
240 return internalError(node, "Unexpected is test.");
241 } else if (operatorText == 'as') {
242 return internalError(node, "Unexpected as cast.");
243 } else if (operatorText == '&&') {
244 return internalError(node, "Unexpected logical and.");
245 } else if (operatorText == '||') {
246 return internalError(node, "Unexpected logical or.");
247 } else if (operatorText == '??') {
248 return internalError(node, "Unexpected if-null.");
249 }
250 }
251
252 SendStructureKind kind;
253
254 if (node.asSendSet() != null) {
255 SendSet sendSet = node.asSendSet();
256 String operatorText = sendSet.assignmentOperator.source;
257 if (sendSet.isPrefix || sendSet.isPostfix) {
258 kind = sendSet.isPrefix
259 ? SendStructureKind.PREFIX
260 : SendStructureKind.POSTFIX;
261 incDecOperator = IncDecOperator.parse(operatorText);
262 if (incDecOperator == null) {
263 return internalError(
264 node, "No inc/dec operator for '$operatorText'.");
265 }
266 } else {
267 assignmentOperator = AssignmentOperator.parse(operatorText);
268 if (assignmentOperator != null) {
269 switch (assignmentOperator.kind) {
270 case AssignmentOperatorKind.ASSIGN:
271 kind = SendStructureKind.SET;
272 break;
273 default:
274 kind = SendStructureKind.COMPOUND;
275 }
276 } else {
277 return internalError(
278 node, "No assignment operator for '$operatorText'.");
279 }
280 }
281 } else if (!node.isPropertyAccess) {
282 kind = SendStructureKind.INVOKE;
283 } else {
284 kind = SendStructureKind.GET;
285 }
286
287 if (node.isOperator) {
288 String operatorText = node.selector.asOperator().source;
289 if (node.arguments.isEmpty) {
290 return internalError(node, "Unexpected unary $operatorText.");
291 } else {
292 binaryOperator = BinaryOperator.parse(operatorText);
293 if (binaryOperator != null) {
294 switch (binaryOperator.kind) {
295 case BinaryOperatorKind.EQ:
296 kind = SendStructureKind.EQ;
297 return internalError(node, "Unexpected binary $kind.");
298 case BinaryOperatorKind.NOT_EQ:
299 kind = SendStructureKind.NOT_EQ;
300 return internalError(node, "Unexpected binary $kind.");
301 case BinaryOperatorKind.INDEX:
302 if (node.isPrefix) {
303 kind = SendStructureKind.INDEX_PREFIX;
304 } else if (node.isPostfix) {
305 kind = SendStructureKind.INDEX_POSTFIX;
306 } else if (node.arguments.tail.isEmpty) {
307 // a[b]
308 kind = SendStructureKind.INDEX;
309 return internalError(node, "Unexpected binary $kind.");
310 } else {
311 if (kind == SendStructureKind.COMPOUND) {
312 // a[b] += c
313 kind = SendStructureKind.COMPOUND_INDEX_SET;
314 } else {
315 // a[b] = c
316 kind = SendStructureKind.INDEX_SET;
317 }
318 }
319 break;
320 default:
321 kind = SendStructureKind.BINARY;
322 return internalError(node, "Unexpected binary $kind.");
323 }
324 } else {
325 return internalError(
326 node, "Unexpected invalid binary $operatorText.");
327 }
328 }
329 }
330 AccessSemantics semantics = computeAccessSemantics(
331 node,
332 isSet: kind == SendStructureKind.SET,
333 isInvoke: kind == SendStructureKind.INVOKE,
334 isCompound: kind == SendStructureKind.COMPOUND ||
335 kind == SendStructureKind.COMPOUND_INDEX_SET ||
336 kind == SendStructureKind.PREFIX ||
337 kind == SendStructureKind.POSTFIX ||
338 kind == SendStructureKind.INDEX_PREFIX ||
339 kind == SendStructureKind.INDEX_POSTFIX);
340 if (semantics == null) {
341 return internalError(node, 'No semantics for $node');
342 }
343 Selector selector = elements.getSelector(node);
344 switch (kind) {
345 case SendStructureKind.GET:
346 return new GetStructure(semantics, selector);
347 case SendStructureKind.SET:
348 return new SetStructure(semantics, selector);
349 case SendStructureKind.INVOKE:
350 switch (semantics.kind) {
351 case AccessKind.STATIC_METHOD:
352 case AccessKind.SUPER_METHOD:
353 case AccessKind.TOPLEVEL_METHOD:
354 // TODO(johnniwinther): Should local function also be handled here?
355 FunctionElement function = semantics.element;
356 FunctionSignature signature = function.functionSignature;
357 if (!selector.callStructure.signatureApplies(signature)) {
358 return new IncompatibleInvokeStructure(semantics, selector);
359 }
360 break;
361 default:
362 break;
363 }
364 return new InvokeStructure(semantics, selector);
365 case SendStructureKind.UNARY:
366 return internalError(node, "Unexpected unary.");
367 case SendStructureKind.NOT:
368 return internalError(node, "Unexpected not.");
369 case SendStructureKind.BINARY:
370 return internalError(node, "Unexpected binary.");
371 case SendStructureKind.INDEX:
372 return internalError(node, "Unexpected index.");
373 case SendStructureKind.EQ:
374 return internalError(node, "Unexpected equals.");
375 case SendStructureKind.NOT_EQ:
376 return internalError(node, "Unexpected not equals.");
377 case SendStructureKind.COMPOUND:
378 Selector getterSelector =
379 elements.getGetterSelectorInComplexSendSet(node);
380 return new CompoundStructure(
381 semantics,
382 assignmentOperator,
383 getterSelector,
384 selector);
385 case SendStructureKind.INDEX_SET:
386 return new IndexSetStructure(semantics, selector);
387 case SendStructureKind.COMPOUND_INDEX_SET:
388 Selector getterSelector =
389 elements.getGetterSelectorInComplexSendSet(node);
390 return new CompoundIndexSetStructure(
391 semantics,
392 assignmentOperator,
393 getterSelector,
394 selector);
395 case SendStructureKind.INDEX_PREFIX:
396 Selector getterSelector =
397 elements.getGetterSelectorInComplexSendSet(node);
398 return new IndexPrefixStructure(
399 semantics,
400 incDecOperator,
401 getterSelector,
402 selector);
403 case SendStructureKind.INDEX_POSTFIX:
404 Selector getterSelector =
405 elements.getGetterSelectorInComplexSendSet(node);
406 return new IndexPostfixStructure(
407 semantics,
408 incDecOperator,
409 getterSelector,
410 selector);
411 case SendStructureKind.PREFIX:
412 Selector getterSelector =
413 elements.getGetterSelectorInComplexSendSet(node);
414 return new PrefixStructure(
415 semantics,
416 incDecOperator,
417 getterSelector,
418 selector);
419 case SendStructureKind.POSTFIX:
420 Selector getterSelector =
421 elements.getGetterSelectorInComplexSendSet(node);
422 return new PostfixStructure(
423 semantics,
424 incDecOperator,
425 getterSelector,
426 selector);
427 }
428 }
429
430 AccessSemantics computeAccessSemantics(Send node,
431 {bool isSet: false,
432 bool isInvoke: false,
433 bool isCompound: false}) {
434 Element element = elements[node];
435 Element getter = isCompound ? elements[node.selector] : null;
436 if (elements.isTypeLiteral(node)) {
437 DartType dartType = elements.getTypeLiteralType(node);
438 // TODO(johnniwinther): Handle deferred constants. There are runtime
439 // but not compile-time constants and should have their own
440 // [DeferredConstantExpression] class.
441 ConstantExpression constant = elements.getConstant(
442 isInvoke || isSet || isCompound ? node.selector : node);
443 switch (dartType.kind) {
444 case TypeKind.INTERFACE:
445 return new ConstantAccess.classTypeLiteral(constant);
446 case TypeKind.TYPEDEF:
447 return new ConstantAccess.typedefTypeLiteral(constant);
448 case TypeKind.TYPE_VARIABLE:
449 return new StaticAccess.typeParameterTypeLiteral(dartType.element);
450 case TypeKind.DYNAMIC:
451 return new ConstantAccess.dynamicTypeLiteral(constant);
452 default:
453 return internalError(node, "Unexpected type literal type: $dartType");
454 }
455 } else if (node.isSuperCall) {
456 if (Elements.isUnresolved(element)) {
457 if (isCompound) {
458 if (Elements.isUnresolved(getter)) {
459 // TODO(johnniwinther): Ensure that [getter] is not null. This
460 // happens in the case of missing super getter.
461 return new StaticAccess.unresolvedSuper(element);
462 } else if (getter.isField) {
463 assert(invariant(node, getter.isFinal,
464 message: "Super field expected to be final."));
465 return new StaticAccess.superFinalField(getter);
466 } else if (getter.isFunction) {
467 if (node.isIndex) {
468 return new CompoundAccessSemantics(
469 CompoundAccessKind.UNRESOLVED_SUPER_SETTER, getter, element);
470 } else {
471 return new StaticAccess.superMethod(getter);
472 }
473 } else {
474 return new CompoundAccessSemantics(
475 CompoundAccessKind.UNRESOLVED_SUPER_SETTER, getter, element);
476 }
477 } else {
478 return new StaticAccess.unresolvedSuper(element);
479 }
480 } else if (isCompound && Elements.isUnresolved(getter)) {
481 // TODO(johnniwinther): Ensure that [getter] is not null. This happens
482 // in the case of missing super getter.
483 return new CompoundAccessSemantics(
484 CompoundAccessKind.UNRESOLVED_SUPER_GETTER, getter, element);
485 } else if (element.isField) {
486 if (getter != null && getter != element) {
487 CompoundAccessKind accessKind;
488 if (getter.isField) {
489 accessKind = CompoundAccessKind.SUPER_FIELD_FIELD;
490 } else if (getter.isGetter) {
491 accessKind = CompoundAccessKind.SUPER_GETTER_FIELD;
492 } else {
493 return internalError(node,
494 "Unsupported super call: $node : $element/$getter.");
495 }
496 return new CompoundAccessSemantics(accessKind, getter, element);
497 } else if (element.isFinal) {
498 return new StaticAccess.superFinalField(element);
499 }
500 return new StaticAccess.superField(element);
501 } else if (element.isGetter) {
502 return new StaticAccess.superGetter(element);
503 } else if (element.isSetter) {
504 if (getter != null) {
505 CompoundAccessKind accessKind;
506 if (getter.isField) {
507 accessKind = CompoundAccessKind.SUPER_FIELD_SETTER;
508 } else if (getter.isGetter) {
509 accessKind = CompoundAccessKind.SUPER_GETTER_SETTER;
510 } else {
511 accessKind = CompoundAccessKind.SUPER_METHOD_SETTER;
512 }
513 return new CompoundAccessSemantics(accessKind, getter, element);
514 }
515 return new StaticAccess.superSetter(element);
516 } else if (isCompound) {
517 return new CompoundAccessSemantics(
518 CompoundAccessKind.SUPER_GETTER_SETTER, getter, element);
519 } else {
520 return new StaticAccess.superMethod(element);
521 }
522 } else if (node.isConditional) {
523 // Conditional sends (e?.x) are treated as dynamic property reads because
524 // they are equivalent to do ((a) => a == null ? null : a.x)(e). If `e` is
525 // a type `A`, this is equivalent to write `(A).x`.
526 return const DynamicAccess.ifNotNullProperty();
527 } else if (node.isOperator) {
528 return const DynamicAccess.dynamicProperty();
529 } else if (Elements.isClosureSend(node, element)) {
530 if (element == null) {
531 if (node.selector.isThis()) {
532 return new DynamicAccess.thisAccess();
533 } else {
534 return new DynamicAccess.expression();
535 }
536 } else if (Elements.isErroneous(element)) {
537 return new StaticAccess.unresolved(element);
538 } else {
539 return handleStaticallyResolvedAccess(
540 node, element, getter, isCompound: isCompound);
541 }
542 } else {
543 bool isDynamicAccess(Element e) => e == null || e.isInstanceMember;
544
545 if (isDynamicAccess(element) &&
546 (!isCompound || isDynamicAccess(getter))) {
547 if (node.receiver == null || node.receiver.isThis()) {
548 return const DynamicAccess.thisProperty();
549 } else {
550 return const DynamicAccess.dynamicProperty();
551 }
552 } else if (element != null && element.impliesType) {
553 // TODO(johnniwinther): Provide an [ErroneousElement].
554 // This happens for code like `C.this`.
555 return new StaticAccess.unresolved(null);
556 } else {
557 return handleStaticallyResolvedAccess(
558 node, element, getter, isCompound: isCompound);
559 }
560 }
561 }
562
563 ConstructorAccessSemantics computeConstructorAccessSemantics( 28 ConstructorAccessSemantics computeConstructorAccessSemantics(
564 ConstructorElement constructor, 29 ConstructorElement constructor,
565 CallStructure callStructure, 30 CallStructure callStructure,
566 DartType type, 31 DartType type,
567 {bool mustBeConstant: false}) { 32 {bool mustBeConstant: false}) {
568 if (mustBeConstant && !constructor.isConst) { 33 if (mustBeConstant && !constructor.isConst) {
569 return new ConstructorAccessSemantics( 34 return new ConstructorAccessSemantics(
570 ConstructorAccessKind.NON_CONSTANT_CONSTRUCTOR, constructor, type); 35 ConstructorAccessKind.NON_CONSTANT_CONSTRUCTOR, constructor, type);
571 } 36 }
572 if (constructor.isErroneous) { 37 if (constructor.isErroneous) {
(...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after
1004 return internalError(node, "Unexpected variable $element."); 469 return internalError(node, "Unexpected variable $element.");
1005 } 470 }
1006 if (element.isConst) { 471 if (element.isConst) {
1007 ConstantExpression constant = elements.getConstant(element.initializer); 472 ConstantExpression constant = elements.getConstant(element.initializer);
1008 return new ConstantVariableStructure(kind, node, element, constant); 473 return new ConstantVariableStructure(kind, node, element, constant);
1009 } else { 474 } else {
1010 return new NonConstantVariableStructure(kind, node, element); 475 return new NonConstantVariableStructure(kind, node, element);
1011 } 476 }
1012 } 477 }
1013 } 478 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/resolution/semantic_visitor.dart ('k') | tests/compiler/dart2js/semantic_visitor_test_send_data.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698