| Index: lib/src/codegen/reify_coercions.dart
|
| diff --git a/lib/src/codegen/reify_coercions.dart b/lib/src/codegen/reify_coercions.dart
|
| index 184aea535919fd290e4d5f7ebec04ab772ff8462..70c1d3e2d7657293fed0f8ed40cdb7b2ea080c20 100644
|
| --- a/lib/src/codegen/reify_coercions.dart
|
| +++ b/lib/src/codegen/reify_coercions.dart
|
| @@ -15,15 +15,6 @@ import 'ast_builder.dart';
|
|
|
| final _log = new logger.Logger('dev_compiler.reify_coercions');
|
|
|
| -// TODO(leafp) Factor this out or use an existing library
|
| -class Tuple2<T0, T1> {
|
| - final T0 e0;
|
| - final T1 e1;
|
| - Tuple2(this.e0, this.e1);
|
| -}
|
| -
|
| -typedef T Function1<S, T>(S _);
|
| -
|
| class NewTypeIdDesc {
|
| /// If null, then this is not a library level identifier (i.e. it's
|
| /// a type parameter, or a special type like void, dynamic, etc)
|
| @@ -40,30 +31,17 @@ class NewTypeIdDesc {
|
| // This class implements a pass which modifies (in place) the ast replacing
|
| // abstract coercion nodes with their dart implementations.
|
| class CoercionReifier extends analyzer.GeneralizingAstVisitor<Object> {
|
| - final CoercionManager _cm;
|
| - final TypeManager _tm;
|
| - final VariableManager _vm;
|
| final LibraryUnit _library;
|
| final StrongTypeSystemImpl _typeSystem;
|
|
|
| - CoercionReifier._(
|
| - this._cm, this._tm, this._vm, this._library, this._typeSystem);
|
| -
|
| - factory CoercionReifier(
|
| - LibraryUnit library, StrongTypeSystemImpl typeSystem) {
|
| - var vm = new VariableManager();
|
| - var tm = new TypeManager(library.library.element.enclosingElement, vm);
|
| - var cm = new CoercionManager(vm, tm);
|
| - return new CoercionReifier._(cm, tm, vm, library, typeSystem);
|
| - }
|
| + CoercionReifier(this._library, this._typeSystem);
|
|
|
| // This should be the entry point for this class. Entering via the
|
| // visit functions directly may not do the right thing with respect
|
| // to discharging the collected definitions.
|
| // Returns the set of new type identifiers added by the reifier
|
| - Map<Identifier, NewTypeIdDesc> reify() {
|
| + void reify() {
|
| _library.partsThenLibrary.forEach(visitCompilationUnit);
|
| - return _tm.addedTypes;
|
| }
|
|
|
| @override
|
| @@ -95,7 +73,7 @@ class CoercionReifier extends analyzer.GeneralizingAstVisitor<Object> {
|
| Object _visitDownCast(DownCast node, Expression expr) {
|
| var parent = expr.parent;
|
| expr.visitChildren(this);
|
| - Expression newE = _cm.coerceExpression(expr, node.cast);
|
| + Expression newE = coerceExpression(expr, node.cast);
|
| if (!identical(expr, newE)) {
|
| var replaced = parent.accept(new NodeReplacer(expr, newE));
|
| // It looks like NodeReplacer will always return true.
|
| @@ -105,60 +83,11 @@ class CoercionReifier extends analyzer.GeneralizingAstVisitor<Object> {
|
| return null;
|
| }
|
|
|
| - Object visitCompilationUnit(CompilationUnit unit) {
|
| - _cm.enterCompilationUnit(unit);
|
| - Object ret = super.visitCompilationUnit(unit);
|
| - _cm.exitCompilationUnit(unit);
|
| - return ret;
|
| - }
|
| -
|
| DartType _getStaticType(Expression expr) {
|
| return expr.staticType ?? DynamicTypeImpl.instance;
|
| }
|
| -}
|
| -
|
| -// This provides a placeholder variable manager. Currently it simply
|
| -// mangles names in a way unlikely (but not guaranteed) to avoid
|
| -// collisions with user variables.
|
| -// TODO(leafp): Replace this with something real.
|
| -class VariableManager {
|
| - // TODO(leafp): Hack, not for real.
|
| - int _id = 0;
|
| -
|
| - SimpleIdentifier freshIdentifier(String hint) {
|
| - String n = _id.toString();
|
| - _id++;
|
| - String s = "__$hint$n";
|
| - return AstBuilder.identifierFromString(s);
|
| - }
|
|
|
| - SimpleIdentifier freshTypeIdentifier(String hint) {
|
| - return freshIdentifier(hint);
|
| - }
|
| -}
|
| -
|
| -// This class manages the reification of coercions as dart code. Given a
|
| -// coercion c and an expression e it will produce an expression e' which
|
| -// is the result of coercing e using c.
|
| -class CoercionManager {
|
| - VariableManager _vm;
|
| - TypeManager _tm;
|
| -
|
| - CoercionManager(this._vm, this._tm);
|
| -
|
| - // Call on entry to and exit from a compilation unit in order to properly
|
| - // discharge the accumulated wrappers.
|
| - void enterCompilationUnit(CompilationUnit unit) {
|
| - _tm.enterCompilationUnit(unit);
|
| - }
|
| -
|
| - void exitCompilationUnit(CompilationUnit unit) {
|
| - _tm.exitCompilationUnit(unit);
|
| - }
|
| -
|
| - // The main entry point. Coerce e using c, returning a new expression,
|
| - // possibly recording additional coercions functions and typedefs to
|
| - // be discharged at a higher level.
|
| + /// Coerce [e] using [c], returning a new expression.
|
| Expression coerceExpression(Expression e, Coercion c) {
|
| assert(c != null);
|
| assert(c is! CoercionError);
|
| @@ -174,289 +103,12 @@ class CoercionManager {
|
| ///////////////// Private //////////////////////////////////
|
|
|
| Expression _castExpression(Expression e, Cast c) {
|
| - var ttName = _tm.typeNameFromDartType(c.toType);
|
| - var cast = AstBuilder.asExpression(e, ttName);
|
| + // We use an empty name in the AST, because the JS code generator only cares
|
| + // about the target type. It does not look at the AST name.
|
| + var typeName = new TypeName(AstBuilder.identifierFromString(''), null);
|
| + typeName.type = c.toType;
|
| + var cast = AstBuilder.asExpression(e, typeName);
|
| cast.staticType = c.toType;
|
| return cast;
|
| }
|
| }
|
| -
|
| -// A class for managing the interaction between the DartType hierarchy
|
| -// and the AST type representation. It provides utilities to translate
|
| -// a DartType to AST. In order to do so, it maintains a map of typedefs
|
| -// naming otherwise un-named types. These must be discharged at the top
|
| -// level of the compilation unit in order to produce well-formed dart code.
|
| -// Note that in order to hoist the typedefs out of parameterized classes
|
| -// we must close over any type variables.
|
| -class TypeManager {
|
| - final VariableManager _vm;
|
| - final LibraryElement _currentLibrary;
|
| - final Map<Identifier, NewTypeIdDesc> addedTypes = {};
|
| - CompilationUnitElement _currentUnit;
|
| -
|
| - /// A map containing new function typedefs to be introduced at the top level
|
| - /// This uses LinkedHashMap to emit code in a consistent order.
|
| - final Map<FunctionType, FunctionTypeAlias> _typedefs = {};
|
| -
|
| - TypeManager(this._currentLibrary, this._vm);
|
| -
|
| - void enterCompilationUnit(CompilationUnit unit) {
|
| - _currentUnit = unit.element;
|
| - }
|
| -
|
| - void exitCompilationUnit(CompilationUnit unit) {
|
| - unit.declarations.addAll(_typedefs.values);
|
| - _typedefs.clear();
|
| - }
|
| -
|
| - TypeName typeNameFromDartType(DartType dType) {
|
| - return _typeNameFromDartType(dType);
|
| - }
|
| -
|
| - NormalFormalParameter typedFormal(Identifier v, DartType type) {
|
| - return _typedFormal(v, type);
|
| - }
|
| -
|
| - ///////////////// Private //////////////////////////////////
|
| - List<TypeParameterType> _freeTypeVariables(DartType type) {
|
| - var s = new Set<TypeParameterType>();
|
| -
|
| - void _ft(DartType type) {
|
| - void _ftMap(Map<String, DartType> m) {
|
| - if (m == null) return;
|
| - for (var k in m.keys) _ft(m[k]);
|
| - }
|
| - void _ftList(List<DartType> l) {
|
| - if (l == null) return;
|
| - for (int i = 0; i < l.length; i++) _ft(l[i]);
|
| - }
|
| -
|
| - if (type == null) return;
|
| - if (type.isDynamic) return;
|
| - if (type.isBottom) return;
|
| - if (type.isObject) return;
|
| - if (type is TypeParameterType) {
|
| - s.add(type);
|
| - return;
|
| - }
|
| - if (type is ParameterizedType) {
|
| - if (type.name != null && type.name != "") {
|
| - _ftList(type.typeArguments);
|
| - return;
|
| - }
|
| - if (type is FunctionType) {
|
| - _ftMap(type.namedParameterTypes);
|
| - _ftList(type.normalParameterTypes);
|
| - _ftList(type.optionalParameterTypes);
|
| - _ft(type.returnType);
|
| - return;
|
| - }
|
| - assert(type is! InterfaceType);
|
| - assert(false);
|
| - }
|
| - if (type is VoidType) return;
|
| - print(type.toString());
|
| - assert(false);
|
| - }
|
| - _ft(type);
|
| - return s.toList();
|
| - }
|
| -
|
| - List<FormalParameter> _formalParameterListForFunctionType(FunctionType type) {
|
| - var namedParameters = type.namedParameterTypes;
|
| - var normalParameters = type.normalParameterTypes;
|
| - var optionalParameters = type.optionalParameterTypes;
|
| - var params = new List<FormalParameter>();
|
| - for (int i = 0; i < normalParameters.length; i++) {
|
| - FormalParameter fp =
|
| - AstBuilder.requiredFormal(_anonymousFormal(normalParameters[i]));
|
| - _resolveFormal(fp, normalParameters[i]);
|
| - params.add(fp);
|
| - }
|
| - for (int i = 0; i < optionalParameters.length; i++) {
|
| - FormalParameter fp =
|
| - AstBuilder.optionalFormal(_anonymousFormal(optionalParameters[i]));
|
| - _resolveFormal(fp, optionalParameters[i]);
|
| - params.add(fp);
|
| - }
|
| - for (String k in namedParameters.keys) {
|
| - FormalParameter fp =
|
| - AstBuilder.namedFormal(_anonymousFormal(namedParameters[k]));
|
| - _resolveFormal(fp, namedParameters[k]);
|
| - params.add(fp);
|
| - }
|
| - return params;
|
| - }
|
| -
|
| - void _resolveFormal(FormalParameter fp, DartType type) {
|
| - ParameterElementImpl fe = new ParameterElementImpl.forNode(fp.identifier);
|
| - fe.parameterKind = fp.kind;
|
| - fe.type = type;
|
| - fp.identifier.staticElement = fe;
|
| - fp.identifier.staticType = type;
|
| - }
|
| -
|
| - FormalParameter _functionTypedFormal(Identifier v, FunctionType type) {
|
| - assert(v != null);
|
| - var params = _formalParameterListForFunctionType(type);
|
| - var ret = typeNameFromDartType(type.returnType);
|
| - return AstBuilder.functionTypedFormal(ret, v, params);
|
| - }
|
| -
|
| - NormalFormalParameter _anonymousFormal(DartType type) {
|
| - Identifier u = _vm.freshIdentifier("u");
|
| - return _typedFormal(u, type);
|
| - }
|
| -
|
| - NormalFormalParameter _typedFormal(Identifier v, DartType type) {
|
| - if (type is FunctionType) {
|
| - return _functionTypedFormal(v, type);
|
| - }
|
| - assert(type.name != null);
|
| - TypeName t = typeNameFromDartType(type);
|
| - return AstBuilder.simpleFormal(v, t);
|
| - }
|
| -
|
| - SimpleIdentifier freshTypeDefVariable(String hint) {
|
| - var t = _vm.freshTypeIdentifier(hint);
|
| - var desc = new NewTypeIdDesc(
|
| - fromCurrent: true, importedFrom: _currentLibrary, synthetic: true);
|
| - addedTypes[t] = desc;
|
| - return t;
|
| - }
|
| -
|
| - SimpleIdentifier typeParameterFromString(String name) =>
|
| - AstBuilder.identifierFromString(name);
|
| -
|
| - SimpleIdentifier freshReferenceToNamedType(DartType type) {
|
| - var name = type.name;
|
| - assert(name != null);
|
| - var id = AstBuilder.identifierFromString(name);
|
| - var element = type.element;
|
| - id.staticElement = element;
|
| - var library = null;
|
| - // This can happen for types like (e.g.) void
|
| - if (element != null) library = element.library;
|
| - var desc = new NewTypeIdDesc(
|
| - fromCurrent: _currentLibrary == library,
|
| - importedFrom: library,
|
| - synthetic: false);
|
| - addedTypes[id] = desc;
|
| - return id;
|
| - }
|
| -
|
| - FunctionTypeAlias _newResolvedTypedef(
|
| - FunctionType type, List<TypeParameterType> ftvs) {
|
| - // The name of the typedef (unresolved at this point)
|
| - // TODO(leafp): better naming.
|
| - SimpleIdentifier t = freshTypeDefVariable("CastType");
|
| -
|
| - // The element for the new typedef
|
| - var element = new FunctionTypeAliasElementImpl(t.name, 0);
|
| -
|
| - // Fresh type parameter identifiers for the free type variables
|
| - List<Identifier> tNames =
|
| - ftvs.map((x) => typeParameterFromString(x.name)).toList();
|
| - // The type parameters themselves
|
| - List<TypeParameter> tps = tNames.map(AstBuilder.typeParameter).toList();
|
| - // Allocate the elements for the type parameters, fill in their
|
| - // type (which makes no sense) and link up the various elements
|
| - // For each type parameter identifier, make an element and a type
|
| - // with that element, link the two together, set the identifier element
|
| - // to that element, and the identifier type to that type.
|
| - List<TypeParameterElement> tElements = tNames.map((x) {
|
| - var element = new TypeParameterElementImpl(x.name, 0);
|
| - var type = new TypeParameterTypeImpl(element);
|
| - element.type = type;
|
| - x.staticElement = element;
|
| - x.staticType = type;
|
| - return element;
|
| - }).toList();
|
| - // Get the types out from the elements
|
| - List<TypeParameterType> tTypes = tElements.map((x) => x.type).toList();
|
| - // Take the return type from the original type, and replace the free
|
| - // type variables with the fresh type variables
|
| - element.returnType = type.returnType.substitute2(tTypes, ftvs);
|
| - // Set the type parameter elements
|
| - element.typeParameters = tElements;
|
| - // Set the parent element to the current compilation unit
|
| - element.enclosingElement = _currentUnit;
|
| -
|
| - // This is the type corresponding to the typedef. Note that
|
| - // almost all methods on this type delegate to the element, so it
|
| - // cannot be safely be used for anything until the element is fully resolved
|
| - FunctionTypeImpl substType = new FunctionTypeImpl.forTypedef(element);
|
| - element.type = substType;
|
| - // Link the type and the element into the identifier for the typedef
|
| - t.staticType = substType;
|
| - t.staticElement = element;
|
| -
|
| - // Make the formal parameters for the typedef, using the original type
|
| - // with the fresh type variables substituted in.
|
| - List<FormalParameter> fps =
|
| - _formalParameterListForFunctionType(type.substitute2(tTypes, ftvs));
|
| - // Get the static elements out of the parameters, and use them to
|
| - // initialize the parameters in the element model
|
| - element.parameters = fps.map((x) => x.identifier.staticElement).toList();
|
| - // Build the return type syntax
|
| - TypeName ret = _typeNameFromDartType(substType.returnType);
|
| - // This should now be fully resolved (or at least enough so for things
|
| - // to work so far).
|
| - FunctionTypeAlias alias = AstBuilder.functionTypeAlias(ret, t, tps, fps);
|
| -
|
| - return alias;
|
| - }
|
| -
|
| - // I think we can avoid alpha-varying type parameters, since
|
| - // the binding forms are so limited, so we just re-use the
|
| - // the original names for the formals and the actuals.
|
| - TypeName _typeNameFromFunctionType(FunctionType type) {
|
| - if (_typedefs.containsKey(type)) {
|
| - var alias = _typedefs[type];
|
| - var ts = null;
|
| - var tpl = alias.typeParameters;
|
| - if (tpl != null) {
|
| - var ltp = tpl.typeParameters;
|
| - ts = new List<TypeName>.from(
|
| - ltp.map((t) => _mkNewTypeName(null, t.name, null)));
|
| - }
|
| - var name = alias.name;
|
| - return _mkNewTypeName(type, name, ts);
|
| - }
|
| -
|
| - List<TypeParameterType> ftvs = _freeTypeVariables(type);
|
| - FunctionTypeAlias alias = _newResolvedTypedef(type, ftvs);
|
| - _typedefs[type] = alias;
|
| -
|
| - List<TypeName> args = ftvs.map(_typeNameFromDartType).toList();
|
| - TypeName namedType =
|
| - _mkNewTypeName(alias.name.staticType, alias.name, args);
|
| -
|
| - return namedType;
|
| - }
|
| -
|
| - TypeName _typeNameFromDartType(DartType dType) {
|
| - String name = dType.name;
|
| - if (name == null || name == "" || dType.isBottom) {
|
| - if (dType is FunctionType) return _typeNameFromFunctionType(dType);
|
| - _log.severe("No name for type, casting through dynamic");
|
| - var d = AstBuilder.identifierFromString("dynamic");
|
| - var t = _mkNewTypeName(dType, d, null);
|
| - return t;
|
| - }
|
| - SimpleIdentifier id = freshReferenceToNamedType(dType);
|
| - List<TypeName> args = null;
|
| - if (dType is ParameterizedType) {
|
| - List<DartType> targs = dType.typeArguments;
|
| - args = targs.map(_typeNameFromDartType).toList();
|
| - }
|
| - var t = _mkNewTypeName(dType, id, args);
|
| - return t;
|
| - }
|
| -
|
| - TypeName _mkNewTypeName(DartType type, Identifier id, List<TypeName> args) {
|
| - var t = AstBuilder.typeName(id, args);
|
| - t.type = type;
|
| - return t;
|
| - }
|
| -}
|
|
|