OLD | NEW |
---|---|
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library dev_compiler.src.codegen.reify_coercions; | 5 library dev_compiler.src.codegen.reify_coercions; |
6 | 6 |
7 import 'package:analyzer/analyzer.dart' as analyzer; | 7 import 'package:analyzer/analyzer.dart' as analyzer; |
8 import 'package:analyzer/src/generated/ast.dart'; | 8 import 'package:analyzer/src/generated/ast.dart'; |
9 import 'package:analyzer/src/generated/element.dart'; | 9 import 'package:analyzer/src/generated/element.dart'; |
10 import 'package:logging/logging.dart' as logger; | 10 import 'package:logging/logging.dart' as logger; |
11 import 'package:source_span/source_span.dart' show SourceFile; | 11 import 'package:source_span/source_span.dart' show SourceFile; |
12 | 12 |
13 import 'package:dev_compiler/src/checker/rules.dart'; | 13 import 'package:dev_compiler/src/checker/rules.dart'; |
14 import 'package:dev_compiler/src/info.dart'; | 14 import 'package:dev_compiler/src/info.dart'; |
15 import 'package:dev_compiler/src/options.dart' show CompilerOptions; | |
15 import 'package:dev_compiler/src/utils.dart' as utils; | 16 import 'package:dev_compiler/src/utils.dart' as utils; |
16 | 17 |
17 import 'ast_builder.dart'; | 18 import 'ast_builder.dart'; |
18 | 19 |
19 final _log = new logger.Logger('dev_compiler.reify_coercions'); | 20 final _log = new logger.Logger('dev_compiler.reify_coercions'); |
20 | 21 |
21 // TODO(leafp) Factor this out or use an existing library | 22 // TODO(leafp) Factor this out or use an existing library |
22 class Tuple2<T0, T1> { | 23 class Tuple2<T0, T1> { |
23 final T0 e0; | 24 final T0 e0; |
24 final T1 e1; | 25 final T1 e1; |
(...skipping 12 matching lines...) Expand all Loading... | |
37 bool synthetic; | 38 bool synthetic; |
38 NewTypeIdDesc({this.fromCurrent, this.importedFrom, this.synthetic}); | 39 NewTypeIdDesc({this.fromCurrent, this.importedFrom, this.synthetic}); |
39 } | 40 } |
40 | 41 |
41 class _LocatedWrapper { | 42 class _LocatedWrapper { |
42 final String loc; | 43 final String loc; |
43 final Wrapper wrapper; | 44 final Wrapper wrapper; |
44 _LocatedWrapper(this.wrapper, this.loc); | 45 _LocatedWrapper(this.wrapper, this.loc); |
45 } | 46 } |
46 | 47 |
48 abstract class InstrumentedRuntime { | |
49 Expression wrap(Expression coercion, Expression e, Expression fromType, | |
50 Expression toType, Expression dartIs, String kind, String location); | |
51 Expression cast(Expression e, Expression fromType, Expression toType, | |
52 Expression dartIs, String kind, String location, bool ground); | |
53 Expression type(Expression witnessFunction); | |
54 } | |
55 | |
47 class _Inference extends DownwardsInference { | 56 class _Inference extends DownwardsInference { |
48 TypeManager _tm; | 57 TypeManager _tm; |
49 | 58 |
50 _Inference(TypeRules rules, this._tm) : super(rules); | 59 _Inference(TypeRules rules, this._tm) : super(rules); |
51 | 60 |
52 @override | 61 @override |
53 void annotateCastFromDynamic(Expression e, DartType t) { | 62 void annotateCastFromDynamic(Expression e, DartType t) { |
54 var cast = Coercion.cast(e.staticType, t); | 63 var cast = Coercion.cast(e.staticType, t); |
55 var node = new DynamicCast(rules, e, cast); | 64 var node = new DynamicCast(rules, e, cast); |
56 if (!NodeReplacer.replace(e, node)) { | 65 if (!NodeReplacer.replace(e, node)) { |
(...skipping 18 matching lines...) Expand all Loading... | |
75 } | 84 } |
76 | 85 |
77 @override | 86 @override |
78 void annotateInstanceCreationExpression( | 87 void annotateInstanceCreationExpression( |
79 InstanceCreationExpression e, List<DartType> targs) { | 88 InstanceCreationExpression e, List<DartType> targs) { |
80 var tNames = targs.map(_tm.typeNameFromDartType).toList(); | 89 var tNames = targs.map(_tm.typeNameFromDartType).toList(); |
81 var cName = e.constructorName; | 90 var cName = e.constructorName; |
82 var id = cName.type.name; | 91 var id = cName.type.name; |
83 var typeName = AstBuilder.typeName(id, tNames); | 92 var typeName = AstBuilder.typeName(id, tNames); |
84 cName.type = typeName; | 93 cName.type = typeName; |
85 var rawType = (e.staticType.element as ClassElement).type; | 94 var newType = |
86 e.staticType = rawType.substitute4(targs); | 95 (e.staticType.element as ClassElement).type.substitute4(targs); |
96 e.staticType = newType; | |
97 typeName.type = newType; | |
87 } | 98 } |
88 | 99 |
89 @override | 100 @override |
90 void annotateFunctionExpression(FunctionExpression e, DartType returnType) { | 101 void annotateFunctionExpression(FunctionExpression e, DartType returnType) { |
91 // Implicitly changes e.staticType | 102 // Implicitly changes e.staticType |
92 (e.element as ExecutableElementImpl).returnType = returnType; | 103 (e.element as ExecutableElementImpl).returnType = returnType; |
93 } | 104 } |
94 } | 105 } |
95 | 106 |
96 // This class implements a pass which modifies (in place) the ast replacing | 107 // This class implements a pass which modifies (in place) the ast replacing |
97 // abstract coercion nodes with their dart implementations. | 108 // abstract coercion nodes with their dart implementations. |
98 class CoercionReifier extends analyzer.GeneralizingAstVisitor<Object> | 109 class CoercionReifier extends analyzer.GeneralizingAstVisitor<Object> |
99 with ConversionVisitor<Object> { | 110 with ConversionVisitor<Object> { |
100 final CoercionManager _cm; | 111 final CoercionManager _cm; |
101 final TypeManager _tm; | 112 final TypeManager _tm; |
102 final VariableManager _vm; | 113 final VariableManager _vm; |
103 final LibraryUnit _library; | 114 final LibraryUnit _library; |
104 SourceFile _file; | 115 SourceFile _file; |
105 bool _skipCoercions = false; | 116 bool _skipCoercions = false; |
106 final TypeRules _rules; | 117 final TypeRules _rules; |
107 final _Inference _inferrer; | 118 final _Inference _inferrer; |
119 final InstrumentedRuntime _runtime; | |
120 final CompilerOptions _options; | |
108 | 121 |
109 CoercionReifier._( | 122 CoercionReifier._(this._cm, this._tm, this._vm, this._library, this._rules, |
110 this._cm, this._tm, this._vm, this._library, this._rules, this._inferrer); | 123 this._inferrer, this._runtime, this._options); |
111 | 124 |
112 factory CoercionReifier(LibraryUnit library, TypeRules rules) { | 125 factory CoercionReifier( |
126 LibraryUnit library, TypeRules rules, CompilerOptions options, | |
127 [InstrumentedRuntime runtime]) { | |
113 var vm = new VariableManager(); | 128 var vm = new VariableManager(); |
114 var tm = new TypeManager(library.library.element.enclosingElement, vm); | 129 var tm = |
115 var cm = new CoercionManager(vm, tm, rules); | 130 new TypeManager(library.library.element.enclosingElement, vm, runtime); |
131 var cm = new CoercionManager(vm, tm, rules, runtime); | |
116 var inferrer = new _Inference(rules, tm); | 132 var inferrer = new _Inference(rules, tm); |
117 return new CoercionReifier._(cm, tm, vm, library, rules, inferrer); | 133 return new CoercionReifier._( |
134 cm, tm, vm, library, rules, inferrer, runtime, options); | |
118 } | 135 } |
119 | 136 |
120 // This should be the entry point for this class. Entering via the | 137 // This should be the entry point for this class. Entering via the |
121 // visit functions directly may not do the right thing with respect | 138 // visit functions directly may not do the right thing with respect |
122 // to discharging the collected definitions. | 139 // to discharging the collected definitions. |
123 // Returns the set of new type identifiers added by the reifier | 140 // Returns the set of new type identifiers added by the reifier |
124 Map<Identifier, NewTypeIdDesc> reify() { | 141 Map<Identifier, NewTypeIdDesc> reify() { |
125 _library.partsThenLibrary.forEach(generateUnit); | 142 _library.partsThenLibrary.forEach(generateUnit); |
126 return _tm.addedTypes; | 143 return _tm.addedTypes; |
127 } | 144 } |
128 | 145 |
129 void generateUnit(CompilationUnit unit) { | 146 void generateUnit(CompilationUnit unit) { |
130 _file = new SourceFile(unit.element.source.contents.data, | 147 _file = new SourceFile(unit.element.source.contents.data, |
131 url: unit.element.source.uri); | 148 url: unit.element.source.uri); |
132 visitCompilationUnit(unit); | 149 visitCompilationUnit(unit); |
133 _file = null; | 150 _file = null; |
134 } | 151 } |
135 | 152 |
136 ///////////////// Private ////////////////////////////////// | 153 ///////////////// Private ////////////////////////////////// |
137 | 154 |
138 String _locationInfo(Expression e) { | 155 String _locationInfo(Expression e) { |
139 if (_file != null) { | 156 if (_file != null) { |
140 final begin = e is AnnotatedNode | 157 final begin = e is AnnotatedNode |
141 ? (e as AnnotatedNode).firstTokenAfterCommentAndMetadata.offset | 158 ? (e as AnnotatedNode).firstTokenAfterCommentAndMetadata.offset |
142 : e.offset; | 159 : e.offset; |
143 if (begin != 0) { | 160 if (begin != 0 && e.end > begin) { |
144 var span = _file.span(begin, e.end); | 161 var span = _file.span(begin, e.end); |
145 var s = span.message("Cast"); | 162 var s = span.message("Cast"); |
146 return s.substring(0, s.indexOf("Cast")); | 163 return s.substring(0, s.indexOf("Cast")); |
147 } | 164 } |
148 } | 165 } |
149 return null; | 166 return null; |
150 } | 167 } |
151 | 168 |
152 static String _conversionKind(Conversion node) { | 169 static String _conversionKind(Conversion node) { |
153 if (node is ClosureWrapLiteral) return "WrapLiteral"; | 170 if (node is ClosureWrapLiteral) return "WrapLiteral"; |
154 if (node is ClosureWrap) return "Wrap"; | 171 if (node is ClosureWrap) return "Wrap"; |
155 if (node is DynamicCast) return "DynamicCast"; | 172 if (node is DynamicCast) return "DynamicCast"; |
156 if (node is AssignmentCast) return "AssignmentCast"; | 173 if (node is AssignmentCast) return "AssignmentCast"; |
157 if (node is UninferredClosure) return "InferableClosure"; | 174 if (node is UninferredClosure) return "InferableClosure"; |
158 if (node is DownCastComposite) return "CompositeCast"; | 175 if (node is DownCastComposite) return "CompositeCast"; |
159 if (node is DownCastImplicit) return "ImplicitCast"; | 176 if (node is DownCastImplicit) return "ImplicitCast"; |
160 assert(false); | 177 assert(false); |
161 return ""; | 178 return ""; |
162 } | 179 } |
163 | 180 |
164 @override | 181 @override |
165 Object visitAsExpression(AsExpression e) { | 182 Object visitAsExpression(AsExpression e) { |
183 if (_runtime == null) return super.visitAsExpression(e); | |
166 var cast = Coercion.cast(_rules.getStaticType(e.expression), e.type.type); | 184 var cast = Coercion.cast(_rules.getStaticType(e.expression), e.type.type); |
167 var loc = _locationInfo(e); | 185 var loc = _locationInfo(e); |
168 Expression castNode = | 186 Expression castNode = |
169 _cm.coerceExpression(e.expression, cast, "CastUser", loc); | 187 _cm.coerceExpression(e.expression, cast, "CastUser", loc); |
170 if (!NodeReplacer.replace(e, castNode)) { | 188 if (!NodeReplacer.replace(e, castNode)) { |
171 _log.severe("Failed to replace node for DownCast"); | 189 _log.severe("Failed to replace node for DownCast"); |
172 } | 190 } |
173 castNode.accept(this); | 191 castNode.accept(this); |
174 return null; | 192 return null; |
175 } | 193 } |
176 | 194 |
177 @override | 195 @override |
178 Object visitInferredTypeBase(InferredTypeBase node) { | 196 Object visitInferredTypeBase(InferredTypeBase node) { |
179 var expr = node.node; | 197 var expr = node.node; |
180 var b = _inferrer.inferExpression(expr, node.type, <String>[]); | 198 var b = _inferrer.inferExpression(expr, node.type, <String>[]); |
181 assert(b); | 199 assert(b); |
182 if (!NodeReplacer.replace(node, expr)) { | 200 if (!NodeReplacer.replace(node, expr)) { |
183 _log.severe("Failed to replace node for InferredType"); | 201 _log.severe("Failed to replace node for InferredType"); |
184 } | 202 } |
185 expr.accept(this); | 203 expr.accept(this); |
186 return null; | 204 return null; |
187 } | 205 } |
188 | 206 |
189 @override | 207 @override |
190 Object visitDownCast(DownCast node) { | 208 Object visitDownCast(DownCast node) { |
191 if (_skipCoercions) { | 209 if (_skipCoercions && !_options.allowConstCasts) { |
192 _log.severe("Skipping runtime downcast in constant context"); | 210 _log.severe("Skipping runtime downcast in constant context"); |
193 return null; | 211 return null; |
194 } | 212 } |
195 String kind = _conversionKind(node); | 213 String kind = _conversionKind(node); |
196 var loc = _locationInfo(node); | 214 var loc = _locationInfo(node); |
197 Expression castNode = _cm.coerceExpression(node.node, node.cast, kind, loc); | 215 Expression castNode = _cm.coerceExpression(node.node, node.cast, kind, loc); |
198 if (!NodeReplacer.replace(node, castNode)) { | 216 if (!NodeReplacer.replace(node, castNode)) { |
199 _log.severe("Failed to replace node for DownCast"); | 217 _log.severe("Failed to replace node for DownCast"); |
200 } | 218 } |
201 castNode.accept(this); | 219 castNode.accept(this); |
202 return null; | 220 return null; |
203 } | 221 } |
204 | 222 |
205 // TODO(leafp): Bind the coercions at the top level | 223 // TODO(leafp): Bind the coercions at the top level |
206 @override | 224 @override |
207 Object visitClosureWrapBase(ClosureWrapBase node) { | 225 Object visitClosureWrapBase(ClosureWrapBase node) { |
208 if (_skipCoercions) { | 226 if (_skipCoercions && !_options.allowConstCasts) { |
209 _log.severe("Skipping coercion wrap in constant context"); | 227 _log.severe("Skipping coercion wrap in constant context"); |
210 return null; | 228 return null; |
211 } | 229 } |
212 String kind = _conversionKind(node); | 230 String kind = _conversionKind(node); |
213 var loc = _locationInfo(node); | 231 var loc = _locationInfo(node); |
214 Expression newE = _cm.coerceExpression(node.node, node.wrapper, kind, loc); | 232 Expression newE = _cm.coerceExpression(node.node, node.wrapper, kind, loc); |
215 if (!NodeReplacer.replace(node, newE)) { | 233 if (!NodeReplacer.replace(node, newE)) { |
216 _log.severe("Failed to replace node for Closure Wrap"); | 234 _log.severe("Failed to replace node for Closure Wrap"); |
217 } | 235 } |
218 newE.accept(this); | 236 newE.accept(this); |
(...skipping 15 matching lines...) Expand all Loading... | |
234 } else if (n is ConstructorDeclaration) { | 252 } else if (n is ConstructorDeclaration) { |
235 _skipCoercions = o || n.element.isConst; | 253 _skipCoercions = o || n.element.isConst; |
236 } | 254 } |
237 } | 255 } |
238 Object ret = super.visitNode(n); | 256 Object ret = super.visitNode(n); |
239 _skipCoercions = o; | 257 _skipCoercions = o; |
240 return ret; | 258 return ret; |
241 } | 259 } |
242 | 260 |
243 Object visitCompilationUnit(CompilationUnit unit) { | 261 Object visitCompilationUnit(CompilationUnit unit) { |
244 _cm.enterCompilationUnit(); | 262 _cm.enterCompilationUnit(unit); |
245 Object ret = super.visitCompilationUnit(unit); | 263 Object ret = super.visitCompilationUnit(unit); |
246 _cm.exitCompilationUnit(unit); | 264 _cm.exitCompilationUnit(unit); |
247 return ret; | 265 return ret; |
248 } | 266 } |
249 | 267 |
250 @override | 268 @override |
251 Object visitClassDeclaration(ClassDeclaration cl) { | 269 Object visitClassDeclaration(ClassDeclaration cl) { |
252 _cm.enterClass(); | 270 _cm.enterClass(); |
253 Object ret = super.visitClassDeclaration(cl); | 271 Object ret = super.visitClassDeclaration(cl); |
254 _cm.exitClass(cl); | 272 _cm.exitClass(cl); |
255 return ret; | 273 return ret; |
256 } | 274 } |
257 } | 275 } |
258 | 276 |
259 // This provides a placeholder variable manager. Currently it simply | 277 // This provides a placeholder variable manager. Currently it simply |
260 // mangles names in a way unlikely (but not guaranteed) to avoid | 278 // mangles names in a way unlikely (but not guaranteed) to avoid |
261 // collisions with user variables. | 279 // collisions with user variables. |
262 // TODO(leafp): Replace this with something real. | 280 // TODO(leafp): Replace this with something real. |
263 class VariableManager { | 281 class VariableManager { |
264 // TODO(leafp): Hack, not for real. | 282 // TODO(leafp): Hack, not for real. |
265 int _id = 0; | 283 int _id = 0; |
266 | 284 |
267 Identifier freshIdentifier(String hint) { | 285 SimpleIdentifier freshIdentifier(String hint) { |
268 String n = _id.toString(); | 286 String n = _id.toString(); |
269 _id++; | 287 _id++; |
270 String s = "__$hint$n"; | 288 String s = "__$hint$n"; |
271 return AstBuilder.identifierFromString(s); | 289 return AstBuilder.identifierFromString(s); |
Jennifer Messerly
2015/04/16 23:31:38
it'd be worth double checking how this identifier
Leaf
2015/04/17 20:49:36
The way JS code gen currently works, I don't think
| |
272 } | 290 } |
273 | 291 |
274 Identifier freshTypeIdentifier(String hint) { | 292 SimpleIdentifier freshTypeIdentifier(String hint) { |
275 return freshIdentifier(hint); | 293 return freshIdentifier(hint); |
276 } | 294 } |
277 } | 295 } |
278 | 296 |
279 // This class manages the reification of coercions as dart code. Given a | 297 // This class manages the reification of coercions as dart code. Given a |
280 // coercion c and an expression e it will produce an expression e' which | 298 // coercion c and an expression e it will produce an expression e' which |
281 // is the result of coercing e using c. For closure wrappers, it maintains | 299 // is the result of coercing e using c. For closure wrappers, it maintains |
282 // a table of wrapper functions to be hoisted out to either the enclosing | 300 // a table of wrapper functions to be hoisted out to either the enclosing |
283 // class level, or to the top level if not in a class (hoisting only to the | 301 // class level, or to the top level if not in a class (hoisting only to the |
284 // class level avoids having to close over type variables, which is not | 302 // class level avoids having to close over type variables, which is not |
285 // easily done given the lack of generic functions). Generating the coercions | 303 // easily done given the lack of generic functions). Generating the coercions |
286 // inline is possible as well, but is quite a bit messier and harder to read | 304 // inline is possible as well, but is quite a bit messier and harder to read |
287 // since in general we need to bind the coerced expression to a lambda | 305 // since in general we need to bind the coerced expression to a lambda |
288 // bound variable, both in order to deal with side-effects and to be | 306 // bound variable, both in order to deal with side-effects and to be |
289 // able to properly record the return type of the wrapper function. | 307 // able to properly record the return type of the wrapper function. |
290 class CoercionManager { | 308 class CoercionManager { |
291 VariableManager _vm; | 309 VariableManager _vm; |
292 TypeManager _tm; | 310 TypeManager _tm; |
293 bool _hoistWrappers = false; | 311 bool _hoistWrappers = false; |
294 TypeRules _rules; | 312 TypeRules _rules; |
313 InstrumentedRuntime _runtime; | |
295 | 314 |
296 // A map containing all of the wrappers collected but not yet discharged | 315 // A map containing all of the wrappers collected but not yet discharged |
297 final Map<Identifier, _LocatedWrapper> _topWrappers = | 316 final Map<Identifier, _LocatedWrapper> _topWrappers = |
298 <Identifier, _LocatedWrapper>{}; | 317 <Identifier, _LocatedWrapper>{}; |
299 final Map<Identifier, _LocatedWrapper> _classWrappers = | 318 final Map<Identifier, _LocatedWrapper> _classWrappers = |
300 <Identifier, _LocatedWrapper>{}; | 319 <Identifier, _LocatedWrapper>{}; |
301 Map<Identifier, _LocatedWrapper> _wrappers; | 320 Map<Identifier, _LocatedWrapper> _wrappers; |
302 | 321 |
303 CoercionManager(this._vm, this._tm, this._rules) { | 322 CoercionManager(this._vm, this._tm, this._rules, [this._runtime]) { |
304 _wrappers = _topWrappers; | 323 _wrappers = _topWrappers; |
305 } | 324 } |
306 | 325 |
307 // Call on entry to and exit from a compilation unit in order to properly | 326 // Call on entry to and exit from a compilation unit in order to properly |
308 // discharge the accumulated wrappers. | 327 // discharge the accumulated wrappers. |
309 void enterCompilationUnit() { | 328 void enterCompilationUnit(CompilationUnit unit) { |
310 _tm.enterCompilationUnit(); | 329 _tm.enterCompilationUnit(unit); |
311 _wrappers = _topWrappers; | 330 _wrappers = _topWrappers; |
312 } | 331 } |
313 void exitCompilationUnit(CompilationUnit unit) { | 332 void exitCompilationUnit(CompilationUnit unit) { |
314 for (Identifier i in _wrappers.keys) { | 333 for (Identifier i in _wrappers.keys) { |
315 FunctionDeclaration f = | 334 FunctionDeclaration f = |
316 _buildCoercion(i, _wrappers[i].wrapper, _wrappers[i].loc, true); | 335 _buildCoercion(i, _wrappers[i].wrapper, _wrappers[i].loc, true); |
317 unit.declarations.add(f); | 336 unit.declarations.add(f); |
318 } | 337 } |
319 _wrappers.clear(); | 338 _wrappers.clear(); |
320 _wrappers = _topWrappers; | 339 _wrappers = _topWrappers; |
(...skipping 30 matching lines...) Expand all Loading... | |
351 return new Tuple2(e1, (e2) => e2); | 370 return new Tuple2(e1, (e2) => e2); |
352 } | 371 } |
353 var id = _vm.freshIdentifier(hint); | 372 var id = _vm.freshIdentifier(hint); |
354 var fp = AstBuilder.simpleFormal(id, null); | 373 var fp = AstBuilder.simpleFormal(id, null); |
355 f(e2) => AstBuilder.parenthesize(AstBuilder.letExpression(fp, e1, e2)); | 374 f(e2) => AstBuilder.parenthesize(AstBuilder.letExpression(fp, e1, e2)); |
356 return new Tuple2(id, f); | 375 return new Tuple2(id, f); |
357 } | 376 } |
358 | 377 |
359 Expression _wrapExpression(Expression e, Wrapper w, String k, String loc) { | 378 Expression _wrapExpression(Expression e, Wrapper w, String k, String loc) { |
360 var q = _addWrapper(w, loc); | 379 var q = _addWrapper(w, loc); |
380 if (_runtime == null) { | |
381 var app = AstBuilder.application(q, <Expression>[e]); | |
382 app.staticType = w.toType; | |
383 return app; | |
384 } | |
361 var ttName = _tm.typeNameFromDartType(w.toType); | 385 var ttName = _tm.typeNameFromDartType(w.toType); |
362 var tt = _tm.typeExpression(ttName); | 386 var tt = _tm.typeExpression(ttName); |
363 var ft = _tm.typeExpressionFromDartType(w.fromType); | 387 var ft = _tm.typeExpressionFromDartType(w.fromType); |
364 if (w.fromType.element.library != null && | 388 if (w.fromType.element.library != null && |
365 utils.isDartPrivateLibrary(w.fromType.element.library)) { | 389 utils.isDartPrivateLibrary(w.fromType.element.library)) { |
366 ft = AstBuilder.nullLiteral(); | 390 ft = AstBuilder.nullLiteral(); |
367 } | 391 } |
368 var tup = _bindExpression("x", e); | 392 var tup = _bindExpression("x", e); |
369 var id = tup.e0; | 393 var id = tup.e0; |
370 var binder = tup.e1; | 394 var binder = tup.e1; |
371 var kind = AstBuilder.stringLiteral(k); | |
372 var key = AstBuilder.multiLineStringLiteral(loc); | |
373 var dartIs = AstBuilder.isExpression(AstBuilder.parenthesize(id), ttName); | 395 var dartIs = AstBuilder.isExpression(AstBuilder.parenthesize(id), ttName); |
374 var arguments = <Expression>[q, id, ft, tt, kind, key, dartIs]; | 396 var oper = _runtime.wrap(q, id, ft, tt, dartIs, k, loc); |
375 return binder(new RuntimeOperation("wrap", arguments)); | 397 return binder(oper); |
376 } | 398 } |
377 | 399 |
378 Expression _castExpression(Expression e, Cast c, String k, String loc) { | 400 Expression _castExpression(Expression e, Cast c, String k, String loc) { |
379 var ttName = _tm.typeNameFromDartType(c.toType); | 401 var ttName = _tm.typeNameFromDartType(c.toType); |
402 if (_runtime == null) { | |
403 var cast = AstBuilder.asExpression(e, ttName); | |
404 cast.staticType = c.toType; | |
405 return cast; | |
406 } | |
380 var tt = _tm.typeExpression(ttName); | 407 var tt = _tm.typeExpression(ttName); |
381 var ft = _tm.typeExpressionFromDartType(c.fromType); | 408 var ft = _tm.typeExpressionFromDartType(c.fromType); |
382 if (c.fromType.element == null) { | 409 if (c.fromType.element == null) { |
383 // Replace bottom with Null type. | 410 // Replace bottom with Null type. |
384 var ftType = _rules.provider.nullType; | 411 var ftType = _rules.provider.nullType; |
385 ft = _tm.typeExpressionFromDartType(ftType); | 412 ft = _tm.typeExpressionFromDartType(ftType); |
386 } else if (c.fromType.element.library != null && | 413 } else if (c.fromType.element.library != null && |
387 utils.isDartPrivateLibrary(c.fromType.element.library)) { | 414 utils.isDartPrivateLibrary(c.fromType.element.library)) { |
388 ft = AstBuilder.nullLiteral(); | 415 ft = AstBuilder.nullLiteral(); |
389 } | 416 } |
390 var tup = _bindExpression("x", e); | 417 var tup = _bindExpression("x", e); |
391 var id = tup.e0; | 418 var id = tup.e0; |
392 var binder = tup.e1; | 419 var binder = tup.e1; |
393 var kind = AstBuilder.stringLiteral(k); | |
394 var key = AstBuilder.multiLineStringLiteral(loc); | |
395 var dartIs = AstBuilder.isExpression(AstBuilder.parenthesize(id), ttName); | 420 var dartIs = AstBuilder.isExpression(AstBuilder.parenthesize(id), ttName); |
396 var ground = AstBuilder.booleanLiteral(_rules.isGroundType(c.toType)); | 421 var ground = _rules.isGroundType(c.toType); |
397 var arguments = <Expression>[id, ft, tt, kind, key, dartIs, ground]; | 422 var oper = _runtime.cast(id, ft, tt, dartIs, k, loc, ground); |
398 return binder(new RuntimeOperation("cast", arguments)); | 423 return binder(oper); |
399 } | 424 } |
400 | 425 |
401 Expression _coerceExpression( | 426 Expression _coerceExpression( |
402 Expression e, Coercion c, String kind, String loc) { | 427 Expression e, Coercion c, String kind, String loc) { |
403 assert(c != null); | 428 assert(c != null); |
404 assert(c is! CoercionError); | 429 assert(c is! CoercionError); |
405 if (e is NamedExpression) { | 430 if (e is NamedExpression) { |
406 Expression inner = _coerceExpression(e.expression, c, kind, loc); | 431 Expression inner = _coerceExpression(e.expression, c, kind, loc); |
407 return new NamedExpression(e.name, inner); | 432 return new NamedExpression(e.name, inner); |
408 } | 433 } |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
547 // and the AST type representation. It provides utilities to translate | 572 // and the AST type representation. It provides utilities to translate |
548 // a DartType to AST. In order to do so, it maintains a map of typedefs | 573 // a DartType to AST. In order to do so, it maintains a map of typedefs |
549 // naming otherwise un-named types. These must be discharged at the top | 574 // naming otherwise un-named types. These must be discharged at the top |
550 // level of the compilation unit in order to produce well-formed dart code. | 575 // level of the compilation unit in order to produce well-formed dart code. |
551 // Note that in order to hoist the typedefs out of parameterized classes | 576 // Note that in order to hoist the typedefs out of parameterized classes |
552 // we must close over any type variables. | 577 // we must close over any type variables. |
553 class TypeManager { | 578 class TypeManager { |
554 final VariableManager _vm; | 579 final VariableManager _vm; |
555 final LibraryElement _currentLibrary; | 580 final LibraryElement _currentLibrary; |
556 final Map<Identifier, NewTypeIdDesc> addedTypes = {}; | 581 final Map<Identifier, NewTypeIdDesc> addedTypes = {}; |
582 final InstrumentedRuntime _runtime; | |
583 CompilationUnitElement _currentUnit; | |
557 | 584 |
558 /// A map containing new function typedefs to be introduced at the top level | 585 /// A map containing new function typedefs to be introduced at the top level |
559 /// This uses LinkedHashMap to emit code in a consistent order. | 586 /// This uses LinkedHashMap to emit code in a consistent order. |
560 final Map<FunctionType, FunctionTypeAlias> _typedefs = {}; | 587 final Map<FunctionType, FunctionTypeAlias> _typedefs = {}; |
561 | 588 |
562 TypeManager(this._currentLibrary, this._vm); | 589 TypeManager(this._currentLibrary, this._vm, [this._runtime]); |
563 | 590 |
564 void enterCompilationUnit() {} | 591 void enterCompilationUnit(CompilationUnit unit) { |
592 _currentUnit = unit.element; | |
593 } | |
594 | |
565 void exitCompilationUnit(CompilationUnit unit) { | 595 void exitCompilationUnit(CompilationUnit unit) { |
566 unit.declarations.addAll(_typedefs.values); | 596 unit.declarations.addAll(_typedefs.values); |
567 _typedefs.clear(); | 597 _typedefs.clear(); |
568 } | 598 } |
569 | 599 |
570 TypeName typeNameFromDartType(DartType dType) { | 600 TypeName typeNameFromDartType(DartType dType) { |
571 return _typeNameFromDartType(dType); | 601 return _typeNameFromDartType(dType); |
572 } | 602 } |
573 | 603 |
574 NormalFormalParameter typedFormal(Identifier v, DartType type) { | 604 NormalFormalParameter typedFormal(Identifier v, DartType type) { |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
624 _ft(type); | 654 _ft(type); |
625 return s.toList(); | 655 return s.toList(); |
626 } | 656 } |
627 | 657 |
628 List<FormalParameter> _formalParameterListForFunctionType(FunctionType type) { | 658 List<FormalParameter> _formalParameterListForFunctionType(FunctionType type) { |
629 var namedParameters = type.namedParameterTypes; | 659 var namedParameters = type.namedParameterTypes; |
630 var normalParameters = type.normalParameterTypes; | 660 var normalParameters = type.normalParameterTypes; |
631 var optionalParameters = type.optionalParameterTypes; | 661 var optionalParameters = type.optionalParameterTypes; |
632 var params = new List<FormalParameter>(); | 662 var params = new List<FormalParameter>(); |
633 for (int i = 0; i < normalParameters.length; i++) { | 663 for (int i = 0; i < normalParameters.length; i++) { |
634 FormalParameter fp = _anonymousFormal(normalParameters[i]); | 664 FormalParameter fp = |
635 params.add(AstBuilder.requiredFormal(fp)); | 665 AstBuilder.requiredFormal(_anonymousFormal(normalParameters[i])); |
666 ParameterElementImpl fe = new ParameterElementImpl.forNode(fp.identifier); | |
667 fe.parameterKind = fp.kind; | |
668 fe.type = normalParameters[i]; | |
669 fp.identifier.staticElement = fe; | |
670 params.add(fp); | |
636 } | 671 } |
637 for (int i = 0; i < optionalParameters.length; i++) { | 672 for (int i = 0; i < optionalParameters.length; i++) { |
638 FormalParameter fp = _anonymousFormal(optionalParameters[i]); | 673 FormalParameter fp = |
639 params.add(AstBuilder.optionalFormal(fp)); | 674 AstBuilder.optionalFormal(_anonymousFormal(optionalParameters[i])); |
675 ParameterElementImpl fe = new ParameterElementImpl.forNode(fp.identifier); | |
Jennifer Messerly
2015/04/16 23:31:38
maybe try to encapsulate this? it seems like we're
Leaf
2015/04/17 20:49:35
Done.
| |
676 fe.parameterKind = fp.kind; | |
677 fe.type = optionalParameters[i]; | |
678 fp.identifier.staticElement = fe; | |
679 params.add(fp); | |
640 } | 680 } |
641 for (String k in namedParameters.keys) { | 681 for (String k in namedParameters.keys) { |
642 FormalParameter fp = _anonymousFormal(namedParameters[k]); | 682 FormalParameter fp = |
643 params.add(AstBuilder.namedFormal(fp)); | 683 AstBuilder.namedFormal(_anonymousFormal(namedParameters[k])); |
684 ParameterElementImpl fe = new ParameterElementImpl.forNode(fp.identifier); | |
685 fe.parameterKind = fp.kind; | |
686 fe.type = namedParameters[k]; | |
687 fp.identifier.staticElement = fe; | |
688 params.add(fp); | |
644 } | 689 } |
645 return params; | 690 return params; |
646 } | 691 } |
647 | 692 |
648 FormalParameter _functionTypedFormal(Identifier v, FunctionType type) { | 693 FormalParameter _functionTypedFormal(Identifier v, FunctionType type) { |
649 assert(v != null); | 694 assert(v != null); |
650 var params = _formalParameterListForFunctionType(type); | 695 var params = _formalParameterListForFunctionType(type); |
651 var ret = typeNameFromDartType(type.returnType); | 696 var ret = typeNameFromDartType(type.returnType); |
652 return AstBuilder.functionTypedFormal(ret, v, params); | 697 return AstBuilder.functionTypedFormal(ret, v, params); |
653 } | 698 } |
654 | 699 |
655 NormalFormalParameter _anonymousFormal(DartType type) { | 700 NormalFormalParameter _anonymousFormal(DartType type) { |
656 Identifier u = _vm.freshIdentifier("u"); | 701 Identifier u = _vm.freshIdentifier("u"); |
657 return _typedFormal(u, type); | 702 return _typedFormal(u, type); |
658 } | 703 } |
659 | 704 |
660 NormalFormalParameter _typedFormal(Identifier v, DartType type) { | 705 NormalFormalParameter _typedFormal(Identifier v, DartType type) { |
661 if (type is FunctionType) { | 706 if (type is FunctionType) { |
662 return _functionTypedFormal(v, type); | 707 return _functionTypedFormal(v, type); |
663 } | 708 } |
664 assert(type.name != null); | 709 assert(type.name != null); |
665 TypeName t = typeNameFromDartType(type); | 710 TypeName t = typeNameFromDartType(type); |
666 return AstBuilder.simpleFormal(v, t); | 711 return AstBuilder.simpleFormal(v, t); |
667 } | 712 } |
668 | 713 |
669 Identifier freshTypeDefVariable() { | 714 SimpleIdentifier freshTypeDefVariable() { |
670 var t = _vm.freshTypeIdentifier("t"); | 715 var t = _vm.freshTypeIdentifier("t"); |
671 var desc = new NewTypeIdDesc( | 716 var desc = new NewTypeIdDesc( |
672 fromCurrent: true, importedFrom: _currentLibrary, synthetic: true); | 717 fromCurrent: true, importedFrom: _currentLibrary, synthetic: true); |
673 addedTypes[t] = desc; | 718 addedTypes[t] = desc; |
674 return t; | 719 return t; |
675 } | 720 } |
676 | 721 |
677 Identifier typeParameterFromString(String name) => | 722 SimpleIdentifier typeParameterFromString(String name) => |
678 AstBuilder.identifierFromString(name); | 723 AstBuilder.identifierFromString(name); |
679 | 724 |
680 Identifier freshReferenceToNamedType(DartType type) { | 725 SimpleIdentifier freshReferenceToNamedType(DartType type) { |
681 var name = type.name; | 726 var name = type.name; |
682 assert(name != null); | 727 assert(name != null); |
683 var id = AstBuilder.identifierFromString(name); | 728 var id = AstBuilder.identifierFromString(name); |
684 var element = type.element; | 729 var element = type.element; |
685 id.staticElement = element; | 730 id.staticElement = element; |
686 var library = null; | 731 var library = null; |
687 // This can happen for types like (e.g.) void | 732 // This can happen for types like (e.g.) void |
688 if (element != null) library = element.library; | 733 if (element != null) library = element.library; |
689 var desc = new NewTypeIdDesc( | 734 var desc = new NewTypeIdDesc( |
690 fromCurrent: _currentLibrary == library, | 735 fromCurrent: _currentLibrary == library, |
691 importedFrom: library, | 736 importedFrom: library, |
692 synthetic: false); | 737 synthetic: false); |
693 addedTypes[id] = desc; | 738 addedTypes[id] = desc; |
694 return id; | 739 return id; |
695 } | 740 } |
696 | 741 |
742 FunctionTypeAlias _newResolvedTypedef( | |
743 FunctionType type, List<TypeParameterType> ftvs) { | |
744 | |
745 // The name of the typedef (unresolved at this point) | |
Jennifer Messerly
2015/04/16 23:31:38
maybe a TODO for now and we can fix later, but: it
Leaf
2015/04/17 20:49:36
Suggestions as to meaningful names? I made the hi
| |
746 SimpleIdentifier t = freshTypeDefVariable(); | |
747 // The element for the new typedef | |
748 var element = new FunctionTypeAliasElementImpl(t.name, 0); | |
749 | |
750 // Fresh type parameter identifiers for the free type variables | |
751 List<Identifier> tNames = | |
752 ftvs.map((x) => typeParameterFromString(x.name)).toList(); | |
753 // The type parameters themselves | |
754 List<TypeParameter> tps = tNames.map(AstBuilder.typeParameter).toList(); | |
755 // Allocate the elements for the type parameters, fill in their | |
756 // type (which makes no sense) and link up the various elements | |
757 // For each type parameter identifier, make an element and a type | |
758 // with that element, link the two together, set the identifier element | |
759 // to that element, and the identifier type to that type. | |
760 List<TypeParameterElement> tElements = tNames.map((x) { | |
761 var element = new TypeParameterElementImpl(x.name, 0); | |
762 var type = new TypeParameterTypeImpl(element); | |
763 element.type = type; | |
764 x.staticElement = element; | |
765 x.staticType = type; | |
766 return element; | |
767 }).toList(); | |
768 // Get the types out from the elements | |
769 List<TypeParameterType> tTypes = tElements.map((x) => x.type).toList(); | |
770 // Take the return type from the original type, and replace the free | |
771 // type variables with the fresh type variables | |
772 element.returnType = type.returnType.substitute2(tTypes, ftvs); | |
773 // Set the type parameter elements | |
774 element.typeParameters = tElements; | |
775 // Set the parent element to the current compilation unit | |
776 element.enclosingElement = _currentUnit; | |
777 | |
778 // This is the type corresponding to the typedef. Note that | |
779 // almost all methods on this type delegate to the element, so it | |
780 // cannot be safely be used for anything until the element is fully resolved | |
781 FunctionTypeImpl substType = new FunctionTypeImpl.con2(element); | |
782 element.type = substType; | |
783 // Link the type and the element into the identifier for the typedef | |
784 t.staticType = substType; | |
785 t.staticElement = element; | |
786 | |
787 // Make the formal parameters for the typedef, using the original type | |
788 // with the fresh type variables substituted in. | |
789 List<FormalParameter> fps = | |
790 _formalParameterListForFunctionType(type.substitute2(tTypes, ftvs)); | |
791 // Get the static elements out of the parameters, and use them to | |
792 // initialize the parameters in the element model | |
793 element.parameters = fps.map((x) => x.identifier.staticElement).toList(); | |
794 // Build the return type syntax | |
795 TypeName ret = _typeNameFromDartType(substType.returnType); | |
796 // This should now be fully resolved (or at least enough so for things | |
797 // to work so far). | |
798 FunctionTypeAlias alias = AstBuilder.functionTypeAlias(ret, t, tps, fps); | |
799 | |
800 return alias; | |
801 } | |
802 | |
697 // I think we can avoid alpha-varying type parameters, since | 803 // I think we can avoid alpha-varying type parameters, since |
698 // the binding forms are so limited, so we just re-use the | 804 // the binding forms are so limited, so we just re-use the |
699 // the original names for the formals and the actuals. | 805 // the original names for the formals and the actuals. |
700 TypeName _typeNameFromFunctionType(FunctionType type) { | 806 TypeName _typeNameFromFunctionType(FunctionType type) { |
701 if (_typedefs.containsKey(type)) { | 807 if (_typedefs.containsKey(type)) { |
702 var alias = _typedefs[type]; | 808 var alias = _typedefs[type]; |
703 var ts = null; | 809 var ts = null; |
704 var tpl = alias.typeParameters; | 810 var tpl = alias.typeParameters; |
705 if (tpl != null) { | 811 if (tpl != null) { |
706 var ltp = tpl.typeParameters; | 812 var ltp = tpl.typeParameters; |
707 ts = new List<TypeName>.from( | 813 ts = new List<TypeName>.from( |
708 ltp.map((t) => _mkNewTypeName(t.name, null))); | 814 ltp.map((t) => _mkNewTypeName(null, t.name, null))); |
709 } | 815 } |
710 var name = alias.name; | 816 var name = alias.name; |
711 return _mkNewTypeName(name, ts); | 817 return _mkNewTypeName(type, name, ts); |
712 } | 818 } |
713 | 819 |
714 List<TypeParameterType> ftvs = _freeTypeVariables(type); | 820 List<TypeParameterType> ftvs = _freeTypeVariables(type); |
715 Identifier t = freshTypeDefVariable(); | 821 FunctionTypeAlias alias = _newResolvedTypedef(type, ftvs); |
716 | |
717 Iterable<Identifier> tNames = | |
718 ftvs.map((x) => typeParameterFromString(x.name)); | |
719 List<TypeParameter> tps = tNames.map(AstBuilder.typeParameter).toList(); | |
720 List<FormalParameter> fps = _formalParameterListForFunctionType(type); | |
721 TypeName ret = _typeNameFromDartType(type.returnType); | |
722 FunctionTypeAlias alias = AstBuilder.functionTypeAlias(ret, t, tps, fps); | |
723 | |
724 _typedefs[type] = alias; | 822 _typedefs[type] = alias; |
725 | 823 |
726 List<TypeName> args = ftvs.map(_typeNameFromDartType).toList(); | 824 List<TypeName> args = ftvs.map(_typeNameFromDartType).toList(); |
727 TypeName namedType = _mkNewTypeName(t, args); | 825 TypeName namedType = |
826 _mkNewTypeName(alias.name.staticType, alias.name, args); | |
728 | 827 |
729 return namedType; | 828 return namedType; |
730 } | 829 } |
731 | 830 |
732 TypeName _typeNameFromDartType(DartType dType) { | 831 TypeName _typeNameFromDartType(DartType dType) { |
733 String name = dType.name; | 832 String name = dType.name; |
734 if (name == null || name == "" || dType.isBottom) { | 833 if (name == null || name == "" || dType.isBottom) { |
735 if (dType is FunctionType) return _typeNameFromFunctionType(dType); | 834 if (dType is FunctionType) return _typeNameFromFunctionType(dType); |
736 _log.severe("No name for type, casting through dynamic"); | 835 _log.severe("No name for type, casting through dynamic"); |
737 var d = AstBuilder.identifierFromString("dynamic"); | 836 var d = AstBuilder.identifierFromString("dynamic"); |
738 var t = _mkNewTypeName(d, null); | 837 var t = _mkNewTypeName(dType, d, null); |
739 t.type = dType; | |
740 return t; | 838 return t; |
741 } | 839 } |
742 SimpleIdentifier id = freshReferenceToNamedType(dType); | 840 SimpleIdentifier id = freshReferenceToNamedType(dType); |
743 List<TypeName> args = null; | 841 List<TypeName> args = null; |
744 if (dType is ParameterizedType) { | 842 if (dType is ParameterizedType) { |
745 List<DartType> targs = dType.typeArguments; | 843 List<DartType> targs = dType.typeArguments; |
746 args = targs.map(_typeNameFromDartType).toList(); | 844 args = targs.map(_typeNameFromDartType).toList(); |
747 } | 845 } |
748 var t = _mkNewTypeName(id, args); | 846 var t = _mkNewTypeName(dType, id, args); |
749 t.type = dType; | |
750 return t; | 847 return t; |
751 } | 848 } |
752 | 849 |
753 TypeName _mkNewTypeName(Identifier id, List<TypeName> args) { | 850 TypeName _mkNewTypeName(DartType type, Identifier id, List<TypeName> args) { |
754 var t = AstBuilder.typeName(id, args); | 851 var t = AstBuilder.typeName(id, args); |
852 t.type = type; | |
755 return t; | 853 return t; |
756 } | 854 } |
757 | 855 |
758 Expression _typeExpression(TypeName t) { | 856 Expression _typeExpression(TypeName t) { |
857 assert(_runtime != null); | |
759 if (t.typeArguments != null && t.typeArguments.length > 0) { | 858 if (t.typeArguments != null && t.typeArguments.length > 0) { |
760 var w = AstBuilder.identifierFromString("_"); | 859 var w = AstBuilder.identifierFromString("_"); |
761 var fp = AstBuilder.simpleFormal(w, t); | 860 var fp = AstBuilder.simpleFormal(w, t); |
762 var f = AstBuilder.blockFunction(<FormalParameter>[fp], <Statement>[]); | 861 var f = AstBuilder.blockFunction(<FormalParameter>[fp], <Statement>[]); |
763 return new RuntimeOperation("type", <Expression>[f]); | 862 return _runtime.type(f); |
764 } | 863 } |
765 return t.name; | 864 return t.name; |
766 } | 865 } |
767 } | 866 } |
OLD | NEW |