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

Side by Side Diff: pkg/compiler/lib/src/kernel/kernel.dart

Issue 2265383002: Copy Rasta visitor to dart2js. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: missed some renames Created 4 years, 4 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
(Empty)
1 // Copyright (c) 2016, 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.md file.
4
5 import 'dart:collection' show Queue;
6
7 import 'package:kernel/ast.dart' as ir;
8 import 'package:kernel/checks.dart' show CheckParentPointers;
9 import 'package:kernel/frontend/super_calls.dart' show moveSuperCallLast;
10
11 import '../compiler.dart' show Compiler;
12 import '../constants/expressions.dart' show TypeConstantExpression;
13 import '../dart_types.dart'
14 show DartType, FunctionType, InterfaceType, TypeKind, TypeVariableType;
15 import '../diagnostics/messages.dart' show MessageKind;
16 import '../diagnostics/spannable.dart' show Spannable;
17 import '../elements/elements.dart'
18 show
19 ClassElement,
20 ConstructorElement,
21 Element,
22 FieldElement,
23 FunctionElement,
24 LibraryElement,
25 MixinApplicationElement,
26 TypeVariableElement;
27 import '../elements/modelx.dart' show ErroneousFieldElementX;
28 import '../tree/tree.dart' show FunctionExpression, Node;
29 import 'kernel_visitor.dart' show IrFunction, KernelVisitor;
30
31 typedef void WorkAction();
32
33 class WorkItem {
34 final Element element;
35 final WorkAction action;
36
37 WorkItem(this.element, this.action);
38 }
39
40 class Kernel {
41 final Compiler compiler;
42
43 final Map<LibraryElement, ir.Library> libraries =
44 <LibraryElement, ir.Library>{};
45
46 final Map<ClassElement, ir.Class> classes = <ClassElement, ir.Class>{};
47
48 final Map<FunctionElement, ir.Member> functions =
49 <FunctionElement, ir.Member>{};
50
51 final Map<FieldElement, ir.Field> fields = <FieldElement, ir.Field>{};
52
53 final Map<TypeVariableElement, ir.TypeParameter> typeParameters =
54 <TypeVariableElement, ir.TypeParameter>{};
55
56 final Map<TypeVariableElement, ir.TypeParameter> factoryTypeParameters =
57 <TypeVariableElement, ir.TypeParameter>{};
58
59 final Set<ir.TreeNode> checkedNodes = new Set<ir.TreeNode>();
60
61 final Map<LibraryElement, Map<String, int>> mixinApplicationNamesByLibrary =
62 <LibraryElement, Map<String, int>>{};
63
64 /// FIFO queue of work that needs to be completed before the returned AST
65 /// nodes are correct.
66 final Queue<WorkItem> workQueue = new Queue<WorkItem>();
67
68 Kernel(this.compiler);
69
70 void addWork(Element element, WorkAction action) {
71 workQueue.addLast(new WorkItem(element, action));
72 }
73
74 void checkMember(Element key, ir.TreeNode value) {
75 if (!checkedNodes.add(value)) return;
76 if (value.parent == null) {
77 internalError(key, "Missing parent on IR node.");
78 }
79 try {
80 CheckParentPointers.check(value);
81 } catch (e, s) {
82 internalError(key, "$e\n$s");
83 }
84 }
85
86 void checkLibrary(Element key, ir.Library library) {
87 if (!checkedNodes.add(library)) return;
88 CheckParentPointers.check(library);
89 }
90
91 void processWorkQueue() {
92 while (workQueue.isNotEmpty) {
93 WorkItem work = workQueue.removeFirst();
94 work.action();
95 }
96 assert(() {
97 libraries.forEach(checkLibrary);
98 classes.forEach(checkMember);
99 functions.forEach(checkMember);
100 fields.forEach(checkMember);
101 return true;
102 });
103 }
104
105 ir.Name irName(String name, Element element) {
106 ir.Library irLibrary = null;
107 if (name.startsWith("_")) {
108 ClassElement cls = element.enclosingClass;
109 if (cls != null && cls.isMixinApplication) {
110 MixinApplicationElement mixinApplication = cls;
111 element = mixinApplication.mixin;
112 }
113 irLibrary = libraryToIr(element.library);
114 }
115 return new ir.Name(name, irLibrary);
116 }
117
118 ir.Library libraryToIr(LibraryElement library) {
119 library = library.declaration;
120 return libraries.putIfAbsent(library, () {
121 String name = library.hasLibraryName ? library.libraryName : null;
122 ir.Library libraryNode = new ir.Library(library.canonicalUri,
123 name: name, classes: null, procedures: null, fields: null);
124 addWork(library, () {
125 Queue<ir.Class> classes = new Queue<ir.Class>();
126 Queue<ir.Member> members = new Queue<ir.Member>();
127 library.implementation.forEachLocalMember((Element e) {
128 if (e.isClass) {
129 classes.addFirst(classToIr(e));
130 } else if (e.isFunction || e.isAccessor) {
131 members.addFirst(functionToIr(e));
132 } else if (e.isField) {
133 members.addFirst(fieldToIr(e));
134 } else if (e.isTypedef) {
135 // Ignored, typedefs are unaliased on use.
136 } else {
137 internalError(e, "Unhandled library member: $e");
138 }
139 });
140 // The elements were inserted in reverse order as forEachLocalMember
141 // above gives them in reversed order.
142 classes.forEach(libraryNode.addClass);
143 members.forEach(libraryNode.addMember);
144 });
145 return libraryNode;
146 });
147 }
148
149 /// Compute a name for [cls]. We want to have unique names in a library, but
150 /// mixin applications can lead to multiple classes with the same name. So
151 /// for those we append `#` and a number.
152 String computeName(ClassElement cls) {
153 String name = cls.name;
154 if (!cls.isUnnamedMixinApplication) return name;
155 Map<String, int> mixinApplicationNames = mixinApplicationNamesByLibrary
156 .putIfAbsent(cls.library.implementation, () => <String, int>{});
157 int count = mixinApplicationNames.putIfAbsent(name, () => 0);
158 mixinApplicationNames[name] = count + 1;
159 return "$name#$count";
160 }
161
162 ir.Class classToIr(ClassElement cls) {
163 cls = cls.declaration;
164 return classes.putIfAbsent(cls, () {
165 String name = computeName(cls);
166 ir.Class classNode = new ir.Class(
167 name: name,
168 isAbstract: cls.isAbstract,
169 typeParameters: null,
170 implementedTypes: null,
171 constructors: null,
172 procedures: null,
173 fields: null);
174 addWork(cls, () {
175 if (cls.supertype != null) {
176 classNode.supertype = interfaceTypeToIr(cls.supertype);
177 }
178 classNode.parent = libraryToIr(cls.library);
179 if (cls.isUnnamedMixinApplication) {
180 classNode.enclosingLibrary.addClass(classNode);
181 }
182 cls.implementation
183 .forEachMember((ClassElement enclosingClass, Element member) {
184 if (member.enclosingClass.declaration != cls) {
185 internalError(cls, "`$member` isn't mine.");
186 } else if (member.isFunction ||
187 member.isAccessor ||
188 member.isConstructor) {
189 classNode.addMember(functionToIr(member));
190 } else if (member.isField) {
191 classNode.addMember(fieldToIr(member));
192 } else {
193 internalError(member, "Unhandled class member: $member");
194 }
195 });
196 classNode.typeParameters.addAll(typeVariablesToIr(cls.typeVariables));
197 for (ir.InterfaceType interface in typesToIr(cls.interfaces.toList())) {
198 classNode.implementedTypes.add(interface);
199 }
200 });
201 return classNode;
202 });
203 }
204
205 bool hasHierarchyProblem(ClassElement cls) => cls.hasIncompleteHierarchy;
206
207 ir.InterfaceType interfaceTypeToIr(InterfaceType type) {
208 ir.Class cls = classToIr(type.element);
209 if (type.typeArguments.isEmpty) {
210 return cls.rawType;
211 } else {
212 return new ir.InterfaceType(cls, typesToIr(type.typeArguments));
213 }
214 }
215
216 // TODO(ahe): Remove this method when dart2js support generic type arguments.
217 List<ir.TypeParameter> typeParametersNotImplemented() {
218 return const <ir.TypeParameter>[];
219 }
220
221 ir.FunctionType functionTypeToIr(FunctionType type) {
222 List<ir.TypeParameter> typeParameters = typeParametersNotImplemented();
223 int requiredParameterCount = type.parameterTypes.length;
224 List<ir.DartType> positionalParameters =
225 new List<ir.DartType>.from(typesToIr(type.parameterTypes))
226 ..addAll(typesToIr(type.optionalParameterTypes));
227 Map<String, ir.DartType> namedParameters = <String, ir.DartType>{};
228 for (int i = 0; i < type.namedParameters.length; i++) {
229 namedParameters[type.namedParameters[i]] =
230 typeToIr(type.namedParameterTypes[i]);
231 }
232 ir.DartType returnType = typeToIr(type.returnType);
233
234 return new ir.FunctionType(positionalParameters, returnType,
235 namedParameters: namedParameters,
236 typeParameters: typeParameters,
237 requiredParameterCount: requiredParameterCount);
238 }
239
240 ir.TypeParameterType typeVariableTypeToIr(TypeVariableType type) {
241 return new ir.TypeParameterType(typeVariableToIr(type.element));
242 }
243
244 List<ir.DartType> typesToIr(List<DartType> types) {
245 List<ir.DartType> result = new List<ir.DartType>(types.length);
246 for (int i = 0; i < types.length; i++) {
247 result[i] = typeToIr(types[i]);
248 }
249 return result;
250 }
251
252 ir.DartType typeToIr(DartType type) {
253 switch (type.kind) {
254 case TypeKind.FUNCTION:
255 return functionTypeToIr(type);
256
257 case TypeKind.INTERFACE:
258 return interfaceTypeToIr(type);
259
260 case TypeKind.STATEMENT:
261 throw "Internal error: statement type: $type.";
262
263 case TypeKind.TYPEDEF:
264 type.computeUnaliased(compiler.resolution);
265 return typeToIr(type.unaliased);
266
267 case TypeKind.TYPE_VARIABLE:
268 return typeVariableTypeToIr(type);
269
270 case TypeKind.MALFORMED_TYPE:
271 return const ir.InvalidType();
272
273 case TypeKind.DYNAMIC:
274 return const ir.DynamicType();
275
276 case TypeKind.VOID:
277 return const ir.VoidType();
278 }
279 }
280
281 ir.DartType typeLiteralToIr(TypeConstantExpression constant) {
282 return typeToIr(constant.type);
283 }
284
285 void setParent(ir.Member member, Element element) {
286 if (element.isLocal) {
287 member.parent = elementToIr(element.enclosingElement);
288 } else if (element.isTopLevel) {
289 member.parent = elementToIr(element.library);
290 } else if (element.isClassMember) {
291 member.parent = elementToIr(element.enclosingClass);
292 } else {
293 member.parent = elementToIr(element.enclosingElement);
294 }
295 }
296
297 bool isNativeMethod(FunctionElement element) {
298 // This method is a (modified) copy of the same method in
299 // `pkg/compiler/lib/src/native/enqueue.dart`.
300 if (!compiler.backend.canLibraryUseNative(element.library)) return false;
301 return compiler.reporter.withCurrentElement(element, () {
302 FunctionExpression functionExpression =
303 element.node?.asFunctionExpression();
304 if (functionExpression == null) return false;
305 Node body = functionExpression.body;
306 if (body == null) return false;
307 if (identical(body.getBeginToken().stringValue, 'native')) return true;
308 return false;
309 });
310 }
311
312 ir.Member functionToIr(FunctionElement function) {
313 if (function.isDeferredLoaderGetter) {
314 internalError(function, "Deferred loader.");
315 }
316 if (function.isLocal) {
317 internalError(function, "Local function.");
318 }
319 if (isSyntheticError(function)) {
320 internalError(function, "Synthetic error function: $function.");
321 }
322 function = function.declaration;
323 return functions.putIfAbsent(function, () {
324 function = function.implementation;
325 ir.Member member;
326 ir.Constructor constructor;
327 ir.Procedure procedure;
328 ir.Name name = irName(function.name, function);
329 bool isNative = isNativeMethod(function);
330 if (function.isGenerativeConstructor) {
331 member = constructor = new ir.Constructor(null,
332 name: name,
333 isConst: function.isConst,
334 isExternal: isNative || function.isExternal,
335 initializers: null);
336 } else {
337 member = procedure = new ir.Procedure(name, null, null,
338 isAbstract: function.isAbstract,
339 isStatic: function.isStatic ||
340 function.isTopLevel ||
341 function.isFactoryConstructor,
342 isExternal: isNative || function.isExternal,
343 isConst: false); // TODO(ahe): When is this true?
344 }
345 addWork(function, () {
346 setParent(member, function);
347 KernelVisitor visitor =
348 new KernelVisitor(function, function.treeElements, this);
349 beginFactoryScope(function);
350 IrFunction irFunction = visitor.buildFunction();
351 // TODO(ahe): Add addFunction/set function to [ir.Procedure].
352 irFunction.node.parent = member;
353 if (irFunction.isConstructor) {
354 assert(irFunction.kind == null);
355 constructor.function = irFunction.node;
356 constructor.initializers = irFunction.initializers;
357 // TODO(ahe): Add setInitializers to [ir.Constructor].
358 for (ir.Initializer initializer in irFunction.initializers) {
359 initializer.parent = constructor;
360 }
361 moveSuperCallLast(constructor);
362 } else {
363 assert(irFunction.kind != null);
364 procedure.function = irFunction.node;
365 procedure.kind = irFunction.kind;
366 }
367 endFactoryScope(function);
368 assert(() {
369 visitor.locals.forEach(checkMember);
370 return true;
371 });
372 });
373 return member;
374 });
375 }
376
377 /// Adds the type parameters of the enclosing class of [function] to
378 /// [factoryTypeParameters]. This serves as a local scope for type variables
379 /// resolved inside the factory.
380 ///
381 /// This method solves the problem that a factory method really is a generic
382 /// method that has its own type parameters, one for each type parameter in
383 /// the enclosing class.
384 void beginFactoryScope(FunctionElement function) {
385 assert(factoryTypeParameters.isEmpty);
386 if (!function.isFactoryConstructor) return;
387 ClassElement cls = function.enclosingClass;
388 for (DartType type in cls.typeVariables) {
389 if (type.isTypeVariable) {
390 TypeVariableElement variable = type.element;
391 factoryTypeParameters[variable] =
392 new ir.TypeParameter(variable.name, null);
393 }
394 }
395 for (DartType type in cls.typeVariables) {
396 if (type.isTypeVariable) {
397 TypeVariableElement variable = type.element;
398 factoryTypeParameters[variable].bound = typeToIr(variable.bound);
399 }
400 }
401 }
402
403 /// Ends the local scope started by [beginFactoryScope].
404 void endFactoryScope(FunctionElement function) {
405 factoryTypeParameters.clear();
406 }
407
408 ir.Field fieldToIr(FieldElement field) {
409 if (isSyntheticError(field)) {
410 internalError(field, "Synthetic error field: $field.");
411 }
412 field = field.declaration;
413 return fields.putIfAbsent(field, () {
414 field = field.implementation;
415 ir.DartType type =
416 field.isMalformed ? const ir.InvalidType() : typeToIr(field.type);
417 ir.Field fieldNode = new ir.Field(irName(field.memberName.text, field),
418 type: type,
419 initializer: null,
420 isFinal: field.isFinal,
421 isStatic: field.isStatic || field.isTopLevel,
422 isConst: field.isConst);
423 addWork(field, () {
424 setParent(fieldNode, field);
425 if (!field.isMalformed &&
426 !field.isInstanceMember &&
427 field.initializer != null) {
428 KernelVisitor visitor =
429 new KernelVisitor(field, field.treeElements, this);
430 fieldNode.initializer = visitor.buildInitializer()
431 ..parent = fieldNode;
432 }
433 });
434 return fieldNode;
435 });
436 }
437
438 ir.TypeParameter typeVariableToIr(TypeVariableElement variable) {
439 variable = variable.declaration;
440 ir.TypeParameter parameter = factoryTypeParameters[variable];
441 if (parameter != null) return parameter;
442 return typeParameters.putIfAbsent(variable, () {
443 ir.TypeParameter parameter = new ir.TypeParameter(variable.name, null);
444 addWork(variable, () {
445 // TODO(ahe): This assignment will probably not be correct when dart2js
446 // supports generic methods.
447 ClassElement cls = variable.typeDeclaration;
448 parameter.parent = classToIr(cls);
449 parameter.bound = typeToIr(variable.bound);
450 });
451 return parameter;
452 });
453 }
454
455 List<ir.TypeParameter> typeVariablesToIr(List<DartType> variables) {
456 List<ir.TypeParameter> result =
457 new List<ir.TypeParameter>(variables.length);
458 for (int i = 0; i < variables.length; i++) {
459 TypeVariableType type = variables[i];
460 result[i] = typeVariableToIr(type.element);
461 }
462 return result;
463 }
464
465 ir.TreeNode elementToIr(Element element) {
466 if (element.isLibrary) return libraryToIr(element);
467 if (element.isClass) return classToIr(element);
468 if (element.isFunction || element.isAccessor) return functionToIr(element);
469 if (element.isField) return fieldToIr(element);
470 throw "unhandled element: $element";
471 }
472
473 void debugMessage(Spannable spannable, String message) {
474 compiler.reporter
475 .reportHintMessage(spannable, MessageKind.GENERIC, {'text': message});
476 }
477
478 void internalError(Spannable spannable, String message) {
479 compiler.reporter.internalError(spannable, message);
480 throw message;
481 }
482
483 ConstructorTarget computeEffectiveTarget(
484 ConstructorElement constructor, DartType type) {
485 constructor = constructor.implementation;
486 Set<ConstructorElement> seen = new Set<ConstructorElement>();
487 functionToIr(constructor);
488 while (constructor != constructor.effectiveTarget) {
489 type = constructor.computeEffectiveTargetType(type);
490 if (constructor.isGenerativeConstructor) break;
491 if (!seen.add(constructor)) break;
492 constructor = constructor.effectiveTarget.implementation;
493 if (isSyntheticError(constructor)) break;
494 functionToIr(constructor);
495 }
496 return new ConstructorTarget(constructor, type);
497 }
498
499 /// Returns true if [element] is synthesized to recover or represent a
500 /// semantic error, for example, missing, duplicated, or ambiguous elements.
501 /// However, returns false for elements that have an unrecoverable syntax
502 /// error. Both kinds of element will return true from [Element.isMalformed],
503 /// but they must be handled differently. For example, a static call to
504 /// synthetic error element should be compiled to [ir.InvalidExpression],
505 /// whereas a static call to a method which has a syntax error should be
506 /// compiled to a static call to the method. The method itself will have a
507 /// method body that is [ir.InvalidStatement].
508 bool isSyntheticError(Element element) {
509 if (element.isAmbiguous) return true;
510 if (element.isError) return true;
511 if (element.isField && element is ErroneousFieldElementX) {
512 return true;
513 }
514 return false;
515 }
516
517 ir.Procedure getDartCoreMethod(String name) {
518 LibraryElement library =
519 compiler.libraryLoader.lookupLibrary(Uri.parse("dart:core"));
520 Element function = library.implementation.localLookup(name);
521 return functionToIr(function);
522 }
523
524 ir.Procedure getMalformedTypeErrorBuilder() {
525 return getDartCoreMethod('_malformedTypeError');
526 }
527
528 ir.Procedure getUnresolvedConstructorBuilder() {
529 return getDartCoreMethod('_unresolvedConstructorError');
530 }
531
532 ir.Procedure getUnresolvedStaticGetterBuilder() {
533 return getDartCoreMethod('_unresolvedStaticGetterError');
534 }
535
536 ir.Procedure getUnresolvedStaticSetterBuilder() {
537 return getDartCoreMethod('_unresolvedStaticSetterError');
538 }
539
540 ir.Procedure getUnresolvedStaticMethodBuilder() {
541 return getDartCoreMethod('_unresolvedStaticMethodError');
542 }
543
544 ir.Procedure getUnresolvedTopLevelGetterBuilder() {
545 return getDartCoreMethod('_unresolvedTopLevelGetterError');
546 }
547
548 ir.Procedure getUnresolvedTopLevelSetterBuilder() {
549 return getDartCoreMethod('_unresolvedTopLevelSetterError');
550 }
551
552 ir.Procedure getUnresolvedTopLevelMethodBuilder() {
553 return getDartCoreMethod('_unresolvedTopLevelMethodError');
554 }
555
556 ir.Procedure getUnresolvedSuperGetterBuilder() {
557 return getDartCoreMethod('_unresolvedSuperGetterError');
558 }
559
560 ir.Procedure getUnresolvedSuperSetterBuilder() {
561 return getDartCoreMethod('_unresolvedSuperSetterError');
562 }
563
564 ir.Procedure getUnresolvedSuperMethodBuilder() {
565 return getDartCoreMethod('_unresolvedSuperMethodError');
566 }
567
568 ir.Procedure getGenericNoSuchMethodBuilder() {
569 return getDartCoreMethod('_genericNoSuchMethod');
570 }
571
572 ir.Procedure getFallThroughErrorBuilder() {
573 return getDartCoreMethod('_fallThroughError');
574 }
575 }
576
577 class ConstructorTarget {
578 final ConstructorElement element;
579 final DartType type;
580
581 ConstructorTarget(this.element, this.type);
582
583 String toString() => "ConstructorTarget($element, $type)";
584 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/kernel/fall_through_visitor.dart ('k') | pkg/compiler/lib/src/kernel/kernel_visitor.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698