| 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:analyzer/src/generated/engine.dart' show AnalysisContext; | |
| 11 import 'package:logging/logging.dart' as logger; | 10 import 'package:logging/logging.dart' as logger; |
| 12 | 11 |
| 13 import 'package:dev_compiler/devc.dart' show AbstractCompiler; | 12 import 'package:dev_compiler/devc.dart' show AbstractCompiler; |
| 14 import 'package:dev_compiler/src/checker/rules.dart'; | 13 import 'package:dev_compiler/src/checker/rules.dart'; |
| 15 import 'package:dev_compiler/src/info.dart'; | 14 import 'package:dev_compiler/src/info.dart'; |
| 16 import 'package:dev_compiler/src/options.dart' show CompilerOptions; | 15 import 'package:dev_compiler/src/options.dart' show CompilerOptions; |
| 17 import 'package:dev_compiler/src/utils.dart' as utils; | |
| 18 | 16 |
| 19 import 'ast_builder.dart'; | 17 import 'ast_builder.dart'; |
| 20 | 18 |
| 21 final _log = new logger.Logger('dev_compiler.reify_coercions'); | 19 final _log = new logger.Logger('dev_compiler.reify_coercions'); |
| 22 | 20 |
| 23 // TODO(leafp) Factor this out or use an existing library | 21 // TODO(leafp) Factor this out or use an existing library |
| 24 class Tuple2<T0, T1> { | 22 class Tuple2<T0, T1> { |
| 25 final T0 e0; | 23 final T0 e0; |
| 26 final T1 e1; | 24 final T1 e1; |
| 27 Tuple2(this.e0, this.e1); | 25 Tuple2(this.e0, this.e1); |
| 28 } | 26 } |
| 29 | 27 |
| 30 typedef T Function1<S, T>(S _); | 28 typedef T Function1<S, T>(S _); |
| 31 | 29 |
| 32 class NewTypeIdDesc { | 30 class NewTypeIdDesc { |
| 33 /// If null, then this is not a library level identifier (i.e. it's | 31 /// If null, then this is not a library level identifier (i.e. it's |
| 34 /// a type parameter, or a special type like void, dynamic, etc) | 32 /// a type parameter, or a special type like void, dynamic, etc) |
| 35 LibraryElement importedFrom; | 33 LibraryElement importedFrom; |
| 36 /// True => use/def in same library | 34 /// True => use/def in same library |
| 37 bool fromCurrent; | 35 bool fromCurrent; |
| 38 /// True => not a source variable | 36 /// True => not a source variable |
| 39 bool synthetic; | 37 bool synthetic; |
| 40 NewTypeIdDesc({this.fromCurrent, this.importedFrom, this.synthetic}); | 38 NewTypeIdDesc({this.fromCurrent, this.importedFrom, this.synthetic}); |
| 41 } | 39 } |
| 42 | 40 |
| 43 class _LocatedWrapper { | |
| 44 final String loc; | |
| 45 final Wrapper wrapper; | |
| 46 _LocatedWrapper(this.wrapper, this.loc); | |
| 47 } | |
| 48 | |
| 49 abstract class InstrumentedRuntime { | |
| 50 Expression wrap(Expression coercion, Expression e, Expression fromType, | |
| 51 Expression toType, Expression dartIs, String kind, String location); | |
| 52 Expression cast(Expression e, Expression fromType, Expression toType, | |
| 53 Expression dartIs, String kind, String location, bool ground); | |
| 54 Expression type(Expression witnessFunction); | |
| 55 } | |
| 56 | |
| 57 class _Inference extends DownwardsInference { | 41 class _Inference extends DownwardsInference { |
| 58 TypeManager _tm; | 42 TypeManager _tm; |
| 59 | 43 |
| 60 _Inference(TypeRules rules, this._tm) : super(rules); | 44 _Inference(TypeRules rules, this._tm) : super(rules); |
| 61 | 45 |
| 62 @override | 46 @override |
| 63 void annotateCastFromDynamic(Expression e, DartType t) { | 47 void annotateCastFromDynamic(Expression e, DartType t) { |
| 64 var cast = Coercion.cast(e.staticType, t); | 48 var cast = Coercion.cast(e.staticType, t); |
| 65 var node = new DynamicCast(rules, e, cast); | 49 var node = new DynamicCast(rules, e, cast); |
| 66 if (!NodeReplacer.replace(e, node)) { | 50 if (!NodeReplacer.replace(e, node)) { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 102 void annotateFunctionExpression(FunctionExpression e, DartType returnType) { | 86 void annotateFunctionExpression(FunctionExpression e, DartType returnType) { |
| 103 // Implicitly changes e.staticType | 87 // Implicitly changes e.staticType |
| 104 (e.element as ExecutableElementImpl).returnType = returnType; | 88 (e.element as ExecutableElementImpl).returnType = returnType; |
| 105 } | 89 } |
| 106 } | 90 } |
| 107 | 91 |
| 108 // This class implements a pass which modifies (in place) the ast replacing | 92 // This class implements a pass which modifies (in place) the ast replacing |
| 109 // abstract coercion nodes with their dart implementations. | 93 // abstract coercion nodes with their dart implementations. |
| 110 class CoercionReifier extends analyzer.GeneralizingAstVisitor<Object> | 94 class CoercionReifier extends analyzer.GeneralizingAstVisitor<Object> |
| 111 with ConversionVisitor<Object> { | 95 with ConversionVisitor<Object> { |
| 112 final AnalysisContext _context; | |
| 113 final CoercionManager _cm; | 96 final CoercionManager _cm; |
| 114 final TypeManager _tm; | 97 final TypeManager _tm; |
| 115 final VariableManager _vm; | 98 final VariableManager _vm; |
| 116 final LibraryUnit _library; | 99 final LibraryUnit _library; |
| 117 bool _skipCoercions = false; | 100 bool _skipCoercions = false; |
| 118 final TypeRules _rules; | |
| 119 final _Inference _inferrer; | 101 final _Inference _inferrer; |
| 120 final InstrumentedRuntime _runtime; | |
| 121 final CompilerOptions _options; | 102 final CompilerOptions _options; |
| 122 | 103 |
| 123 CompilationUnit _unit; | 104 CoercionReifier._(this._cm, this._tm, this._vm, this._library, this._inferrer, |
| 105 this._options); |
| 124 | 106 |
| 125 CoercionReifier._(this._cm, this._tm, this._vm, this._library, this._rules, | 107 factory CoercionReifier(LibraryUnit library, AbstractCompiler compiler) { |
| 126 this._inferrer, this._runtime, this._context, this._options); | |
| 127 | |
| 128 factory CoercionReifier(LibraryUnit library, AbstractCompiler compiler, | |
| 129 [InstrumentedRuntime runtime]) { | |
| 130 var vm = new VariableManager(); | 108 var vm = new VariableManager(); |
| 131 var tm = | 109 var tm = new TypeManager(library.library.element.enclosingElement, vm); |
| 132 new TypeManager(library.library.element.enclosingElement, vm, runtime); | 110 var cm = new CoercionManager(vm, tm); |
| 133 var rules = compiler.rules; | 111 var inferrer = new _Inference(compiler.rules, tm); |
| 134 var cm = new CoercionManager(vm, tm, rules, runtime); | |
| 135 var inferrer = new _Inference(rules, tm); | |
| 136 var context = compiler.context; | |
| 137 var options = compiler.options; | 112 var options = compiler.options; |
| 138 return new CoercionReifier._( | 113 return new CoercionReifier._(cm, tm, vm, library, inferrer, options); |
| 139 cm, tm, vm, library, rules, inferrer, runtime, context, options); | |
| 140 } | 114 } |
| 141 | 115 |
| 142 // This should be the entry point for this class. Entering via the | 116 // This should be the entry point for this class. Entering via the |
| 143 // visit functions directly may not do the right thing with respect | 117 // visit functions directly may not do the right thing with respect |
| 144 // to discharging the collected definitions. | 118 // to discharging the collected definitions. |
| 145 // Returns the set of new type identifiers added by the reifier | 119 // Returns the set of new type identifiers added by the reifier |
| 146 Map<Identifier, NewTypeIdDesc> reify() { | 120 Map<Identifier, NewTypeIdDesc> reify() { |
| 147 _library.partsThenLibrary.forEach(generateUnit); | 121 _library.partsThenLibrary.forEach(generateUnit); |
| 148 return _tm.addedTypes; | 122 return _tm.addedTypes; |
| 149 } | 123 } |
| 150 | 124 |
| 151 void generateUnit(CompilationUnit unit) { | 125 void generateUnit(CompilationUnit unit) { |
| 152 _unit = unit; | |
| 153 visitCompilationUnit(unit); | 126 visitCompilationUnit(unit); |
| 154 _unit = null; | |
| 155 } | 127 } |
| 156 | 128 |
| 157 ///////////////// Private ////////////////////////////////// | 129 ///////////////// Private ////////////////////////////////// |
| 158 | 130 |
| 159 String _locationInfo(Expression e) { | |
| 160 if (_unit != null) { | |
| 161 final begin = e is AnnotatedNode | |
| 162 ? (e as AnnotatedNode).firstTokenAfterCommentAndMetadata.offset | |
| 163 : e.offset; | |
| 164 if (begin != 0 && e.end > begin) { | |
| 165 var span = utils.createSpan(_context, _unit, begin, e.end); | |
| 166 var s = span.message("Cast"); | |
| 167 return s.substring(0, s.indexOf("Cast")); | |
| 168 } | |
| 169 } | |
| 170 return null; | |
| 171 } | |
| 172 | |
| 173 static String _conversionKind(Conversion node) { | |
| 174 if (node is ClosureWrapLiteral) return "WrapLiteral"; | |
| 175 if (node is ClosureWrap) return "Wrap"; | |
| 176 if (node is DynamicCast) return "DynamicCast"; | |
| 177 if (node is AssignmentCast) return "AssignmentCast"; | |
| 178 if (node is UninferredClosure) return "InferableClosure"; | |
| 179 if (node is DownCastComposite) return "CompositeCast"; | |
| 180 if (node is DownCastImplicit) return "ImplicitCast"; | |
| 181 assert(false); | |
| 182 return ""; | |
| 183 } | |
| 184 | |
| 185 @override | |
| 186 Object visitAsExpression(AsExpression e) { | |
| 187 if (_runtime == null) return super.visitAsExpression(e); | |
| 188 var cast = Coercion.cast(_rules.getStaticType(e.expression), e.type.type); | |
| 189 var loc = _locationInfo(e); | |
| 190 Expression castNode = | |
| 191 _cm.coerceExpression(e.expression, cast, "CastUser", loc); | |
| 192 if (!NodeReplacer.replace(e, castNode)) { | |
| 193 _log.severe("Failed to replace node for DownCast"); | |
| 194 } | |
| 195 castNode.accept(this); | |
| 196 return null; | |
| 197 } | |
| 198 | |
| 199 @override | 131 @override |
| 200 Object visitInferredTypeBase(InferredTypeBase node) { | 132 Object visitInferredTypeBase(InferredTypeBase node) { |
| 201 var expr = node.node; | 133 var expr = node.node; |
| 202 var b = _inferrer.inferExpression(expr, node.type, <String>[]); | 134 var b = _inferrer.inferExpression(expr, node.type, <String>[]); |
| 203 assert(b); | 135 assert(b); |
| 204 if (!NodeReplacer.replace(node, expr)) { | 136 if (!NodeReplacer.replace(node, expr)) { |
| 205 _log.severe("Failed to replace node for InferredType"); | 137 _log.severe("Failed to replace node for InferredType"); |
| 206 } | 138 } |
| 207 expr.accept(this); | 139 expr.accept(this); |
| 208 return null; | 140 return null; |
| 209 } | 141 } |
| 210 | 142 |
| 211 @override | 143 @override |
| 212 Object visitDownCast(DownCast node) { | 144 Object visitDownCast(DownCast node) { |
| 213 if (_skipCoercions && !_options.allowConstCasts) { | 145 if (_skipCoercions && !_options.allowConstCasts) { |
| 214 _log.severe("Skipping runtime downcast in constant context"); | 146 _log.severe("Skipping runtime downcast in constant context"); |
| 215 return null; | 147 return null; |
| 216 } | 148 } |
| 217 String kind = _conversionKind(node); | 149 Expression castNode = _cm.coerceExpression(node.node, node.cast); |
| 218 var loc = _locationInfo(node); | |
| 219 Expression castNode = _cm.coerceExpression(node.node, node.cast, kind, loc); | |
| 220 if (!NodeReplacer.replace(node, castNode)) { | 150 if (!NodeReplacer.replace(node, castNode)) { |
| 221 _log.severe("Failed to replace node for DownCast"); | 151 _log.severe("Failed to replace node for DownCast"); |
| 222 } | 152 } |
| 223 castNode.accept(this); | 153 castNode.accept(this); |
| 224 return null; | 154 return null; |
| 225 } | 155 } |
| 226 | 156 |
| 227 // TODO(leafp): Bind the coercions at the top level | 157 // TODO(leafp): Bind the coercions at the top level |
| 228 @override | 158 @override |
| 229 Object visitClosureWrapBase(ClosureWrapBase node) { | 159 Object visitClosureWrapBase(ClosureWrapBase node) { |
| 230 if (_skipCoercions && !_options.allowConstCasts) { | 160 if (_skipCoercions && !_options.allowConstCasts) { |
| 231 _log.severe("Skipping coercion wrap in constant context"); | 161 _log.severe("Skipping coercion wrap in constant context"); |
| 232 return null; | 162 return null; |
| 233 } | 163 } |
| 234 String kind = _conversionKind(node); | 164 Expression newE = _cm.coerceExpression(node.node, node.wrapper); |
| 235 var loc = _locationInfo(node); | |
| 236 Expression newE = _cm.coerceExpression(node.node, node.wrapper, kind, loc); | |
| 237 if (!NodeReplacer.replace(node, newE)) { | 165 if (!NodeReplacer.replace(node, newE)) { |
| 238 _log.severe("Failed to replace node for Closure Wrap"); | 166 _log.severe("Failed to replace node for Closure Wrap"); |
| 239 } | 167 } |
| 240 newE.accept(this); | 168 newE.accept(this); |
| 241 return null; | 169 return null; |
| 242 } | 170 } |
| 243 | 171 |
| 244 @override | 172 @override |
| 245 Object visitNode(AstNode n) { | 173 Object visitNode(AstNode n) { |
| 246 var o = _skipCoercions; | 174 var o = _skipCoercions; |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 306 // class level avoids having to close over type variables, which is not | 234 // class level avoids having to close over type variables, which is not |
| 307 // easily done given the lack of generic functions). Generating the coercions | 235 // easily done given the lack of generic functions). Generating the coercions |
| 308 // inline is possible as well, but is quite a bit messier and harder to read | 236 // inline is possible as well, but is quite a bit messier and harder to read |
| 309 // since in general we need to bind the coerced expression to a lambda | 237 // since in general we need to bind the coerced expression to a lambda |
| 310 // bound variable, both in order to deal with side-effects and to be | 238 // bound variable, both in order to deal with side-effects and to be |
| 311 // able to properly record the return type of the wrapper function. | 239 // able to properly record the return type of the wrapper function. |
| 312 class CoercionManager { | 240 class CoercionManager { |
| 313 VariableManager _vm; | 241 VariableManager _vm; |
| 314 TypeManager _tm; | 242 TypeManager _tm; |
| 315 bool _hoistWrappers = false; | 243 bool _hoistWrappers = false; |
| 316 TypeRules _rules; | |
| 317 InstrumentedRuntime _runtime; | |
| 318 | 244 |
| 319 // A map containing all of the wrappers collected but not yet discharged | 245 // A map containing all of the wrappers collected but not yet discharged |
| 320 final Map<Identifier, _LocatedWrapper> _topWrappers = | 246 final Map<Identifier, Wrapper> _topWrappers = <Identifier, Wrapper>{}; |
| 321 <Identifier, _LocatedWrapper>{}; | 247 final Map<Identifier, Wrapper> _classWrappers = <Identifier, Wrapper>{}; |
| 322 final Map<Identifier, _LocatedWrapper> _classWrappers = | 248 Map<Identifier, Wrapper> _wrappers; |
| 323 <Identifier, _LocatedWrapper>{}; | |
| 324 Map<Identifier, _LocatedWrapper> _wrappers; | |
| 325 | 249 |
| 326 CoercionManager(this._vm, this._tm, this._rules, [this._runtime]) { | 250 CoercionManager(this._vm, this._tm) { |
| 327 _wrappers = _topWrappers; | 251 _wrappers = _topWrappers; |
| 328 } | 252 } |
| 329 | 253 |
| 330 // Call on entry to and exit from a compilation unit in order to properly | 254 // Call on entry to and exit from a compilation unit in order to properly |
| 331 // discharge the accumulated wrappers. | 255 // discharge the accumulated wrappers. |
| 332 void enterCompilationUnit(CompilationUnit unit) { | 256 void enterCompilationUnit(CompilationUnit unit) { |
| 333 _tm.enterCompilationUnit(unit); | 257 _tm.enterCompilationUnit(unit); |
| 334 _wrappers = _topWrappers; | 258 _wrappers = _topWrappers; |
| 335 } | 259 } |
| 336 void exitCompilationUnit(CompilationUnit unit) { | 260 void exitCompilationUnit(CompilationUnit unit) { |
| 337 for (Identifier i in _wrappers.keys) { | 261 for (Identifier i in _wrappers.keys) { |
| 338 FunctionDeclaration f = | 262 FunctionDeclaration f = _buildCoercion(i, _wrappers[i], true); |
| 339 _buildCoercion(i, _wrappers[i].wrapper, _wrappers[i].loc, true); | |
| 340 unit.declarations.add(f); | 263 unit.declarations.add(f); |
| 341 } | 264 } |
| 342 _wrappers.clear(); | 265 _wrappers.clear(); |
| 343 _wrappers = _topWrappers; | 266 _wrappers = _topWrappers; |
| 344 _tm.exitCompilationUnit(unit); | 267 _tm.exitCompilationUnit(unit); |
| 345 } | 268 } |
| 346 | 269 |
| 347 // Call on entry to and exit from a class in order to properly | 270 // Call on entry to and exit from a class in order to properly |
| 348 // discharge the accumulated wrappers. | 271 // discharge the accumulated wrappers. |
| 349 void enterClass() { | 272 void enterClass() { |
| 350 _wrappers = _classWrappers; | 273 _wrappers = _classWrappers; |
| 351 } | 274 } |
| 352 void exitClass(ClassDeclaration cl) { | 275 void exitClass(ClassDeclaration cl) { |
| 353 for (Identifier i in _wrappers.keys) { | 276 for (Identifier i in _wrappers.keys) { |
| 354 ClassMember f = | 277 ClassMember f = _buildCoercion(i, _wrappers[i], false); |
| 355 _buildCoercion(i, _wrappers[i].wrapper, _wrappers[i].loc, false); | |
| 356 cl.members.add(f); | 278 cl.members.add(f); |
| 357 } | 279 } |
| 358 _wrappers.clear(); | 280 _wrappers.clear(); |
| 359 _wrappers = _topWrappers; | 281 _wrappers = _topWrappers; |
| 360 } | 282 } |
| 361 | 283 |
| 362 // The main entry point. Coerce e using c, returning a new expression, | 284 // The main entry point. Coerce e using c, returning a new expression, |
| 363 // possibly recording additional coercions functions and typedefs to | 285 // possibly recording additional coercions functions and typedefs to |
| 364 // be discharged at a higher level. | 286 // be discharged at a higher level. |
| 365 Expression coerceExpression( | 287 Expression coerceExpression(Expression e, Coercion c) { |
| 366 Expression e, Coercion c, String kind, String loc) { | |
| 367 return _coerceExpression(e, c, kind, loc); | |
| 368 } | |
| 369 | |
| 370 ///////////////// Private ////////////////////////////////// | |
| 371 Tuple2<Identifier, Function1<Expression, Expression>> _bindExpression( | |
| 372 String hint, Expression e1) { | |
| 373 if (e1 is Identifier) { | |
| 374 return new Tuple2(e1, (e2) => e2); | |
| 375 } | |
| 376 var id = _vm.freshIdentifier(hint); | |
| 377 var fp = AstBuilder.simpleFormal(id, null); | |
| 378 Expression f(Expression e2) => | |
| 379 AstBuilder.parenthesize(AstBuilder.letExpression(fp, e1, e2)); | |
| 380 return new Tuple2(id, f); | |
| 381 } | |
| 382 | |
| 383 Expression _wrapExpression(Expression e, Wrapper w, String k, String loc) { | |
| 384 var q = _addWrapper(w, loc); | |
| 385 if (_runtime == null) { | |
| 386 var app = AstBuilder.application(q, <Expression>[e]); | |
| 387 app.staticType = w.toType; | |
| 388 return app; | |
| 389 } | |
| 390 var ttName = _tm.typeNameFromDartType(w.toType); | |
| 391 var tt = _tm.typeExpression(ttName); | |
| 392 var ft = _tm.typeExpressionFromDartType(w.fromType); | |
| 393 if (w.fromType.element.library != null && | |
| 394 utils.isDartPrivateLibrary(w.fromType.element.library)) { | |
| 395 ft = AstBuilder.nullLiteral(); | |
| 396 } | |
| 397 var tup = _bindExpression("x", e); | |
| 398 var id = tup.e0; | |
| 399 var binder = tup.e1; | |
| 400 var dartIs = AstBuilder.isExpression(AstBuilder.parenthesize(id), ttName); | |
| 401 var oper = _runtime.wrap(q, id, ft, tt, dartIs, k, loc); | |
| 402 return binder(oper); | |
| 403 } | |
| 404 | |
| 405 Expression _castExpression(Expression e, Cast c, String k, String loc) { | |
| 406 var ttName = _tm.typeNameFromDartType(c.toType); | |
| 407 if (_runtime == null) { | |
| 408 var cast = AstBuilder.asExpression(e, ttName); | |
| 409 cast.staticType = c.toType; | |
| 410 return cast; | |
| 411 } | |
| 412 var tt = _tm.typeExpression(ttName); | |
| 413 var ft = _tm.typeExpressionFromDartType(c.fromType); | |
| 414 if (c.fromType.element == null) { | |
| 415 // Replace bottom with Null type. | |
| 416 var ftType = _rules.provider.nullType; | |
| 417 ft = _tm.typeExpressionFromDartType(ftType); | |
| 418 } else if (c.fromType.element.library != null && | |
| 419 utils.isDartPrivateLibrary(c.fromType.element.library)) { | |
| 420 ft = AstBuilder.nullLiteral(); | |
| 421 } | |
| 422 var tup = _bindExpression("x", e); | |
| 423 var id = tup.e0; | |
| 424 var binder = tup.e1; | |
| 425 var dartIs = AstBuilder.isExpression(AstBuilder.parenthesize(id), ttName); | |
| 426 var ground = _rules.isGroundType(c.toType); | |
| 427 var oper = _runtime.cast(id, ft, tt, dartIs, k, loc, ground); | |
| 428 return binder(oper); | |
| 429 } | |
| 430 | |
| 431 Expression _coerceExpression( | |
| 432 Expression e, Coercion c, String kind, String loc) { | |
| 433 assert(c != null); | 288 assert(c != null); |
| 434 assert(c is! CoercionError); | 289 assert(c is! CoercionError); |
| 435 if (e is NamedExpression) { | 290 if (e is NamedExpression) { |
| 436 Expression inner = _coerceExpression(e.expression, c, kind, loc); | 291 Expression inner = coerceExpression(e.expression, c); |
| 437 return new NamedExpression(e.name, inner); | 292 return new NamedExpression(e.name, inner); |
| 438 } | 293 } |
| 439 if (c is Cast) return _castExpression(e, c, kind, loc); | 294 if (c is Cast) return _castExpression(e, c); |
| 440 if (c is Wrapper) return _wrapExpression(e, c, kind, loc); | 295 if (c is Wrapper) return _wrapExpression(e, c); |
| 441 assert(c is Identity); | 296 assert(c is Identity); |
| 442 return e; | 297 return e; |
| 443 } | 298 } |
| 444 | 299 |
| 445 Expression _addWrapper(Wrapper w, String loc) { | 300 ///////////////// Private ////////////////////////////////// |
| 301 |
| 302 Expression _wrapExpression(Expression e, Wrapper w) { |
| 303 var q = _addWrapper(w); |
| 304 var app = AstBuilder.application(q, <Expression>[e]); |
| 305 app.staticType = w.toType; |
| 306 return app; |
| 307 } |
| 308 |
| 309 Expression _castExpression(Expression e, Cast c) { |
| 310 var ttName = _tm.typeNameFromDartType(c.toType); |
| 311 var cast = AstBuilder.asExpression(e, ttName); |
| 312 cast.staticType = c.toType; |
| 313 return cast; |
| 314 } |
| 315 |
| 316 Expression _addWrapper(Wrapper w) { |
| 446 if (_hoistWrappers) { | 317 if (_hoistWrappers) { |
| 447 var q = _vm.freshIdentifier("q"); | 318 var q = _vm.freshIdentifier("q"); |
| 448 _wrappers[q] = new _LocatedWrapper(w, loc); | 319 _wrappers[q] = w; |
| 449 return q; | 320 return q; |
| 450 } else { | 321 } else { |
| 451 return _buildCoercionExpression(w, loc); | 322 return _buildCoercionExpression(w); |
| 452 } | 323 } |
| 453 } | 324 } |
| 454 | 325 |
| 455 // Choose a canonical name for the ith coercion parameter | 326 // Choose a canonical name for the ith coercion parameter |
| 456 // with name "name". | 327 // with name "name". |
| 457 Identifier _coercionParameter(String name, int index) { | 328 Identifier _coercionParameter(String name, int index) { |
| 458 String s = name + index.toString(); | 329 String s = name + index.toString(); |
| 459 return AstBuilder.identifierFromString(s); | 330 return AstBuilder.identifierFromString(s); |
| 460 } | 331 } |
| 461 | 332 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 479 for (String k in namedParameters.keys) { | 350 for (String k in namedParameters.keys) { |
| 480 // TODO(leafp): These could collide with the generated names. | 351 // TODO(leafp): These could collide with the generated names. |
| 481 Identifier z = AstBuilder.identifierFromString(k); | 352 Identifier z = AstBuilder.identifierFromString(k); |
| 482 // We use the toType to avoid changing the reified type | 353 // We use the toType to avoid changing the reified type |
| 483 FormalParameter fp = _tm.typedFormal(z, namedParameters[k].toType); | 354 FormalParameter fp = _tm.typedFormal(z, namedParameters[k].toType); |
| 484 params.add(AstBuilder.namedFormal(fp)); | 355 params.add(AstBuilder.namedFormal(fp)); |
| 485 } | 356 } |
| 486 return params; | 357 return params; |
| 487 } | 358 } |
| 488 | 359 |
| 489 List<Expression> _wrapperCoercedArguments(Wrapper wrapper, String loc) { | 360 List<Expression> _wrapperCoercedArguments(Wrapper wrapper) { |
| 490 var namedParameters = wrapper.namedParameters; | 361 var namedParameters = wrapper.namedParameters; |
| 491 var normalParameters = wrapper.normalParameters; | 362 var normalParameters = wrapper.normalParameters; |
| 492 var optionalParameters = wrapper.optionalParameters; | 363 var optionalParameters = wrapper.optionalParameters; |
| 493 var args = new List<Expression>(); | 364 var args = new List<Expression>(); |
| 494 for (int i = 0; i < normalParameters.length; i++) { | 365 for (int i = 0; i < normalParameters.length; i++) { |
| 495 Identifier x = _coercionParameter("x", i); | 366 Identifier x = _coercionParameter("x", i); |
| 496 Expression e = | 367 Expression e = coerceExpression(x, normalParameters[i]); |
| 497 _coerceExpression(x, normalParameters[i], "CastParam", loc); | |
| 498 args.add(e); | 368 args.add(e); |
| 499 } | 369 } |
| 500 for (int i = 0; i < optionalParameters.length; i++) { | 370 for (int i = 0; i < optionalParameters.length; i++) { |
| 501 Identifier y = _coercionParameter("y", i); | 371 Identifier y = _coercionParameter("y", i); |
| 502 Expression e = | 372 Expression e = coerceExpression(y, optionalParameters[i]); |
| 503 _coerceExpression(y, optionalParameters[i], "CastParam", loc); | |
| 504 args.add(e); | 373 args.add(e); |
| 505 } | 374 } |
| 506 for (String k in namedParameters.keys) { | 375 for (String k in namedParameters.keys) { |
| 507 // TODO(leafp): These could collide with the generated names. | 376 // TODO(leafp): These could collide with the generated names. |
| 508 Identifier z = AstBuilder.identifierFromString(k); | 377 Identifier z = AstBuilder.identifierFromString(k); |
| 509 Expression e = _coerceExpression(z, namedParameters[k], "CastParam", loc); | 378 Expression e = coerceExpression(z, namedParameters[k]); |
| 510 args.add(AstBuilder.namedParameter(k, e)); | 379 args.add(AstBuilder.namedParameter(k, e)); |
| 511 } | 380 } |
| 512 return args; | 381 return args; |
| 513 } | 382 } |
| 514 | 383 |
| 515 // Given an identifier c, a value f and a coercion q : T0 -> T1 => S0 -> S1 | 384 // Given an identifier c, a value f and a coercion q : T0 -> T1 => S0 -> S1 |
| 516 // wrap f using q and bind it to variable c | 385 // wrap f using q and bind it to variable c |
| 517 // T1 c(T0 x) => (f(x as T0) as S1) | 386 // T1 c(T0 x) => (f(x as T0) as S1) |
| 518 // Note that we use the "fromType" to decorate the wrapper | 387 // Note that we use the "fromType" to decorate the wrapper |
| 519 // rather than the "toType" to avoid changing the reified type | 388 // rather than the "toType" to avoid changing the reified type |
| 520 // TODO(leafp): If we wrap non-function literals, we can still | 389 // TODO(leafp): If we wrap non-function literals, we can still |
| 521 // end up changing the runtime reified type, since we build a function | 390 // end up changing the runtime reified type, since we build a function |
| 522 // literal based on the static type. | 391 // literal based on the static type. |
| 523 FunctionDeclarationStatement _wrapperMkInner( | 392 FunctionDeclarationStatement _wrapperMkInner( |
| 524 Identifier c, Expression f, Wrapper wrapper, String loc) { | 393 Identifier c, Expression f, Wrapper wrapper) { |
| 525 List<FormalParameter> params = _wrapperFormalParameters(wrapper); | 394 List<FormalParameter> params = _wrapperFormalParameters(wrapper); |
| 526 List<Expression> args = _wrapperCoercedArguments(wrapper, loc); | 395 List<Expression> args = _wrapperCoercedArguments(wrapper); |
| 527 Expression app = AstBuilder.application(f, args); | 396 Expression app = AstBuilder.application(f, args); |
| 528 Expression body = _coerceExpression(app, wrapper.ret, "CastResult", loc); | 397 Expression body = coerceExpression(app, wrapper.ret); |
| 529 FunctionExpression ce = AstBuilder.expressionFunction(params, body, true); | 398 FunctionExpression ce = AstBuilder.expressionFunction(params, body, true); |
| 530 TypeName rt = | 399 TypeName rt = |
| 531 _tm.typeNameFromDartType((wrapper.fromType as FunctionType).returnType); | 400 _tm.typeNameFromDartType((wrapper.fromType as FunctionType).returnType); |
| 532 Statement cDec = AstBuilder.functionDeclarationStatement(rt, c, ce); | 401 Statement cDec = AstBuilder.functionDeclarationStatement(rt, c, ce); |
| 533 return cDec; | 402 return cDec; |
| 534 } | 403 } |
| 535 | 404 |
| 536 Tuple2<List<FormalParameter>, List<Statement>> _buildCoercionBody( | 405 Tuple2<List<FormalParameter>, List<Statement>> _buildCoercionBody( |
| 537 Wrapper wrapper, String loc) { | 406 Wrapper wrapper) { |
| 538 var f = AstBuilder.identifierFromString("f"); | 407 var f = AstBuilder.identifierFromString("f"); |
| 539 var c = AstBuilder.identifierFromString("c"); | 408 var c = AstBuilder.identifierFromString("c"); |
| 540 var cDec = _wrapperMkInner(c, f, wrapper, loc); | 409 var cDec = _wrapperMkInner(c, f, wrapper); |
| 541 var comp = AstBuilder.binaryExpression(f, "==", AstBuilder.nullLiteral()); | 410 var comp = AstBuilder.binaryExpression(f, "==", AstBuilder.nullLiteral()); |
| 542 var n = AstBuilder.nullLiteral(); | 411 var n = AstBuilder.nullLiteral(); |
| 543 var cond = AstBuilder.conditionalExpression(comp, n, c); | 412 var cond = AstBuilder.conditionalExpression(comp, n, c); |
| 544 var stmts = <Statement>[cDec, AstBuilder.returnExpression(cond)]; | 413 var stmts = <Statement>[cDec, AstBuilder.returnExpression(cond)]; |
| 545 var fp = _tm.typedFormal(f, wrapper.fromType); | 414 var fp = _tm.typedFormal(f, wrapper.fromType); |
| 546 var params = <FormalParameter>[fp]; | 415 var params = <FormalParameter>[fp]; |
| 547 return new Tuple2<List<FormalParameter>, List<Statement>>(params, stmts); | 416 return new Tuple2<List<FormalParameter>, List<Statement>>(params, stmts); |
| 548 } | 417 } |
| 549 | 418 |
| 550 Expression _buildCoercionExpression(Wrapper wrapper, String loc) { | 419 Expression _buildCoercionExpression(Wrapper wrapper) { |
| 551 var tup = _buildCoercionBody(wrapper, loc); | 420 var tup = _buildCoercionBody(wrapper); |
| 552 return AstBuilder.blockFunction(tup.e0, tup.e1); | 421 return AstBuilder.blockFunction(tup.e0, tup.e1); |
| 553 } | 422 } |
| 554 | 423 |
| 555 // Given a name g and coercion q : T0 -> T1 => S0 -> S1 | 424 // Given a name g and coercion q : T0 -> T1 => S0 -> S1 |
| 556 // Bind g to a function or static method which maps | 425 // Bind g to a function or static method which maps |
| 557 // T0 -> T1 functions to S0 -> S1 functions. | 426 // T0 -> T1 functions to S0 -> S1 functions. |
| 558 // T0 -> T1 g(S1 f(S0)) { | 427 // T0 -> T1 g(S1 f(S0)) { |
| 559 // T1 c(T0 x) => (f(x as T0) as S1); | 428 // T1 c(T0 x) => (f(x as T0) as S1); |
| 560 // return (f == null) ? null : c; | 429 // return (f == null) ? null : c; |
| 561 // } | 430 // } |
| 562 Declaration _buildCoercion( | 431 Declaration _buildCoercion(Identifier q, Wrapper wrapper, bool top) { |
| 563 Identifier q, Wrapper wrapper, String loc, bool top) { | 432 var tup = _buildCoercionBody(wrapper); |
| 564 var tup = _buildCoercionBody(wrapper, loc); | |
| 565 var params = tup.e0; | 433 var params = tup.e0; |
| 566 var stmts = tup.e1; | 434 var stmts = tup.e1; |
| 567 TypeName rt = _tm.typeNameFromDartType(wrapper.toType); | 435 TypeName rt = _tm.typeNameFromDartType(wrapper.toType); |
| 568 if (top) { | 436 if (top) { |
| 569 return AstBuilder.blockFunctionDeclaration(rt, q, params, stmts); | 437 return AstBuilder.blockFunctionDeclaration(rt, q, params, stmts); |
| 570 } else { | 438 } else { |
| 571 return AstBuilder.blockMethodDeclaration(rt, q, params, stmts); | 439 return AstBuilder.blockMethodDeclaration(rt, q, params, stmts); |
| 572 } | 440 } |
| 573 } | 441 } |
| 574 } | 442 } |
| 575 | 443 |
| 576 // A class for managing the interaction between the DartType hierarchy | 444 // A class for managing the interaction between the DartType hierarchy |
| 577 // and the AST type representation. It provides utilities to translate | 445 // and the AST type representation. It provides utilities to translate |
| 578 // a DartType to AST. In order to do so, it maintains a map of typedefs | 446 // a DartType to AST. In order to do so, it maintains a map of typedefs |
| 579 // naming otherwise un-named types. These must be discharged at the top | 447 // naming otherwise un-named types. These must be discharged at the top |
| 580 // level of the compilation unit in order to produce well-formed dart code. | 448 // level of the compilation unit in order to produce well-formed dart code. |
| 581 // Note that in order to hoist the typedefs out of parameterized classes | 449 // Note that in order to hoist the typedefs out of parameterized classes |
| 582 // we must close over any type variables. | 450 // we must close over any type variables. |
| 583 class TypeManager { | 451 class TypeManager { |
| 584 final VariableManager _vm; | 452 final VariableManager _vm; |
| 585 final LibraryElement _currentLibrary; | 453 final LibraryElement _currentLibrary; |
| 586 final Map<Identifier, NewTypeIdDesc> addedTypes = {}; | 454 final Map<Identifier, NewTypeIdDesc> addedTypes = {}; |
| 587 final InstrumentedRuntime _runtime; | |
| 588 CompilationUnitElement _currentUnit; | 455 CompilationUnitElement _currentUnit; |
| 589 | 456 |
| 590 /// A map containing new function typedefs to be introduced at the top level | 457 /// A map containing new function typedefs to be introduced at the top level |
| 591 /// This uses LinkedHashMap to emit code in a consistent order. | 458 /// This uses LinkedHashMap to emit code in a consistent order. |
| 592 final Map<FunctionType, FunctionTypeAlias> _typedefs = {}; | 459 final Map<FunctionType, FunctionTypeAlias> _typedefs = {}; |
| 593 | 460 |
| 594 TypeManager(this._currentLibrary, this._vm, [this._runtime]); | 461 TypeManager(this._currentLibrary, this._vm); |
| 595 | 462 |
| 596 void enterCompilationUnit(CompilationUnit unit) { | 463 void enterCompilationUnit(CompilationUnit unit) { |
| 597 _currentUnit = unit.element; | 464 _currentUnit = unit.element; |
| 598 } | 465 } |
| 599 | 466 |
| 600 void exitCompilationUnit(CompilationUnit unit) { | 467 void exitCompilationUnit(CompilationUnit unit) { |
| 601 unit.declarations.addAll(_typedefs.values); | 468 unit.declarations.addAll(_typedefs.values); |
| 602 _typedefs.clear(); | 469 _typedefs.clear(); |
| 603 } | 470 } |
| 604 | 471 |
| 605 TypeName typeNameFromDartType(DartType dType) { | 472 TypeName typeNameFromDartType(DartType dType) { |
| 606 return _typeNameFromDartType(dType); | 473 return _typeNameFromDartType(dType); |
| 607 } | 474 } |
| 608 | 475 |
| 609 NormalFormalParameter typedFormal(Identifier v, DartType type) { | 476 NormalFormalParameter typedFormal(Identifier v, DartType type) { |
| 610 return _typedFormal(v, type); | 477 return _typedFormal(v, type); |
| 611 } | 478 } |
| 612 | 479 |
| 613 Expression typeExpressionFromDartType(DartType t) => | |
| 614 typeExpression(typeNameFromDartType(t)); | |
| 615 | |
| 616 Expression typeExpression(TypeName t) => _typeExpression(t); | |
| 617 | |
| 618 ///////////////// Private ////////////////////////////////// | 480 ///////////////// Private ////////////////////////////////// |
| 619 List<TypeParameterType> _freeTypeVariables(DartType type) { | 481 List<TypeParameterType> _freeTypeVariables(DartType type) { |
| 620 var s = new Set<TypeParameterType>(); | 482 var s = new Set<TypeParameterType>(); |
| 621 | 483 |
| 622 void _ft(DartType type) { | 484 void _ft(DartType type) { |
| 623 void _ftMap(Map<String, DartType> m) { | 485 void _ftMap(Map<String, DartType> m) { |
| 624 if (m == null) return; | 486 if (m == null) return; |
| 625 for (var k in m.keys) _ft(m[k]); | 487 for (var k in m.keys) _ft(m[k]); |
| 626 } | 488 } |
| 627 void _ftList(List<DartType> l) { | 489 void _ftList(List<DartType> l) { |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 851 } | 713 } |
| 852 var t = _mkNewTypeName(dType, id, args); | 714 var t = _mkNewTypeName(dType, id, args); |
| 853 return t; | 715 return t; |
| 854 } | 716 } |
| 855 | 717 |
| 856 TypeName _mkNewTypeName(DartType type, Identifier id, List<TypeName> args) { | 718 TypeName _mkNewTypeName(DartType type, Identifier id, List<TypeName> args) { |
| 857 var t = AstBuilder.typeName(id, args); | 719 var t = AstBuilder.typeName(id, args); |
| 858 t.type = type; | 720 t.type = type; |
| 859 return t; | 721 return t; |
| 860 } | 722 } |
| 861 | |
| 862 Expression _typeExpression(TypeName t) { | |
| 863 assert(_runtime != null); | |
| 864 if (t.typeArguments != null && t.typeArguments.length > 0) { | |
| 865 var w = AstBuilder.identifierFromString("_"); | |
| 866 var fp = AstBuilder.simpleFormal(w, t); | |
| 867 var f = AstBuilder.blockFunction(<FormalParameter>[fp], <Statement>[]); | |
| 868 return _runtime.type(f); | |
| 869 } | |
| 870 return t.name; | |
| 871 } | |
| 872 } | 723 } |
| OLD | NEW |