Chromium Code Reviews| Index: pkg/compiler/lib/src/inferrer/builder_kernel.dart |
| diff --git a/pkg/compiler/lib/src/inferrer/builder_kernel.dart b/pkg/compiler/lib/src/inferrer/builder_kernel.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..06f9b5e3e0e01d76d1138df417829b147baf5844 |
| --- /dev/null |
| +++ b/pkg/compiler/lib/src/inferrer/builder_kernel.dart |
| @@ -0,0 +1,160 @@ |
| +// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| +// for details. All rights reserved. Use of this source code is governed by a |
| +// BSD-style license that can be found in the LICENSE file. |
| + |
| +import 'package:kernel/ast.dart' as ir; |
| + |
| +import '../closure.dart'; |
| +import '../compiler.dart'; |
| +import '../elements/elements.dart'; |
| +import '../elements/entities.dart'; |
| +import '../kernel/kernel.dart'; |
| +import '../ssa/kernel_ast_adapter.dart'; |
| +import '../tree/tree.dart' as ast; |
| +import '../types/types.dart' show TypeMask; |
| +import '../universe/side_effects.dart' show SideEffects; |
| +import 'inferrer_engine.dart'; |
| +import 'locals_handler.dart'; |
| +import 'type_graph_nodes.dart'; |
| +import 'type_system.dart'; |
| + |
| +/// [KernelTypeGraphBuilder] can be thought of as a type-inference graph |
|
Siggi Cherem (dart-lang)
2017/03/16 00:37:44
BTW - we should be able to update these comments a
Emily Fortuna
2017/03/17 01:03:02
Done.
|
| +/// builder for a single element. |
| +/// |
| +/// Calling [run] will start the work of visiting the body of the code to |
| +/// construct a set of infernece-nodes that abstractly represent what the code |
| +/// is doing. |
| +/// |
| +/// This visitor is parameterized by an [InferenceEngine], which internally |
|
Siggi Cherem (dart-lang)
2017/03/16 00:37:44
similarly note the engine parameter is now gone (J
Emily Fortuna
2017/03/17 01:03:01
Done.
|
| +/// decides how to represent inference nodes. |
| +class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> { |
| + final Compiler compiler; |
| + final AstElement originalElement; |
| + // TODO(efortuna): Remove this. |
| + final Element outermostElement; |
| + ir.Node analyzedNode; |
| + final ResolvedAst resolvedAst; |
| + final TypeSystem types; |
| + LocalsHandler locals; |
| + final InferrerEngine inferrer; |
| + SideEffects sideEffects = new SideEffects.empty(); |
| + int loopLevel = 0; |
| + final Set<Entity> capturedVariables = new Set<Entity>(); |
| + |
| + KernelAstAdapter astAdapter; |
| + |
| + bool get inLoop => loopLevel > 0; |
|
Siggi Cherem (dart-lang)
2017/03/16 00:37:44
nit: I'd move htis up next to loopLevel (it mixes
Emily Fortuna
2017/03/17 01:03:02
Done.
|
| + |
| + KernelTypeGraphBuilder.internal(this.originalElement, this.resolvedAst, |
| + this.outermostElement, this.inferrer, this.compiler, this.locals) |
| + : this.types = inferrer.types { |
| + if (locals != null) return; |
| + |
| + Kernel kernel = compiler.backend.kernelTask.kernel; |
| + this.astAdapter = new KernelAstAdapter(kernel, compiler.backend, |
|
Siggi Cherem (dart-lang)
2017/03/16 00:37:45
it might not be worth making this change because t
Emily Fortuna
2017/03/17 01:03:02
Done.
|
| + resolvedAst, kernel.nodeToAst, kernel.nodeToElement); |
| + |
| + analyzedNode = astAdapter.getInitialKernelNode(originalElement); |
|
Siggi Cherem (dart-lang)
2017/03/16 00:37:44
will analyzerNode ever change? If not, then maybe
Emily Fortuna
2017/03/17 01:03:02
Done.
|
| + |
| + ast.Node node; |
|
Siggi Cherem (dart-lang)
2017/03/16 00:37:45
I'm guessing the idea is this will be replaced by
Emily Fortuna
2017/03/17 01:03:01
yep. The list of things to do grows very quickly!
|
| + if (resolvedAst.kind == ResolvedAstKind.PARSED) { |
| + node = resolvedAst.node; |
| + } |
| + FieldInitializationScope fieldScope = (analyzedNode is ir.Constructor) |
| + ? new FieldInitializationScope(types) |
| + : null; |
| + locals = |
| + new LocalsHandler(inferrer, types, compiler.options, node, fieldScope); |
| + } |
| + |
| + KernelTypeGraphBuilder(Element element, ResolvedAst resolvedAst, |
| + Compiler compiler, InferrerEngine inferrer, [LocalsHandler handler]) |
| + : this.internal( |
| + element, |
| + resolvedAst, |
| + element.outermostEnclosingMemberOrTopLevel.implementation, |
| + inferrer, |
| + compiler, |
| + handler); |
| + |
| + TypeInformation run() { |
| + ir.Expression initializer; |
| + if (analyzedNode is ir.Field) { |
| + initializer = (analyzedNode as ir.Field).initializer; |
|
Siggi Cherem (dart-lang)
2017/03/16 00:37:45
If we can make analyzerNode final above, then this
Emily Fortuna
2017/03/17 01:03:02
Hmm I made this change complete with the finals, a
Siggi Cherem (dart-lang)
2017/03/17 21:10:17
interesting - I think I understand why now - this
|
| + if (initializer == null) { |
| + // Eagerly bailout, because computing the closure data only |
| + // works for functions and field assignments. |
| + return types.nullType; |
| + } |
| + } |
| + |
| + // Update the locals that are boxed in [locals]. These locals will |
| + // be handled specially, in that we are computing their LUB at |
| + // each update, and reading them yields the type that was found in a |
| + // previous analysis of [outermostElement]. |
| + ClosureClassMap closureData = |
| + compiler.closureToClassMapper.getClosureToClassMapping(resolvedAst); |
| + closureData.forEachCapturedVariable((variable, field) { |
| + locals.setCaptured(variable, field); |
| + }); |
| + closureData.forEachBoxedVariable((variable, field) { |
| + locals.setCapturedAndBoxed(variable, field); |
| + }); |
| + |
| + if (analyzedNode is ir.Field) { |
| + return initializer.accept(this); |
| + } |
| + return _processFunctionNode(analyzedNode); |
| + } |
| + |
| + TypeInformation _processFunctionNode(ir.FunctionNode funcNode) { |
| + // TODO(efortuna): Implement. |
| + return types.dynamicType; |
| + } |
| + |
| + @override |
| + TypeInformation defaultExpression(ir.Expression expression) { |
| + // TODO(efortuna): Remove when more is implemented. |
| + return types.dynamicType; |
| + } |
| + |
| + @override |
| + TypeInformation visitNullLiteral(ir.NullLiteral literal) { |
| + return types.nullType; |
| + } |
| + |
| + @override |
| + TypeInformation visitBlock(ir.Block block) { |
| + for (ir.Statement statement in block.statements) { |
| + statement.accept(this); |
| + if (locals.aborts) break; |
| + } |
| + return null; |
| + } |
| + |
| + @override |
| + TypeInformation visitListLiteral(ir.ListLiteral listLiteral) { |
| + // We only set the type once. We don't need to re-visit the children |
| + // when re-analyzing the node. |
| + return inferrer.concreteKernelTypes.putIfAbsent(listLiteral, () { |
| + TypeInformation elementType; |
| + int length = 0; |
| + for (ir.Expression element in listLiteral.expressions) { |
| + TypeInformation type = element.accept(this); |
| + elementType = elementType == null |
| + ? types.allocatePhi(null, null, type) |
| + : types.addPhiInput(null, elementType, type); |
| + length++; |
| + } |
| + elementType = elementType == null |
| + ? types.nonNullEmpty() |
| + : types.simplifyPhi(null, null, elementType); |
| + TypeInformation containerType = |
| + listLiteral.isConst ? types.constListType : types.growableListType; |
| + // TODO(efortuna): Change signature of allocateList and the rest of |
| + // type_system to deal with Kernel elements. |
| + return types.allocateList(containerType, astAdapter.getNode(listLiteral), |
| + outermostElement, elementType, length); |
| + }); |
| + } |
| +} |