| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2017, 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 import 'package:kernel/ast.dart' as ir; |
| 6 |
| 7 import '../closure.dart'; |
| 8 import '../compiler.dart'; |
| 9 import '../elements/elements.dart'; |
| 10 import '../elements/entities.dart'; |
| 11 import '../kernel/kernel.dart'; |
| 12 import '../ssa/kernel_ast_adapter.dart'; |
| 13 import '../tree/tree.dart' as ast; |
| 14 import '../types/types.dart' show TypeMask; |
| 15 import '../universe/side_effects.dart' show SideEffects; |
| 16 import 'inferrer_engine.dart'; |
| 17 import 'locals_handler.dart'; |
| 18 import 'type_graph_nodes.dart'; |
| 19 import 'type_system.dart'; |
| 20 |
| 21 /// [KernelTypeGraphBuilder] constructs a type-inference graph for a particular |
| 22 /// element. |
| 23 /// |
| 24 /// Calling [run] will start the work of visiting the body of the code to |
| 25 /// construct a set of inference-nodes that abstractly represent what the code |
| 26 /// is doing. |
| 27 class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> { |
| 28 final Compiler compiler; |
| 29 final AstElement originalElement; |
| 30 // TODO(efortuna): Remove this. |
| 31 final Element outermostElement; |
| 32 final ir.Node analyzedNode; |
| 33 final ResolvedAst resolvedAst; |
| 34 final TypeSystem types; |
| 35 LocalsHandler locals; |
| 36 final InferrerEngine inferrer; |
| 37 SideEffects sideEffects = new SideEffects.empty(); |
| 38 int loopLevel = 0; |
| 39 bool get inLoop => loopLevel > 0; |
| 40 |
| 41 final Set<Entity> capturedVariables = new Set<Entity>(); |
| 42 |
| 43 final KernelAstAdapter astAdapter; |
| 44 |
| 45 KernelTypeGraphBuilder.internal( |
| 46 this.originalElement, |
| 47 this.resolvedAst, |
| 48 this.outermostElement, |
| 49 this.inferrer, |
| 50 this.compiler, |
| 51 this.locals, |
| 52 this.astAdapter, |
| 53 this.analyzedNode) |
| 54 : this.types = inferrer.types { |
| 55 if (locals != null) return; |
| 56 |
| 57 ast.Node node; |
| 58 if (resolvedAst.kind == ResolvedAstKind.PARSED) { |
| 59 node = resolvedAst.node; |
| 60 } |
| 61 FieldInitializationScope fieldScope = (analyzedNode is ir.Constructor) |
| 62 ? new FieldInitializationScope(types) |
| 63 : null; |
| 64 locals = |
| 65 new LocalsHandler(inferrer, types, compiler.options, node, fieldScope); |
| 66 } |
| 67 |
| 68 factory KernelTypeGraphBuilder(Element element, ResolvedAst resolvedAst, |
| 69 Compiler compiler, InferrerEngine inferrer, |
| 70 [LocalsHandler handler]) { |
| 71 var adapter = _createKernelAdapter(compiler, resolvedAst); |
| 72 var node = adapter.getInitialKernelNode(element); |
| 73 return new KernelTypeGraphBuilder.internal( |
| 74 element, |
| 75 resolvedAst, |
| 76 element.outermostEnclosingMemberOrTopLevel.implementation, |
| 77 inferrer, |
| 78 compiler, |
| 79 handler, |
| 80 adapter, |
| 81 node); |
| 82 } |
| 83 |
| 84 static KernelAstAdapter _createKernelAdapter( |
| 85 Compiler compiler, ResolvedAst resolvedAst) { |
| 86 Kernel kernel = compiler.backend.kernelTask.kernel; |
| 87 return new KernelAstAdapter(kernel, compiler.backend, resolvedAst, |
| 88 kernel.nodeToAst, kernel.nodeToElement); |
| 89 } |
| 90 |
| 91 TypeInformation run() { |
| 92 ir.Expression initializer; |
| 93 if (analyzedNode is ir.Field) { |
| 94 ir.Field field = analyzedNode; |
| 95 initializer = field.initializer; |
| 96 if (initializer == null || initializer is ir.NullLiteral) { |
| 97 // Eagerly bailout, because computing the closure data only |
| 98 // works for functions and field assignments. |
| 99 return types.nullType; |
| 100 } |
| 101 } |
| 102 |
| 103 // Update the locals that are boxed in [locals]. These locals will |
| 104 // be handled specially, in that we are computing their LUB at |
| 105 // each update, and reading them yields the type that was found in a |
| 106 // previous analysis of [outermostElement]. |
| 107 ClosureClassMap closureData = |
| 108 compiler.closureToClassMapper.getClosureToClassMapping(resolvedAst); |
| 109 closureData.forEachCapturedVariable((variable, field) { |
| 110 locals.setCaptured(variable, field); |
| 111 }); |
| 112 closureData.forEachBoxedVariable((variable, field) { |
| 113 locals.setCapturedAndBoxed(variable, field); |
| 114 }); |
| 115 |
| 116 if (analyzedNode is ir.Field) { |
| 117 return initializer.accept(this); |
| 118 } |
| 119 return _processFunctionNode(analyzedNode); |
| 120 } |
| 121 |
| 122 TypeInformation _processFunctionNode(ir.FunctionNode funcNode) { |
| 123 // TODO(efortuna): Implement. |
| 124 return types.dynamicType; |
| 125 } |
| 126 |
| 127 @override |
| 128 TypeInformation defaultExpression(ir.Expression expression) { |
| 129 // TODO(efortuna): Remove when more is implemented. |
| 130 return types.dynamicType; |
| 131 } |
| 132 |
| 133 @override |
| 134 TypeInformation visitNullLiteral(ir.NullLiteral literal) { |
| 135 return types.nullType; |
| 136 } |
| 137 |
| 138 @override |
| 139 TypeInformation visitBlock(ir.Block block) { |
| 140 for (ir.Statement statement in block.statements) { |
| 141 statement.accept(this); |
| 142 if (locals.aborts) break; |
| 143 } |
| 144 return null; |
| 145 } |
| 146 |
| 147 @override |
| 148 TypeInformation visitListLiteral(ir.ListLiteral listLiteral) { |
| 149 // We only set the type once. We don't need to re-visit the children |
| 150 // when re-analyzing the node. |
| 151 return inferrer.concreteKernelTypes.putIfAbsent(listLiteral, () { |
| 152 TypeInformation elementType; |
| 153 int length = 0; |
| 154 for (ir.Expression element in listLiteral.expressions) { |
| 155 TypeInformation type = element.accept(this); |
| 156 elementType = elementType == null |
| 157 ? types.allocatePhi(null, null, type) |
| 158 : types.addPhiInput(null, elementType, type); |
| 159 length++; |
| 160 } |
| 161 elementType = elementType == null |
| 162 ? types.nonNullEmpty() |
| 163 : types.simplifyPhi(null, null, elementType); |
| 164 TypeInformation containerType = |
| 165 listLiteral.isConst ? types.constListType : types.growableListType; |
| 166 // TODO(efortuna): Change signature of allocateList and the rest of |
| 167 // type_system to deal with Kernel elements. |
| 168 return types.allocateList(containerType, astAdapter.getNode(listLiteral), |
| 169 outermostElement, elementType, length); |
| 170 }); |
| 171 } |
| 172 } |
| OLD | NEW |