|  | // 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.Visitor<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(CURRENT_ELEMENT_SPANNABLE, '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; | 
|  | } | 
|  | } |