Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(856)

Side by Side Diff: lib/src/codegen/reify_coercions.dart

Issue 1783603009: simplify function coercions -- DDC can generate function types in place (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/runtime/dart/indexed_db.js ('k') | lib/src/utils.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 import 'package:analyzer/analyzer.dart' as analyzer; 5 import 'package:analyzer/analyzer.dart' as analyzer;
6 import 'package:analyzer/src/generated/ast.dart'; 6 import 'package:analyzer/src/generated/ast.dart';
7 import 'package:analyzer/src/generated/element.dart'; 7 import 'package:analyzer/src/generated/element.dart';
8 import 'package:analyzer/src/generated/type_system.dart' 8 import 'package:analyzer/src/generated/type_system.dart'
9 show StrongTypeSystemImpl; 9 show StrongTypeSystemImpl;
10 import 'package:logging/logging.dart' as logger; 10 import 'package:logging/logging.dart' as logger;
11 11
12 import '../info.dart'; 12 import '../info.dart';
13 13
14 import 'ast_builder.dart'; 14 import 'ast_builder.dart';
15 15
16 final _log = new logger.Logger('dev_compiler.reify_coercions'); 16 final _log = new logger.Logger('dev_compiler.reify_coercions');
17 17
18 // TODO(leafp) Factor this out or use an existing library
19 class Tuple2<T0, T1> {
20 final T0 e0;
21 final T1 e1;
22 Tuple2(this.e0, this.e1);
23 }
24
25 typedef T Function1<S, T>(S _);
26
27 class NewTypeIdDesc { 18 class NewTypeIdDesc {
28 /// If null, then this is not a library level identifier (i.e. it's 19 /// If null, then this is not a library level identifier (i.e. it's
29 /// a type parameter, or a special type like void, dynamic, etc) 20 /// a type parameter, or a special type like void, dynamic, etc)
30 LibraryElement importedFrom; 21 LibraryElement importedFrom;
31 22
32 /// True => use/def in same library 23 /// True => use/def in same library
33 bool fromCurrent; 24 bool fromCurrent;
34 25
35 /// True => not a source variable 26 /// True => not a source variable
36 bool synthetic; 27 bool synthetic;
37 NewTypeIdDesc({this.fromCurrent, this.importedFrom, this.synthetic}); 28 NewTypeIdDesc({this.fromCurrent, this.importedFrom, this.synthetic});
38 } 29 }
39 30
40 // This class implements a pass which modifies (in place) the ast replacing 31 // This class implements a pass which modifies (in place) the ast replacing
41 // abstract coercion nodes with their dart implementations. 32 // abstract coercion nodes with their dart implementations.
42 class CoercionReifier extends analyzer.GeneralizingAstVisitor<Object> { 33 class CoercionReifier extends analyzer.GeneralizingAstVisitor<Object> {
43 final CoercionManager _cm;
44 final TypeManager _tm;
45 final VariableManager _vm;
46 final LibraryUnit _library; 34 final LibraryUnit _library;
47 final StrongTypeSystemImpl _typeSystem; 35 final StrongTypeSystemImpl _typeSystem;
48 36
49 CoercionReifier._( 37 CoercionReifier(this._library, this._typeSystem);
50 this._cm, this._tm, this._vm, this._library, this._typeSystem);
51
52 factory CoercionReifier(
53 LibraryUnit library, StrongTypeSystemImpl typeSystem) {
54 var vm = new VariableManager();
55 var tm = new TypeManager(library.library.element.enclosingElement, vm);
56 var cm = new CoercionManager(vm, tm);
57 return new CoercionReifier._(cm, tm, vm, library, typeSystem);
58 }
59 38
60 // This should be the entry point for this class. Entering via the 39 // This should be the entry point for this class. Entering via the
61 // visit functions directly may not do the right thing with respect 40 // visit functions directly may not do the right thing with respect
62 // to discharging the collected definitions. 41 // to discharging the collected definitions.
63 // Returns the set of new type identifiers added by the reifier 42 // Returns the set of new type identifiers added by the reifier
64 Map<Identifier, NewTypeIdDesc> reify() { 43 void reify() {
65 _library.partsThenLibrary.forEach(visitCompilationUnit); 44 _library.partsThenLibrary.forEach(visitCompilationUnit);
66 return _tm.addedTypes;
67 } 45 }
68 46
69 @override 47 @override
70 Object visitExpression(Expression node) { 48 Object visitExpression(Expression node) {
71 var info = CoercionInfo.get(node); 49 var info = CoercionInfo.get(node);
72 if (info is InferredTypeBase) { 50 if (info is InferredTypeBase) {
73 return _visitInferredTypeBase(info, node); 51 return _visitInferredTypeBase(info, node);
74 } else if (info is DownCast) { 52 } else if (info is DownCast) {
75 return _visitDownCast(info, node); 53 return _visitDownCast(info, node);
76 } 54 }
(...skipping 11 matching lines...) Expand all
88 CoercionInfo.set(expr, info); 66 CoercionInfo.set(expr, info);
89 } 67 }
90 } 68 }
91 expr.visitChildren(this); 69 expr.visitChildren(this);
92 return null; 70 return null;
93 } 71 }
94 72
95 Object _visitDownCast(DownCast node, Expression expr) { 73 Object _visitDownCast(DownCast node, Expression expr) {
96 var parent = expr.parent; 74 var parent = expr.parent;
97 expr.visitChildren(this); 75 expr.visitChildren(this);
98 Expression newE = _cm.coerceExpression(expr, node.cast); 76 Expression newE = coerceExpression(expr, node.cast);
99 if (!identical(expr, newE)) { 77 if (!identical(expr, newE)) {
100 var replaced = parent.accept(new NodeReplacer(expr, newE)); 78 var replaced = parent.accept(new NodeReplacer(expr, newE));
101 // It looks like NodeReplacer will always return true. 79 // It looks like NodeReplacer will always return true.
102 // It does throw IllegalArgumentException though, if child is not found. 80 // It does throw IllegalArgumentException though, if child is not found.
103 assert(replaced); 81 assert(replaced);
104 } 82 }
105 return null; 83 return null;
106 } 84 }
107 85
108 Object visitCompilationUnit(CompilationUnit unit) {
109 _cm.enterCompilationUnit(unit);
110 Object ret = super.visitCompilationUnit(unit);
111 _cm.exitCompilationUnit(unit);
112 return ret;
113 }
114
115 DartType _getStaticType(Expression expr) { 86 DartType _getStaticType(Expression expr) {
116 return expr.staticType ?? DynamicTypeImpl.instance; 87 return expr.staticType ?? DynamicTypeImpl.instance;
117 } 88 }
118 }
119 89
120 // This provides a placeholder variable manager. Currently it simply 90 /// Coerce [e] using [c], returning a new expression.
121 // mangles names in a way unlikely (but not guaranteed) to avoid
122 // collisions with user variables.
123 // TODO(leafp): Replace this with something real.
124 class VariableManager {
125 // TODO(leafp): Hack, not for real.
126 int _id = 0;
127
128 SimpleIdentifier freshIdentifier(String hint) {
129 String n = _id.toString();
130 _id++;
131 String s = "__$hint$n";
132 return AstBuilder.identifierFromString(s);
133 }
134
135 SimpleIdentifier freshTypeIdentifier(String hint) {
136 return freshIdentifier(hint);
137 }
138 }
139
140 // This class manages the reification of coercions as dart code. Given a
141 // coercion c and an expression e it will produce an expression e' which
142 // is the result of coercing e using c.
143 class CoercionManager {
144 VariableManager _vm;
145 TypeManager _tm;
146
147 CoercionManager(this._vm, this._tm);
148
149 // Call on entry to and exit from a compilation unit in order to properly
150 // discharge the accumulated wrappers.
151 void enterCompilationUnit(CompilationUnit unit) {
152 _tm.enterCompilationUnit(unit);
153 }
154
155 void exitCompilationUnit(CompilationUnit unit) {
156 _tm.exitCompilationUnit(unit);
157 }
158
159 // The main entry point. Coerce e using c, returning a new expression,
160 // possibly recording additional coercions functions and typedefs to
161 // be discharged at a higher level.
162 Expression coerceExpression(Expression e, Coercion c) { 91 Expression coerceExpression(Expression e, Coercion c) {
163 assert(c != null); 92 assert(c != null);
164 assert(c is! CoercionError); 93 assert(c is! CoercionError);
165 if (e is NamedExpression) { 94 if (e is NamedExpression) {
166 Expression inner = coerceExpression(e.expression, c); 95 Expression inner = coerceExpression(e.expression, c);
167 return new NamedExpression(e.name, inner); 96 return new NamedExpression(e.name, inner);
168 } 97 }
169 if (c is Cast) return _castExpression(e, c); 98 if (c is Cast) return _castExpression(e, c);
170 assert(c is Identity); 99 assert(c is Identity);
171 return e; 100 return e;
172 } 101 }
173 102
174 ///////////////// Private ////////////////////////////////// 103 ///////////////// Private //////////////////////////////////
175 104
176 Expression _castExpression(Expression e, Cast c) { 105 Expression _castExpression(Expression e, Cast c) {
177 var ttName = _tm.typeNameFromDartType(c.toType); 106 // We use an empty name in the AST, because the JS code generator only cares
178 var cast = AstBuilder.asExpression(e, ttName); 107 // about the target type. It does not look at the AST name.
108 var typeName = new TypeName(AstBuilder.identifierFromString(''), null);
109 typeName.type = c.toType;
110 var cast = AstBuilder.asExpression(e, typeName);
179 cast.staticType = c.toType; 111 cast.staticType = c.toType;
180 return cast; 112 return cast;
181 } 113 }
182 } 114 }
183
184 // A class for managing the interaction between the DartType hierarchy
185 // and the AST type representation. It provides utilities to translate
186 // a DartType to AST. In order to do so, it maintains a map of typedefs
187 // naming otherwise un-named types. These must be discharged at the top
188 // level of the compilation unit in order to produce well-formed dart code.
189 // Note that in order to hoist the typedefs out of parameterized classes
190 // we must close over any type variables.
191 class TypeManager {
192 final VariableManager _vm;
193 final LibraryElement _currentLibrary;
194 final Map<Identifier, NewTypeIdDesc> addedTypes = {};
195 CompilationUnitElement _currentUnit;
196
197 /// A map containing new function typedefs to be introduced at the top level
198 /// This uses LinkedHashMap to emit code in a consistent order.
199 final Map<FunctionType, FunctionTypeAlias> _typedefs = {};
200
201 TypeManager(this._currentLibrary, this._vm);
202
203 void enterCompilationUnit(CompilationUnit unit) {
204 _currentUnit = unit.element;
205 }
206
207 void exitCompilationUnit(CompilationUnit unit) {
208 unit.declarations.addAll(_typedefs.values);
209 _typedefs.clear();
210 }
211
212 TypeName typeNameFromDartType(DartType dType) {
213 return _typeNameFromDartType(dType);
214 }
215
216 NormalFormalParameter typedFormal(Identifier v, DartType type) {
217 return _typedFormal(v, type);
218 }
219
220 ///////////////// Private //////////////////////////////////
221 List<TypeParameterType> _freeTypeVariables(DartType type) {
222 var s = new Set<TypeParameterType>();
223
224 void _ft(DartType type) {
225 void _ftMap(Map<String, DartType> m) {
226 if (m == null) return;
227 for (var k in m.keys) _ft(m[k]);
228 }
229 void _ftList(List<DartType> l) {
230 if (l == null) return;
231 for (int i = 0; i < l.length; i++) _ft(l[i]);
232 }
233
234 if (type == null) return;
235 if (type.isDynamic) return;
236 if (type.isBottom) return;
237 if (type.isObject) return;
238 if (type is TypeParameterType) {
239 s.add(type);
240 return;
241 }
242 if (type is ParameterizedType) {
243 if (type.name != null && type.name != "") {
244 _ftList(type.typeArguments);
245 return;
246 }
247 if (type is FunctionType) {
248 _ftMap(type.namedParameterTypes);
249 _ftList(type.normalParameterTypes);
250 _ftList(type.optionalParameterTypes);
251 _ft(type.returnType);
252 return;
253 }
254 assert(type is! InterfaceType);
255 assert(false);
256 }
257 if (type is VoidType) return;
258 print(type.toString());
259 assert(false);
260 }
261 _ft(type);
262 return s.toList();
263 }
264
265 List<FormalParameter> _formalParameterListForFunctionType(FunctionType type) {
266 var namedParameters = type.namedParameterTypes;
267 var normalParameters = type.normalParameterTypes;
268 var optionalParameters = type.optionalParameterTypes;
269 var params = new List<FormalParameter>();
270 for (int i = 0; i < normalParameters.length; i++) {
271 FormalParameter fp =
272 AstBuilder.requiredFormal(_anonymousFormal(normalParameters[i]));
273 _resolveFormal(fp, normalParameters[i]);
274 params.add(fp);
275 }
276 for (int i = 0; i < optionalParameters.length; i++) {
277 FormalParameter fp =
278 AstBuilder.optionalFormal(_anonymousFormal(optionalParameters[i]));
279 _resolveFormal(fp, optionalParameters[i]);
280 params.add(fp);
281 }
282 for (String k in namedParameters.keys) {
283 FormalParameter fp =
284 AstBuilder.namedFormal(_anonymousFormal(namedParameters[k]));
285 _resolveFormal(fp, namedParameters[k]);
286 params.add(fp);
287 }
288 return params;
289 }
290
291 void _resolveFormal(FormalParameter fp, DartType type) {
292 ParameterElementImpl fe = new ParameterElementImpl.forNode(fp.identifier);
293 fe.parameterKind = fp.kind;
294 fe.type = type;
295 fp.identifier.staticElement = fe;
296 fp.identifier.staticType = type;
297 }
298
299 FormalParameter _functionTypedFormal(Identifier v, FunctionType type) {
300 assert(v != null);
301 var params = _formalParameterListForFunctionType(type);
302 var ret = typeNameFromDartType(type.returnType);
303 return AstBuilder.functionTypedFormal(ret, v, params);
304 }
305
306 NormalFormalParameter _anonymousFormal(DartType type) {
307 Identifier u = _vm.freshIdentifier("u");
308 return _typedFormal(u, type);
309 }
310
311 NormalFormalParameter _typedFormal(Identifier v, DartType type) {
312 if (type is FunctionType) {
313 return _functionTypedFormal(v, type);
314 }
315 assert(type.name != null);
316 TypeName t = typeNameFromDartType(type);
317 return AstBuilder.simpleFormal(v, t);
318 }
319
320 SimpleIdentifier freshTypeDefVariable(String hint) {
321 var t = _vm.freshTypeIdentifier(hint);
322 var desc = new NewTypeIdDesc(
323 fromCurrent: true, importedFrom: _currentLibrary, synthetic: true);
324 addedTypes[t] = desc;
325 return t;
326 }
327
328 SimpleIdentifier typeParameterFromString(String name) =>
329 AstBuilder.identifierFromString(name);
330
331 SimpleIdentifier freshReferenceToNamedType(DartType type) {
332 var name = type.name;
333 assert(name != null);
334 var id = AstBuilder.identifierFromString(name);
335 var element = type.element;
336 id.staticElement = element;
337 var library = null;
338 // This can happen for types like (e.g.) void
339 if (element != null) library = element.library;
340 var desc = new NewTypeIdDesc(
341 fromCurrent: _currentLibrary == library,
342 importedFrom: library,
343 synthetic: false);
344 addedTypes[id] = desc;
345 return id;
346 }
347
348 FunctionTypeAlias _newResolvedTypedef(
349 FunctionType type, List<TypeParameterType> ftvs) {
350 // The name of the typedef (unresolved at this point)
351 // TODO(leafp): better naming.
352 SimpleIdentifier t = freshTypeDefVariable("CastType");
353
354 // The element for the new typedef
355 var element = new FunctionTypeAliasElementImpl(t.name, 0);
356
357 // Fresh type parameter identifiers for the free type variables
358 List<Identifier> tNames =
359 ftvs.map((x) => typeParameterFromString(x.name)).toList();
360 // The type parameters themselves
361 List<TypeParameter> tps = tNames.map(AstBuilder.typeParameter).toList();
362 // Allocate the elements for the type parameters, fill in their
363 // type (which makes no sense) and link up the various elements
364 // For each type parameter identifier, make an element and a type
365 // with that element, link the two together, set the identifier element
366 // to that element, and the identifier type to that type.
367 List<TypeParameterElement> tElements = tNames.map((x) {
368 var element = new TypeParameterElementImpl(x.name, 0);
369 var type = new TypeParameterTypeImpl(element);
370 element.type = type;
371 x.staticElement = element;
372 x.staticType = type;
373 return element;
374 }).toList();
375 // Get the types out from the elements
376 List<TypeParameterType> tTypes = tElements.map((x) => x.type).toList();
377 // Take the return type from the original type, and replace the free
378 // type variables with the fresh type variables
379 element.returnType = type.returnType.substitute2(tTypes, ftvs);
380 // Set the type parameter elements
381 element.typeParameters = tElements;
382 // Set the parent element to the current compilation unit
383 element.enclosingElement = _currentUnit;
384
385 // This is the type corresponding to the typedef. Note that
386 // almost all methods on this type delegate to the element, so it
387 // cannot be safely be used for anything until the element is fully resolved
388 FunctionTypeImpl substType = new FunctionTypeImpl.forTypedef(element);
389 element.type = substType;
390 // Link the type and the element into the identifier for the typedef
391 t.staticType = substType;
392 t.staticElement = element;
393
394 // Make the formal parameters for the typedef, using the original type
395 // with the fresh type variables substituted in.
396 List<FormalParameter> fps =
397 _formalParameterListForFunctionType(type.substitute2(tTypes, ftvs));
398 // Get the static elements out of the parameters, and use them to
399 // initialize the parameters in the element model
400 element.parameters = fps.map((x) => x.identifier.staticElement).toList();
401 // Build the return type syntax
402 TypeName ret = _typeNameFromDartType(substType.returnType);
403 // This should now be fully resolved (or at least enough so for things
404 // to work so far).
405 FunctionTypeAlias alias = AstBuilder.functionTypeAlias(ret, t, tps, fps);
406
407 return alias;
408 }
409
410 // I think we can avoid alpha-varying type parameters, since
411 // the binding forms are so limited, so we just re-use the
412 // the original names for the formals and the actuals.
413 TypeName _typeNameFromFunctionType(FunctionType type) {
414 if (_typedefs.containsKey(type)) {
415 var alias = _typedefs[type];
416 var ts = null;
417 var tpl = alias.typeParameters;
418 if (tpl != null) {
419 var ltp = tpl.typeParameters;
420 ts = new List<TypeName>.from(
421 ltp.map((t) => _mkNewTypeName(null, t.name, null)));
422 }
423 var name = alias.name;
424 return _mkNewTypeName(type, name, ts);
425 }
426
427 List<TypeParameterType> ftvs = _freeTypeVariables(type);
428 FunctionTypeAlias alias = _newResolvedTypedef(type, ftvs);
429 _typedefs[type] = alias;
430
431 List<TypeName> args = ftvs.map(_typeNameFromDartType).toList();
432 TypeName namedType =
433 _mkNewTypeName(alias.name.staticType, alias.name, args);
434
435 return namedType;
436 }
437
438 TypeName _typeNameFromDartType(DartType dType) {
439 String name = dType.name;
440 if (name == null || name == "" || dType.isBottom) {
441 if (dType is FunctionType) return _typeNameFromFunctionType(dType);
442 _log.severe("No name for type, casting through dynamic");
443 var d = AstBuilder.identifierFromString("dynamic");
444 var t = _mkNewTypeName(dType, d, null);
445 return t;
446 }
447 SimpleIdentifier id = freshReferenceToNamedType(dType);
448 List<TypeName> args = null;
449 if (dType is ParameterizedType) {
450 List<DartType> targs = dType.typeArguments;
451 args = targs.map(_typeNameFromDartType).toList();
452 }
453 var t = _mkNewTypeName(dType, id, args);
454 return t;
455 }
456
457 TypeName _mkNewTypeName(DartType type, Identifier id, List<TypeName> args) {
458 var t = AstBuilder.typeName(id, args);
459 t.type = type;
460 return t;
461 }
462 }
OLDNEW
« no previous file with comments | « lib/runtime/dart/indexed_db.js ('k') | lib/src/utils.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698