OLD | NEW |
(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 file. |
| 4 |
| 5 library kernel.transformations.closure.info; |
| 6 |
| 7 import '../../ast.dart' |
| 8 show |
| 9 Class, |
| 10 Constructor, |
| 11 Field, |
| 12 FunctionDeclaration, |
| 13 FunctionNode, |
| 14 Member, |
| 15 Name, |
| 16 Procedure, |
| 17 ProcedureKind, |
| 18 PropertyGet, |
| 19 ThisExpression, |
| 20 TypeParameter, |
| 21 TypeParameterType, |
| 22 VariableDeclaration, |
| 23 VariableGet, |
| 24 VariableSet; |
| 25 |
| 26 import '../../visitor.dart' show RecursiveVisitor; |
| 27 |
| 28 class ClosureInfo extends RecursiveVisitor { |
| 29 FunctionNode currentFunction; |
| 30 final Map<VariableDeclaration, FunctionNode> function = |
| 31 <VariableDeclaration, FunctionNode>{}; |
| 32 |
| 33 final Set<VariableDeclaration> variables = new Set<VariableDeclaration>(); |
| 34 |
| 35 final Map<FunctionNode, Set<TypeParameter>> typeVariables = |
| 36 <FunctionNode, Set<TypeParameter>>{}; |
| 37 |
| 38 /// Map from members to synthetic variables for accessing `this` in a local |
| 39 /// function. |
| 40 final Map<FunctionNode, VariableDeclaration> thisAccess = |
| 41 <FunctionNode, VariableDeclaration>{}; |
| 42 |
| 43 final Set<String> currentMemberLocalNames = new Set<String>(); |
| 44 |
| 45 final Map<FunctionNode, String> localNames = <FunctionNode, String>{}; |
| 46 |
| 47 /// Contains all names used as getter through a [PropertyGet]. |
| 48 final Set<Name> invokedGetters = new Set<Name>(); |
| 49 |
| 50 /// Contains all names of declared regular instance methods (not including |
| 51 /// accessors and operators). |
| 52 final Set<Name> declaredInstanceMethodNames = new Set<Name>(); |
| 53 |
| 54 Class currentClass; |
| 55 |
| 56 Member currentMember; |
| 57 |
| 58 FunctionNode currentMemberFunction; |
| 59 |
| 60 bool get isOuterMostContext { |
| 61 return currentFunction == null || currentMemberFunction == currentFunction; |
| 62 } |
| 63 |
| 64 /// Maps the names of all instance methods that may be torn off (aka |
| 65 /// implicitly closurized) to `${name.name}#get`. |
| 66 Map<Name, Name> get tearOffGetterNames { |
| 67 Map<Name, Name> result = <Name, Name>{}; |
| 68 for (Name name in declaredInstanceMethodNames) { |
| 69 if (invokedGetters.contains(name)) { |
| 70 result[name] = new Name("${name.name}#get", name.library); |
| 71 } |
| 72 } |
| 73 return result; |
| 74 } |
| 75 |
| 76 void beginMember(Member member, [FunctionNode function]) { |
| 77 currentMemberLocalNames.clear(); |
| 78 if (function != null) { |
| 79 localNames[function] = computeUniqueLocalName(member.name.name); |
| 80 } |
| 81 currentMember = member; |
| 82 currentMemberFunction = function; |
| 83 } |
| 84 |
| 85 void endMember() { |
| 86 currentMember = null; |
| 87 currentMemberFunction = null; |
| 88 } |
| 89 |
| 90 visitClass(Class node) { |
| 91 currentClass = node; |
| 92 super.visitClass(node); |
| 93 currentClass = null; |
| 94 } |
| 95 |
| 96 visitConstructor(Constructor node) { |
| 97 beginMember(node, node.function); |
| 98 super.visitConstructor(node); |
| 99 endMember(); |
| 100 } |
| 101 |
| 102 visitProcedure(Procedure node) { |
| 103 beginMember(node, node.function); |
| 104 if (node.isInstanceMember && node.kind == ProcedureKind.Method) { |
| 105 // Ignore the `length` method of [File] subclasses for now, as they |
| 106 // will force us to rename the `length` getter (kernel issue #43). |
| 107 // TODO(ahe): remove this condition. |
| 108 Class parent = node.parent; |
| 109 if (node.name.name != "length" || |
| 110 parent.enclosingLibrary.importUri.toString() != "dart:io") { |
| 111 declaredInstanceMethodNames.add(node.name); |
| 112 } |
| 113 } |
| 114 super.visitProcedure(node); |
| 115 endMember(); |
| 116 } |
| 117 |
| 118 visitField(Field node) { |
| 119 beginMember(node); |
| 120 super.visitField(node); |
| 121 endMember(); |
| 122 } |
| 123 |
| 124 String computeUniqueLocalName([String name]) { |
| 125 if (name == null || name.isEmpty) { |
| 126 name = "function"; |
| 127 } |
| 128 if (currentFunction == null) { |
| 129 if (currentMember != null) { |
| 130 name = "${currentMember.name.name}#$name"; |
| 131 } |
| 132 if (currentClass != null) { |
| 133 name = "${currentClass.name}#$name"; |
| 134 } |
| 135 } else { |
| 136 name = "${localNames[currentFunction]}#$name"; |
| 137 } |
| 138 int count = 1; |
| 139 String candidate = name; |
| 140 while (currentMemberLocalNames.contains(candidate)) { |
| 141 candidate = "$name#${count++}"; |
| 142 } |
| 143 currentMemberLocalNames.add(candidate); |
| 144 return candidate; |
| 145 } |
| 146 |
| 147 visitFunctionDeclaration(FunctionDeclaration node) { |
| 148 assert(!localNames.containsKey(node)); |
| 149 localNames[node.function] = computeUniqueLocalName(node.variable.name); |
| 150 return super.visitFunctionDeclaration(node); |
| 151 } |
| 152 |
| 153 visitFunctionNode(FunctionNode node) { |
| 154 localNames.putIfAbsent(node, computeUniqueLocalName); |
| 155 var saved = currentFunction; |
| 156 currentFunction = node; |
| 157 node.visitChildren(this); |
| 158 currentFunction = saved; |
| 159 Set<TypeParameter> capturedTypeVariables = typeVariables[node]; |
| 160 if (capturedTypeVariables != null && !isOuterMostContext) { |
| 161 // Propagate captured type variables to enclosing function. |
| 162 typeVariables |
| 163 .putIfAbsent(currentFunction, () => new Set<TypeParameter>()) |
| 164 .addAll(capturedTypeVariables); |
| 165 } |
| 166 } |
| 167 |
| 168 visitVariableDeclaration(VariableDeclaration node) { |
| 169 function[node] = currentFunction; |
| 170 node.visitChildren(this); |
| 171 } |
| 172 |
| 173 visitVariableGet(VariableGet node) { |
| 174 if (function[node.variable] != currentFunction) { |
| 175 variables.add(node.variable); |
| 176 } |
| 177 node.visitChildren(this); |
| 178 } |
| 179 |
| 180 visitVariableSet(VariableSet node) { |
| 181 if (function[node.variable] != currentFunction) { |
| 182 variables.add(node.variable); |
| 183 } |
| 184 node.visitChildren(this); |
| 185 } |
| 186 |
| 187 visitTypeParameterType(TypeParameterType node) { |
| 188 if (!isOuterMostContext) { |
| 189 typeVariables |
| 190 .putIfAbsent(currentFunction, () => new Set<TypeParameter>()) |
| 191 .add(node.parameter); |
| 192 } |
| 193 } |
| 194 |
| 195 visitThisExpression(ThisExpression node) { |
| 196 if (!isOuterMostContext) { |
| 197 thisAccess.putIfAbsent( |
| 198 currentMemberFunction, () => new VariableDeclaration("#self")); |
| 199 } |
| 200 } |
| 201 |
| 202 visitPropertyGet(PropertyGet node) { |
| 203 invokedGetters.add(node.name); |
| 204 super.visitPropertyGet(node); |
| 205 } |
| 206 } |
OLD | NEW |