Index: lib/src/codegen/reify_coercions.dart |
diff --git a/lib/src/codegen/reify_coercions.dart b/lib/src/codegen/reify_coercions.dart |
index c8ad334dc0e3e63b0eb04cb7b841360f3cfaaccf..e9b54b06e60b68214eda30440a8f8998e0987c86 100644 |
--- a/lib/src/codegen/reify_coercions.dart |
+++ b/lib/src/codegen/reify_coercions.dart |
@@ -12,6 +12,7 @@ import 'package:source_span/source_span.dart' show SourceFile; |
import 'package:dev_compiler/src/checker/rules.dart'; |
import 'package:dev_compiler/src/info.dart'; |
+import 'package:dev_compiler/src/options.dart' show CompilerOptions; |
import 'package:dev_compiler/src/utils.dart' as utils; |
import 'ast_builder.dart'; |
@@ -44,6 +45,14 @@ class _LocatedWrapper { |
_LocatedWrapper(this.wrapper, this.loc); |
} |
+abstract class InstrumentedRuntime { |
+ Expression wrap(Expression coercion, Expression e, Expression fromType, |
+ Expression toType, Expression dartIs, String kind, String location); |
+ Expression cast(Expression e, Expression fromType, Expression toType, |
+ Expression dartIs, String kind, String location, bool ground); |
+ Expression type(Expression witnessFunction); |
+} |
+ |
class _Inference extends DownwardsInference { |
TypeManager _tm; |
@@ -82,8 +91,10 @@ class _Inference extends DownwardsInference { |
var id = cName.type.name; |
var typeName = AstBuilder.typeName(id, tNames); |
cName.type = typeName; |
- var rawType = (e.staticType.element as ClassElement).type; |
- e.staticType = rawType.substitute4(targs); |
+ var newType = |
+ (e.staticType.element as ClassElement).type.substitute4(targs); |
+ e.staticType = newType; |
+ typeName.type = newType; |
} |
@override |
@@ -105,16 +116,22 @@ class CoercionReifier extends analyzer.GeneralizingAstVisitor<Object> |
bool _skipCoercions = false; |
final TypeRules _rules; |
final _Inference _inferrer; |
+ final InstrumentedRuntime _runtime; |
+ final CompilerOptions _options; |
- CoercionReifier._( |
- this._cm, this._tm, this._vm, this._library, this._rules, this._inferrer); |
+ CoercionReifier._(this._cm, this._tm, this._vm, this._library, this._rules, |
+ this._inferrer, this._runtime, this._options); |
- factory CoercionReifier(LibraryUnit library, TypeRules rules) { |
+ factory CoercionReifier( |
+ LibraryUnit library, TypeRules rules, CompilerOptions options, |
+ [InstrumentedRuntime runtime]) { |
var vm = new VariableManager(); |
- var tm = new TypeManager(library.library.element.enclosingElement, vm); |
- var cm = new CoercionManager(vm, tm, rules); |
+ var tm = |
+ new TypeManager(library.library.element.enclosingElement, vm, runtime); |
+ var cm = new CoercionManager(vm, tm, rules, runtime); |
var inferrer = new _Inference(rules, tm); |
- return new CoercionReifier._(cm, tm, vm, library, rules, inferrer); |
+ return new CoercionReifier._( |
+ cm, tm, vm, library, rules, inferrer, runtime, options); |
} |
// This should be the entry point for this class. Entering via the |
@@ -140,7 +157,7 @@ class CoercionReifier extends analyzer.GeneralizingAstVisitor<Object> |
final begin = e is AnnotatedNode |
? (e as AnnotatedNode).firstTokenAfterCommentAndMetadata.offset |
: e.offset; |
- if (begin != 0) { |
+ if (begin != 0 && e.end > begin) { |
var span = _file.span(begin, e.end); |
var s = span.message("Cast"); |
return s.substring(0, s.indexOf("Cast")); |
@@ -163,6 +180,7 @@ class CoercionReifier extends analyzer.GeneralizingAstVisitor<Object> |
@override |
Object visitAsExpression(AsExpression e) { |
+ if (_runtime == null) return super.visitAsExpression(e); |
var cast = Coercion.cast(_rules.getStaticType(e.expression), e.type.type); |
var loc = _locationInfo(e); |
Expression castNode = |
@@ -188,7 +206,7 @@ class CoercionReifier extends analyzer.GeneralizingAstVisitor<Object> |
@override |
Object visitDownCast(DownCast node) { |
- if (_skipCoercions) { |
+ if (_skipCoercions && !_options.allowConstCasts) { |
_log.severe("Skipping runtime downcast in constant context"); |
return null; |
} |
@@ -205,7 +223,7 @@ class CoercionReifier extends analyzer.GeneralizingAstVisitor<Object> |
// TODO(leafp): Bind the coercions at the top level |
@override |
Object visitClosureWrapBase(ClosureWrapBase node) { |
- if (_skipCoercions) { |
+ if (_skipCoercions && !_options.allowConstCasts) { |
_log.severe("Skipping coercion wrap in constant context"); |
return null; |
} |
@@ -241,7 +259,7 @@ class CoercionReifier extends analyzer.GeneralizingAstVisitor<Object> |
} |
Object visitCompilationUnit(CompilationUnit unit) { |
- _cm.enterCompilationUnit(); |
+ _cm.enterCompilationUnit(unit); |
Object ret = super.visitCompilationUnit(unit); |
_cm.exitCompilationUnit(unit); |
return ret; |
@@ -264,14 +282,14 @@ class VariableManager { |
// TODO(leafp): Hack, not for real. |
int _id = 0; |
- Identifier freshIdentifier(String hint) { |
+ SimpleIdentifier freshIdentifier(String hint) { |
String n = _id.toString(); |
_id++; |
String s = "__$hint$n"; |
return AstBuilder.identifierFromString(s); |
} |
- Identifier freshTypeIdentifier(String hint) { |
+ SimpleIdentifier freshTypeIdentifier(String hint) { |
return freshIdentifier(hint); |
} |
} |
@@ -292,6 +310,7 @@ class CoercionManager { |
TypeManager _tm; |
bool _hoistWrappers = false; |
TypeRules _rules; |
+ InstrumentedRuntime _runtime; |
// A map containing all of the wrappers collected but not yet discharged |
final Map<Identifier, _LocatedWrapper> _topWrappers = |
@@ -300,14 +319,14 @@ class CoercionManager { |
<Identifier, _LocatedWrapper>{}; |
Map<Identifier, _LocatedWrapper> _wrappers; |
- CoercionManager(this._vm, this._tm, this._rules) { |
+ CoercionManager(this._vm, this._tm, this._rules, [this._runtime]) { |
_wrappers = _topWrappers; |
} |
// Call on entry to and exit from a compilation unit in order to properly |
// discharge the accumulated wrappers. |
- void enterCompilationUnit() { |
- _tm.enterCompilationUnit(); |
+ void enterCompilationUnit(CompilationUnit unit) { |
+ _tm.enterCompilationUnit(unit); |
_wrappers = _topWrappers; |
} |
void exitCompilationUnit(CompilationUnit unit) { |
@@ -358,6 +377,11 @@ class CoercionManager { |
Expression _wrapExpression(Expression e, Wrapper w, String k, String loc) { |
var q = _addWrapper(w, loc); |
+ if (_runtime == null) { |
+ var app = AstBuilder.application(q, <Expression>[e]); |
+ app.staticType = w.toType; |
+ return app; |
+ } |
var ttName = _tm.typeNameFromDartType(w.toType); |
var tt = _tm.typeExpression(ttName); |
var ft = _tm.typeExpressionFromDartType(w.fromType); |
@@ -368,15 +392,18 @@ class CoercionManager { |
var tup = _bindExpression("x", e); |
var id = tup.e0; |
var binder = tup.e1; |
- var kind = AstBuilder.stringLiteral(k); |
- var key = AstBuilder.multiLineStringLiteral(loc); |
var dartIs = AstBuilder.isExpression(AstBuilder.parenthesize(id), ttName); |
- var arguments = <Expression>[q, id, ft, tt, kind, key, dartIs]; |
- return binder(new RuntimeOperation("wrap", arguments)); |
+ var oper = _runtime.wrap(q, id, ft, tt, dartIs, k, loc); |
+ return binder(oper); |
} |
Expression _castExpression(Expression e, Cast c, String k, String loc) { |
var ttName = _tm.typeNameFromDartType(c.toType); |
+ if (_runtime == null) { |
+ var cast = AstBuilder.asExpression(e, ttName); |
+ cast.staticType = c.toType; |
+ return cast; |
+ } |
var tt = _tm.typeExpression(ttName); |
var ft = _tm.typeExpressionFromDartType(c.fromType); |
if (c.fromType.element == null) { |
@@ -390,12 +417,10 @@ class CoercionManager { |
var tup = _bindExpression("x", e); |
var id = tup.e0; |
var binder = tup.e1; |
- var kind = AstBuilder.stringLiteral(k); |
- var key = AstBuilder.multiLineStringLiteral(loc); |
var dartIs = AstBuilder.isExpression(AstBuilder.parenthesize(id), ttName); |
- var ground = AstBuilder.booleanLiteral(_rules.isGroundType(c.toType)); |
- var arguments = <Expression>[id, ft, tt, kind, key, dartIs, ground]; |
- return binder(new RuntimeOperation("cast", arguments)); |
+ var ground = _rules.isGroundType(c.toType); |
+ var oper = _runtime.cast(id, ft, tt, dartIs, k, loc, ground); |
+ return binder(oper); |
} |
Expression _coerceExpression( |
@@ -554,14 +579,19 @@ class TypeManager { |
final VariableManager _vm; |
final LibraryElement _currentLibrary; |
final Map<Identifier, NewTypeIdDesc> addedTypes = {}; |
+ final InstrumentedRuntime _runtime; |
+ 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); |
+ TypeManager(this._currentLibrary, this._vm, [this._runtime]); |
+ |
+ void enterCompilationUnit(CompilationUnit unit) { |
+ _currentUnit = unit.element; |
+ } |
- void enterCompilationUnit() {} |
void exitCompilationUnit(CompilationUnit unit) { |
unit.declarations.addAll(_typedefs.values); |
_typedefs.clear(); |
@@ -631,20 +661,34 @@ class TypeManager { |
var optionalParameters = type.optionalParameterTypes; |
var params = new List<FormalParameter>(); |
for (int i = 0; i < normalParameters.length; i++) { |
- FormalParameter fp = _anonymousFormal(normalParameters[i]); |
- params.add(AstBuilder.requiredFormal(fp)); |
+ FormalParameter fp = |
+ AstBuilder.requiredFormal(_anonymousFormal(normalParameters[i])); |
+ _resolveFormal(fp, normalParameters[i]); |
+ params.add(fp); |
} |
for (int i = 0; i < optionalParameters.length; i++) { |
- FormalParameter fp = _anonymousFormal(optionalParameters[i]); |
- params.add(AstBuilder.optionalFormal(fp)); |
+ FormalParameter fp = |
+ AstBuilder.optionalFormal(_anonymousFormal(optionalParameters[i])); |
+ _resolveFormal(fp, optionalParameters[i]); |
+ params.add(fp); |
} |
for (String k in namedParameters.keys) { |
- FormalParameter fp = _anonymousFormal(namedParameters[k]); |
- params.add(AstBuilder.namedFormal(fp)); |
+ 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); |
@@ -666,18 +710,18 @@ class TypeManager { |
return AstBuilder.simpleFormal(v, t); |
} |
- Identifier freshTypeDefVariable() { |
- var t = _vm.freshTypeIdentifier("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; |
} |
- Identifier typeParameterFromString(String name) => |
+ SimpleIdentifier typeParameterFromString(String name) => |
AstBuilder.identifierFromString(name); |
- Identifier freshReferenceToNamedType(DartType type) { |
+ SimpleIdentifier freshReferenceToNamedType(DartType type) { |
var name = type.name; |
assert(name != null); |
var id = AstBuilder.identifierFromString(name); |
@@ -694,6 +738,68 @@ class TypeManager { |
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.con2(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. |
@@ -705,26 +811,19 @@ class TypeManager { |
if (tpl != null) { |
var ltp = tpl.typeParameters; |
ts = new List<TypeName>.from( |
- ltp.map((t) => _mkNewTypeName(t.name, null))); |
+ ltp.map((t) => _mkNewTypeName(null, t.name, null))); |
} |
var name = alias.name; |
- return _mkNewTypeName(name, ts); |
+ return _mkNewTypeName(type, name, ts); |
} |
List<TypeParameterType> ftvs = _freeTypeVariables(type); |
- Identifier t = freshTypeDefVariable(); |
- |
- Iterable<Identifier> tNames = |
- ftvs.map((x) => typeParameterFromString(x.name)); |
- List<TypeParameter> tps = tNames.map(AstBuilder.typeParameter).toList(); |
- List<FormalParameter> fps = _formalParameterListForFunctionType(type); |
- TypeName ret = _typeNameFromDartType(type.returnType); |
- FunctionTypeAlias alias = AstBuilder.functionTypeAlias(ret, t, tps, fps); |
- |
+ FunctionTypeAlias alias = _newResolvedTypedef(type, ftvs); |
_typedefs[type] = alias; |
List<TypeName> args = ftvs.map(_typeNameFromDartType).toList(); |
- TypeName namedType = _mkNewTypeName(t, args); |
+ TypeName namedType = |
+ _mkNewTypeName(alias.name.staticType, alias.name, args); |
return namedType; |
} |
@@ -735,8 +834,7 @@ class TypeManager { |
if (dType is FunctionType) return _typeNameFromFunctionType(dType); |
_log.severe("No name for type, casting through dynamic"); |
var d = AstBuilder.identifierFromString("dynamic"); |
- var t = _mkNewTypeName(d, null); |
- t.type = dType; |
+ var t = _mkNewTypeName(dType, d, null); |
return t; |
} |
SimpleIdentifier id = freshReferenceToNamedType(dType); |
@@ -745,22 +843,23 @@ class TypeManager { |
List<DartType> targs = dType.typeArguments; |
args = targs.map(_typeNameFromDartType).toList(); |
} |
- var t = _mkNewTypeName(id, args); |
- t.type = dType; |
+ var t = _mkNewTypeName(dType, id, args); |
return t; |
} |
- TypeName _mkNewTypeName(Identifier id, List<TypeName> args) { |
+ TypeName _mkNewTypeName(DartType type, Identifier id, List<TypeName> args) { |
var t = AstBuilder.typeName(id, args); |
+ t.type = type; |
return t; |
} |
Expression _typeExpression(TypeName t) { |
+ assert(_runtime != null); |
if (t.typeArguments != null && t.typeArguments.length > 0) { |
var w = AstBuilder.identifierFromString("_"); |
var fp = AstBuilder.simpleFormal(w, t); |
var f = AstBuilder.blockFunction(<FormalParameter>[fp], <Statement>[]); |
- return new RuntimeOperation("type", <Expression>[f]); |
+ return _runtime.type(f); |
} |
return t.name; |
} |