Chromium Code Reviews| 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/utils.dart' as utils; | 15 import 'package:dev_compiler/src/utils.dart' as utils; |
| 16 | 16 |
| 17 import 'ast_builder.dart'; | 17 import 'ast_builder.dart'; |
| 18 | 18 |
| 19 final _log = new logger.Logger('dev_compiler.reify_coercions'); | 19 final _log = new logger.Logger('dev_compiler.reify_coercions'); |
| 20 | 20 |
| 21 // TODO(leafp) Factor this out or use an existing library | 21 // TODO(leafp) Factor this out or use an existing library |
| 22 class Tuple2<T0, T1> { | 22 class Tuple2<T0, T1> { |
| 23 final T0 e0; | 23 final T0 e0; |
| 24 final T1 e1; | 24 final T1 e1; |
| 25 Tuple2(this.e0, this.e1); | 25 Tuple2(this.e0, this.e1); |
| 26 } | 26 } |
| 27 | 27 |
| 28 typedef T Function1<S, T>(S _); | 28 typedef T Function1<S, T>(S _); |
| 29 | 29 |
| 30 class NewTypeIdDesc { | |
| 31 // If null, then this is not a library level identifier (i.e. it's | |
|
Jennifer Messerly
2015/04/08 20:28:16
nit: triple slash for doc comment style:
/// If n
| |
| 32 // a type parameter, or a special type like void, dynamic, etc) | |
| 33 LibraryElement importedFrom; | |
| 34 // True => use/def in same library | |
|
vsm
2015/04/08 15:31:02
Does class this describe one specific use? If not
| |
| 35 bool fromCurrent; | |
| 36 // True => not a source variable | |
| 37 bool synthetic; | |
| 38 NewTypeIdDesc({this.fromCurrent, this.importedFrom, this.synthetic}); | |
| 39 } | |
| 40 | |
| 30 class _LocatedWrapper { | 41 class _LocatedWrapper { |
| 31 final String loc; | 42 final String loc; |
| 32 final Wrapper wrapper; | 43 final Wrapper wrapper; |
| 33 _LocatedWrapper(this.wrapper, this.loc); | 44 _LocatedWrapper(this.wrapper, this.loc); |
| 34 } | 45 } |
| 35 | 46 |
| 36 class _Inference extends DownwardsInference { | 47 class _Inference extends DownwardsInference { |
| 37 TypeManager _tm; | 48 TypeManager _tm; |
| 38 | 49 |
| 39 _Inference(TypeRules rules, this._tm) : super(rules); | 50 _Inference(TypeRules rules, this._tm) : super(rules); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 77 | 88 |
| 78 @override | 89 @override |
| 79 void annotateFunctionExpression(FunctionExpression e, DartType returnType) { | 90 void annotateFunctionExpression(FunctionExpression e, DartType returnType) { |
| 80 // Implicitly changes e.staticType | 91 // Implicitly changes e.staticType |
| 81 (e.element as ExecutableElementImpl).returnType = returnType; | 92 (e.element as ExecutableElementImpl).returnType = returnType; |
| 82 } | 93 } |
| 83 } | 94 } |
| 84 | 95 |
| 85 // This class implements a pass which modifies (in place) the ast replacing | 96 // This class implements a pass which modifies (in place) the ast replacing |
| 86 // abstract coercion nodes with their dart implementations. | 97 // abstract coercion nodes with their dart implementations. |
| 87 class UnitCoercionReifier extends analyzer.GeneralizingAstVisitor<Object> | 98 class CoercionReifier extends analyzer.GeneralizingAstVisitor<Object> |
| 88 with ConversionVisitor<Object> { | 99 with ConversionVisitor<Object> { |
| 89 CoercionManager _cm; | 100 CoercionManager _cm; |
| 90 final TypeManager _tm; | 101 TypeManager _tm; |
| 91 final VariableManager _vm; | 102 VariableManager _vm; |
| 103 LibraryUnit _library; | |
| 92 SourceFile _file; | 104 SourceFile _file; |
| 93 bool _skipCoercions = false; | 105 bool _skipCoercions = false; |
| 94 final TypeRules _rules; | 106 final TypeRules _rules; |
| 95 _Inference _inferrer; | 107 _Inference _inferrer; |
| 96 | 108 |
| 97 UnitCoercionReifier(this._tm, this._vm, this._rules) { | 109 CoercionReifier(this._library, this._rules) { |
| 110 _vm = new VariableManager(); | |
|
Jennifer Messerly
2015/04/08 20:28:16
if you want to keep final fields, it could be done
| |
| 111 _tm = new TypeManager(_library.library.element.enclosingElement, _vm); | |
| 98 _cm = new CoercionManager(_vm, _tm, _rules); | 112 _cm = new CoercionManager(_vm, _tm, _rules); |
| 99 _inferrer = new _Inference(_rules, _tm); | 113 _inferrer = new _Inference(_rules, _tm); |
| 100 } | 114 } |
| 101 | 115 |
| 102 // 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 |
| 103 // visit functions directly may not do the right thing with respect | 117 // visit functions directly may not do the right thing with respect |
| 104 // to discharging the collected definitions. | 118 // to discharging the collected definitions. |
| 105 void reify(CompilationUnit unit) { | 119 // Returns the set of new type identifiers added by the reifier |
| 120 Map<Identifier, NewTypeIdDesc> reify() { | |
| 121 for (var unit in _library.partsThenLibrary) { | |
|
Jennifer Messerly
2015/04/08 20:28:16
_library.partsThenLibrary.forEach(generateUnit); ?
| |
| 122 generateUnit(unit); | |
| 123 } | |
| 124 return _tm.addedTypes; | |
| 125 } | |
| 126 | |
| 127 void generateUnit(CompilationUnit unit) { | |
| 106 _file = new SourceFile(unit.element.source.contents.data, | 128 _file = new SourceFile(unit.element.source.contents.data, |
| 107 url: unit.element.source.uri); | 129 url: unit.element.source.uri); |
| 108 visitCompilationUnit(unit); | 130 visitCompilationUnit(unit); |
| 131 _file = null; | |
| 109 } | 132 } |
| 110 | 133 |
| 111 ///////////////// Private ////////////////////////////////// | 134 ///////////////// Private ////////////////////////////////// |
| 112 | 135 |
| 113 String _locationInfo(Expression e) { | 136 String _locationInfo(Expression e) { |
| 114 if (_file != null) { | 137 if (_file != null) { |
| 115 final begin = e is AnnotatedNode | 138 final begin = e is AnnotatedNode |
| 116 ? (e as AnnotatedNode).firstTokenAfterCommentAndMetadata.offset | 139 ? (e as AnnotatedNode).firstTokenAfterCommentAndMetadata.offset |
| 117 : e.offset; | 140 : e.offset; |
| 118 if (begin != 0) { | 141 if (begin != 0) { |
| (...skipping 400 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 519 } | 542 } |
| 520 | 543 |
| 521 // A class for managing the interaction between the DartType hierarchy | 544 // A class for managing the interaction between the DartType hierarchy |
| 522 // and the AST type representation. It provides utilities to translate | 545 // and the AST type representation. It provides utilities to translate |
| 523 // a DartType to AST. In order to do so, it maintains a map of typedefs | 546 // a DartType to AST. In order to do so, it maintains a map of typedefs |
| 524 // naming otherwise un-named types. These must be discharged at the top | 547 // naming otherwise un-named types. These must be discharged at the top |
| 525 // level of the compilation unit in order to produce well-formed dart code. | 548 // level of the compilation unit in order to produce well-formed dart code. |
| 526 // Note that in order to hoist the typedefs out of parameterized classes | 549 // Note that in order to hoist the typedefs out of parameterized classes |
| 527 // we must close over any type variables. | 550 // we must close over any type variables. |
| 528 class TypeManager { | 551 class TypeManager { |
| 529 VariableManager _vm; | 552 final VariableManager _vm; |
| 530 Set<TypeName> _newTypes = new Set<TypeName>(); | 553 final LibraryElement _currentLibrary; |
| 554 final Map<Identifier, NewTypeIdDesc> addedTypes = | |
|
vsm
2015/04/08 15:31:02
Omit the type on the left?
| |
| 555 new Map<Identifier, NewTypeIdDesc>(); | |
| 531 | 556 |
| 532 /// A map containing new function typedefs to be introduced at the top level | 557 /// A map containing new function typedefs to be introduced at the top level |
| 533 /// This uses LinkedHashMap to emit code in a consistent order. | 558 /// This uses LinkedHashMap to emit code in a consistent order. |
| 534 final Map<FunctionType, FunctionTypeAlias> _typedefs = | 559 final Map<FunctionType, FunctionTypeAlias> _typedefs = |
| 535 new Map<FunctionType, FunctionTypeAlias>(); | 560 new Map<FunctionType, FunctionTypeAlias>(); |
| 536 | 561 |
| 537 TypeManager(this._vm); | 562 TypeManager(this._currentLibrary, this._vm); |
| 538 | 563 |
| 539 void enterCompilationUnit() {} | 564 void enterCompilationUnit() {} |
| 540 void exitCompilationUnit(CompilationUnit unit) { | 565 void exitCompilationUnit(CompilationUnit unit) { |
| 541 unit.declarations.addAll(_typedefs.values); | 566 unit.declarations.addAll(_typedefs.values); |
| 542 _typedefs.clear(); | 567 _typedefs.clear(); |
| 543 } | 568 } |
| 544 | 569 |
| 545 TypeName typeNameFromDartType(DartType dType) { | 570 TypeName typeNameFromDartType(DartType dType) { |
| 546 return _typeNameFromDartType(dType); | 571 return _typeNameFromDartType(dType); |
| 547 } | 572 } |
| 548 | 573 |
| 549 NormalFormalParameter typedFormal(Identifier v, DartType type) { | 574 NormalFormalParameter typedFormal(Identifier v, DartType type) { |
| 550 return _typedFormal(v, type); | 575 return _typedFormal(v, type); |
| 551 } | 576 } |
| 552 | 577 |
| 553 Expression typeExpressionFromDartType(DartType t) => | 578 Expression typeExpressionFromDartType(DartType t) => |
| 554 typeExpression(typeNameFromDartType(t)); | 579 typeExpression(typeNameFromDartType(t)); |
| 555 | 580 |
| 556 Expression typeExpression(TypeName t) => _typeExpression(t); | 581 Expression typeExpression(TypeName t) => _typeExpression(t); |
| 557 | 582 |
| 558 Set<TypeName> get addedTypes => _newTypes; | |
| 559 | |
| 560 ///////////////// Private ////////////////////////////////// | 583 ///////////////// Private ////////////////////////////////// |
| 561 List<TypeParameterType> _freeTypeVariables(DartType type) { | 584 List<TypeParameterType> _freeTypeVariables(DartType type) { |
| 562 var s = new Set<TypeParameterType>(); | 585 var s = new Set<TypeParameterType>(); |
| 563 | 586 |
| 564 void _ft(DartType type) { | 587 void _ft(DartType type) { |
| 565 void _ftMap(Map<String, DartType> m) { | 588 void _ftMap(Map<String, DartType> m) { |
| 566 if (m == null) return; | 589 if (m == null) return; |
| 567 for (var k in m.keys) _ft(m[k]); | 590 for (var k in m.keys) _ft(m[k]); |
| 568 } | 591 } |
| 569 void _ftList(List<DartType> l) { | 592 void _ftList(List<DartType> l) { |
| 570 if (l == null) return; | 593 if (l == null) return; |
| 571 for (int i = 0; i < l.length; i++) _ft(l[i]); | 594 for (int i = 0; i < l.length; i++) _ft(l[i]); |
| 572 } | 595 } |
| 573 | 596 |
| 574 if (type == null) return; | 597 if (type == null) return; |
| 575 if (type.isDynamic) return; | 598 if (type.isDynamic) return; |
| 576 if (type.isBottom) return; | 599 if (type.isBottom) return; |
| 577 if (type.isObject) return; | 600 if (type.isObject) return; |
| 578 if (type is TypeParameterType) { | 601 if (type is TypeParameterType) { |
| 579 s.add(type); | 602 s.add(type); |
| 580 return; | 603 return; |
| 581 } | 604 } |
| 582 if (type is ParameterizedType) { | 605 if (type is ParameterizedType) { |
| 583 // TODO(leafp): The inner conditional (testing FunctionType, etc) | 606 // TODO(leafp): The inner conditional (testing FunctionType, etc) |
| 584 // can be eliminated after the roll to the next analyzer which fixes | 607 // can be eliminated after the roll to the next analyzer which fixes |
| 585 // a bug in how they resolve type names. | 608 // a bug in how they resolve type names. |
| 586 if (type.name != null && type.name != "") { | 609 if (type.name != null && type.name != "") { |
| 587 if (type is! FunctionType || | 610 if (type is! FunctionType || |
| 588 (type.element != null && type.element is FunctionTypeAlias)) { | 611 (type.element != null && type.element is FunctionTypeAlias)) { |
|
vsm
2015/04/08 18:27:09
BTW, shouldn't this be:
type is FunctionTypeAlias
| |
| 589 _ftList(type.typeArguments); | 612 _ftList(type.typeArguments); |
| 590 return; | 613 return; |
| 591 } | 614 } |
| 592 } | 615 } |
| 593 if (type is FunctionType) { | 616 if (type is FunctionType) { |
| 594 _ftMap(type.namedParameterTypes); | 617 _ftMap(type.namedParameterTypes); |
| 595 _ftList(type.normalParameterTypes); | 618 _ftList(type.normalParameterTypes); |
| 596 _ftList(type.optionalParameterTypes); | 619 _ftList(type.optionalParameterTypes); |
| 597 _ft(type.returnType); | 620 _ft(type.returnType); |
| 598 return; | 621 return; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 643 | 666 |
| 644 NormalFormalParameter _typedFormal(Identifier v, DartType type) { | 667 NormalFormalParameter _typedFormal(Identifier v, DartType type) { |
| 645 if (type is FunctionType) { | 668 if (type is FunctionType) { |
| 646 return _functionTypedFormal(v, type); | 669 return _functionTypedFormal(v, type); |
| 647 } | 670 } |
| 648 assert(type.name != null); | 671 assert(type.name != null); |
| 649 TypeName t = typeNameFromDartType(type); | 672 TypeName t = typeNameFromDartType(type); |
| 650 return AstBuilder.simpleFormal(v, t); | 673 return AstBuilder.simpleFormal(v, t); |
| 651 } | 674 } |
| 652 | 675 |
| 676 Identifier freshTypeDefVariable() { | |
| 677 var t = _vm.freshTypeIdentifier("t"); | |
| 678 var desc = new NewTypeIdDesc( | |
| 679 fromCurrent: true, importedFrom: _currentLibrary, synthetic: true); | |
| 680 addedTypes[t] = desc; | |
| 681 return t; | |
| 682 } | |
| 683 | |
| 684 Identifier typeParameterFromString(String name) => | |
| 685 AstBuilder.identifierFromString(name); | |
| 686 | |
| 687 Identifier freshReferenceToNamedType(DartType type) { | |
| 688 var name = type.name; | |
| 689 assert(name != null); | |
| 690 var id = AstBuilder.identifierFromString(name); | |
| 691 var element = type.element; | |
| 692 id.staticElement = element; | |
| 693 var library = null; | |
| 694 // This can happen for types like (e.g.) void | |
| 695 if (element != null) library = element.library; | |
| 696 var desc = new NewTypeIdDesc( | |
| 697 fromCurrent: _currentLibrary == library, | |
| 698 importedFrom: library, | |
| 699 synthetic: false); | |
| 700 addedTypes[id] = desc; | |
| 701 return id; | |
| 702 } | |
| 703 | |
| 653 // I think we can avoid alpha-varying type parameters, since | 704 // I think we can avoid alpha-varying type parameters, since |
| 654 // the binding forms are so limited, so we just re-use the | 705 // the binding forms are so limited, so we just re-use the |
| 655 // the original names for the formals and the actuals. | 706 // the original names for the formals and the actuals. |
| 656 TypeName _typeNameFromFunctionType(FunctionType type) { | 707 TypeName _typeNameFromFunctionType(FunctionType type) { |
| 657 if (_typedefs.containsKey(type)) { | 708 if (_typedefs.containsKey(type)) { |
| 658 var alias = _typedefs[type]; | 709 var alias = _typedefs[type]; |
| 659 var ts = null; | 710 var ts = null; |
| 660 var tpl = alias.typeParameters; | 711 var tpl = alias.typeParameters; |
| 661 if (tpl != null) { | 712 if (tpl != null) { |
| 662 var ltp = tpl.typeParameters; | 713 var ltp = tpl.typeParameters; |
| 663 ts = new List<TypeName>.from( | 714 ts = new List<TypeName>.from( |
| 664 ltp.map((t) => _mkNewTypeName(t.name, null))); | 715 ltp.map((t) => _mkNewTypeName(t.name, null))); |
| 665 } | 716 } |
| 666 var name = alias.name; | 717 var name = alias.name; |
| 667 return _mkNewTypeName(name, ts); | 718 return _mkNewTypeName(name, ts); |
| 668 } | 719 } |
| 669 | 720 |
| 670 List<TypeParameterType> ftvs = _freeTypeVariables(type); | 721 List<TypeParameterType> ftvs = _freeTypeVariables(type); |
| 671 Identifier t = _vm.freshTypeIdentifier("t"); | 722 Identifier t = freshTypeDefVariable(); |
| 672 | 723 |
| 673 Iterable<Identifier> tNames = | 724 Iterable<Identifier> tNames = |
| 674 ftvs.map((x) => AstBuilder.identifierFromString(x.name)); | 725 ftvs.map((x) => typeParameterFromString(x.name)); |
| 675 List<TypeParameter> tps = tNames.map(AstBuilder.typeParameter).toList(); | 726 List<TypeParameter> tps = tNames.map(AstBuilder.typeParameter).toList(); |
| 676 List<FormalParameter> fps = _formalParameterListForFunctionType(type); | 727 List<FormalParameter> fps = _formalParameterListForFunctionType(type); |
| 677 TypeName ret = _typeNameFromDartType(type.returnType); | 728 TypeName ret = _typeNameFromDartType(type.returnType); |
| 678 FunctionTypeAlias alias = AstBuilder.functionTypeAlias(ret, t, tps, fps); | 729 FunctionTypeAlias alias = AstBuilder.functionTypeAlias(ret, t, tps, fps); |
| 679 | 730 |
| 680 _typedefs[type] = alias; | 731 _typedefs[type] = alias; |
| 681 | 732 |
| 682 List<TypeName> args = ftvs.map(_typeNameFromDartType).toList(); | 733 List<TypeName> args = ftvs.map(_typeNameFromDartType).toList(); |
| 683 TypeName namedType = _mkNewTypeName(t, args); | 734 TypeName namedType = _mkNewTypeName(t, args); |
| 684 | 735 |
| 685 return namedType; | 736 return namedType; |
| 686 } | 737 } |
| 687 | 738 |
| 688 TypeName _typeNameFromDartType(DartType dType) { | 739 TypeName _typeNameFromDartType(DartType dType) { |
| 689 // TODO(leafp) This doesn't re-use the name when the function type | |
| 690 // is derived from a typedef, since I've moved it above the check | |
| 691 // for a name. I think there's a bug in the resolver here: I | |
| 692 // sometimes see function types named not with a typedef name, | |
| 693 // but rather with the name of the function that they classify. | |
| 694 if (dType is FunctionType) return _typeNameFromFunctionType(dType); | |
| 695 String name = dType.name; | 740 String name = dType.name; |
| 696 if (name == null || name == "" || dType.isBottom) { | 741 if (name == null || name == "" || dType.isBottom) { |
| 742 if (dType is FunctionType) return _typeNameFromFunctionType(dType); | |
|
Leaf
2015/04/07 22:29:58
This is the only thing that changes the output cod
| |
| 697 _log.severe("No name for type, casting through dynamic"); | 743 _log.severe("No name for type, casting through dynamic"); |
| 698 var d = AstBuilder.identifierFromString("dynamic"); | 744 var d = AstBuilder.identifierFromString("dynamic"); |
| 699 var t = _mkNewTypeName(d, null); | 745 var t = _mkNewTypeName(d, null); |
| 700 t.type = dType; | 746 t.type = dType; |
| 701 return t; | 747 return t; |
| 702 } | 748 } |
| 703 SimpleIdentifier id = AstBuilder.identifierFromString(name); | 749 SimpleIdentifier id = freshReferenceToNamedType(dType); |
| 704 id.staticElement = dType.element; | |
| 705 List<TypeName> args = null; | 750 List<TypeName> args = null; |
| 706 if (dType is ParameterizedType) { | 751 if (dType is ParameterizedType) { |
| 707 List<DartType> targs = dType.typeArguments; | 752 List<DartType> targs = dType.typeArguments; |
| 708 args = targs.map(_typeNameFromDartType).toList(); | 753 args = targs.map(_typeNameFromDartType).toList(); |
| 709 } | 754 } |
| 710 var t = _mkNewTypeName(id, args); | 755 var t = _mkNewTypeName(id, args); |
| 711 t.type = dType; | 756 t.type = dType; |
| 712 return t; | 757 return t; |
| 713 } | 758 } |
| 714 | 759 |
| 715 TypeName _mkNewTypeName(Identifier id, List<TypeName> args) { | 760 TypeName _mkNewTypeName(Identifier id, List<TypeName> args) { |
| 716 var t = AstBuilder.typeName(id, args); | 761 var t = AstBuilder.typeName(id, args); |
| 717 _newTypes.add(t); | |
| 718 return t; | 762 return t; |
| 719 } | 763 } |
| 720 | 764 |
| 721 Expression _typeExpression(TypeName t) { | 765 Expression _typeExpression(TypeName t) { |
| 722 if (t.typeArguments != null && t.typeArguments.length > 0) { | 766 if (t.typeArguments != null && t.typeArguments.length > 0) { |
| 723 var w = AstBuilder.identifierFromString("_"); | 767 var w = AstBuilder.identifierFromString("_"); |
| 724 var fp = AstBuilder.simpleFormal(w, t); | 768 var fp = AstBuilder.simpleFormal(w, t); |
| 725 var f = AstBuilder.blockFunction(<FormalParameter>[fp], <Statement>[]); | 769 var f = AstBuilder.blockFunction(<FormalParameter>[fp], <Statement>[]); |
| 726 return new RuntimeOperation("type", <Expression>[f]); | 770 return new RuntimeOperation("type", <Expression>[f]); |
| 727 } | 771 } |
| 728 return t.name; | 772 return t.name; |
| 729 } | 773 } |
| 730 } | 774 } |
| OLD | NEW |