| // Copyright (c) 2016, 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 '../common.dart'; | |
| import '../inferrer/abstract_value_domain.dart'; | |
| import 'builder.dart'; | |
| import 'nodes.dart'; | |
| /// Visits and concatenates the expressions in a string concatenation. | |
| class KernelStringBuilder extends ir.VisitorDefault<void> | |
| with ir.VisitorVoidMixin { | |
| final KernelSsaGraphBuilder builder; | |
| /// The string value generated so far. | |
| HInstruction? result; | |
| KernelStringBuilder(this.builder); | |
| AbstractValueDomain get _abstractValueDomain => | |
| builder.closedWorld.abstractValueDomain; | |
| @override | |
| void defaultNode(ir.Node node) { | |
| failedAt(currentElementSpannable, 'Unexpected node: $node'); | |
| } | |
| @override | |
| void defaultExpression(ir.Expression node) { | |
| node.accept(builder); | |
| HInstruction expression = builder.pop(); | |
| // We want to use HStringify when: | |
| // 1. The value is known to be a primitive type, because it might get | |
| // constant-folded and codegen has some tricks with JavaScript | |
| // conversions. | |
| // 2. The value can be primitive, because the library stringifier has | |
| // fast-path code for most primitives. | |
| if (expression.isPrimitive(_abstractValueDomain).isPotentiallyTrue) { | |
| append(stringify(expression)); | |
| return; | |
| } | |
| // TODO(efortuna): If we decide to do inlining before finishing constructing | |
| // the control flow graph, we'd want to do the optimization of | |
| // calling toString here if the type is provably a string rather than in the | |
| // optimization phase (which is where we currently do it). | |
| append(stringify(expression)); | |
| } | |
| @override | |
| void visitStringConcatenation(ir.StringConcatenation node) { | |
| node.visitChildren(this); | |
| } | |
| void append(HInstruction expression) { | |
| result = (result == null) ? expression : concat(result!, expression); | |
| } | |
| HInstruction concat(HInstruction left, HInstruction right) { | |
| HInstruction instruction = HStringConcat( | |
| left, | |
| right, | |
| _abstractValueDomain.stringType, | |
| ); | |
| builder.add(instruction); | |
| return instruction; | |
| } | |
| HInstruction stringify(HInstruction expression) { | |
| HInstruction instruction = HStringify( | |
| expression, | |
| _abstractValueDomain.stringType, | |
| )..sourceInformation = expression.sourceInformation; | |
| builder.add(instruction); | |
| return instruction; | |
| } | |
| } |