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

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

Issue 1171713002: remove ClosureWrap option and related implementation (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 6 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/src/checker/rules.dart ('k') | lib/src/info.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 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;
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
139 @override 139 @override
140 Object visitDownCast(DownCast node) { 140 Object visitDownCast(DownCast node) {
141 Expression castNode = _cm.coerceExpression(node.node, node.cast); 141 Expression castNode = _cm.coerceExpression(node.node, node.cast);
142 if (!NodeReplacer.replace(node, castNode)) { 142 if (!NodeReplacer.replace(node, castNode)) {
143 _log.severe("Failed to replace node for DownCast"); 143 _log.severe("Failed to replace node for DownCast");
144 } 144 }
145 castNode.accept(this); 145 castNode.accept(this);
146 return null; 146 return null;
147 } 147 }
148 148
149 // TODO(leafp): Bind the coercions at the top level
150 @override
151 Object visitClosureWrapBase(ClosureWrapBase node) {
152 Expression newE = _cm.coerceExpression(node.node, node.wrapper);
153 if (!NodeReplacer.replace(node, newE)) {
154 _log.severe("Failed to replace node for Closure Wrap");
155 }
156 newE.accept(this);
157 return null;
158 }
159
160 Object visitCompilationUnit(CompilationUnit unit) { 149 Object visitCompilationUnit(CompilationUnit unit) {
161 _cm.enterCompilationUnit(unit); 150 _cm.enterCompilationUnit(unit);
162 Object ret = super.visitCompilationUnit(unit); 151 Object ret = super.visitCompilationUnit(unit);
163 _cm.exitCompilationUnit(unit); 152 _cm.exitCompilationUnit(unit);
164 return ret; 153 return ret;
165 } 154 }
166
167 @override
168 Object visitClassDeclaration(ClassDeclaration cl) {
169 _cm.enterClass();
170 Object ret = super.visitClassDeclaration(cl);
171 _cm.exitClass(cl);
172 return ret;
173 }
174 } 155 }
175 156
176 // This provides a placeholder variable manager. Currently it simply 157 // This provides a placeholder variable manager. Currently it simply
177 // mangles names in a way unlikely (but not guaranteed) to avoid 158 // mangles names in a way unlikely (but not guaranteed) to avoid
178 // collisions with user variables. 159 // collisions with user variables.
179 // TODO(leafp): Replace this with something real. 160 // TODO(leafp): Replace this with something real.
180 class VariableManager { 161 class VariableManager {
181 // TODO(leafp): Hack, not for real. 162 // TODO(leafp): Hack, not for real.
182 int _id = 0; 163 int _id = 0;
183 164
184 SimpleIdentifier freshIdentifier(String hint) { 165 SimpleIdentifier freshIdentifier(String hint) {
185 String n = _id.toString(); 166 String n = _id.toString();
186 _id++; 167 _id++;
187 String s = "__$hint$n"; 168 String s = "__$hint$n";
188 return AstBuilder.identifierFromString(s); 169 return AstBuilder.identifierFromString(s);
189 } 170 }
190 171
191 SimpleIdentifier freshTypeIdentifier(String hint) { 172 SimpleIdentifier freshTypeIdentifier(String hint) {
192 return freshIdentifier(hint); 173 return freshIdentifier(hint);
193 } 174 }
194 } 175 }
195 176
196 // This class manages the reification of coercions as dart code. Given a 177 // This class manages the reification of coercions as dart code. Given a
197 // coercion c and an expression e it will produce an expression e' which 178 // coercion c and an expression e it will produce an expression e' which
198 // is the result of coercing e using c. For closure wrappers, it maintains 179 // is the result of coercing e using c.
199 // a table of wrapper functions to be hoisted out to either the enclosing
200 // class level, or to the top level if not in a class (hoisting only to the
201 // class level avoids having to close over type variables, which is not
202 // easily done given the lack of generic functions). Generating the coercions
203 // inline is possible as well, but is quite a bit messier and harder to read
204 // since in general we need to bind the coerced expression to a lambda
205 // bound variable, both in order to deal with side-effects and to be
206 // able to properly record the return type of the wrapper function.
207 class CoercionManager { 180 class CoercionManager {
208 VariableManager _vm; 181 VariableManager _vm;
209 TypeManager _tm; 182 TypeManager _tm;
210 bool _hoistWrappers = false;
211 183
212 // A map containing all of the wrappers collected but not yet discharged 184 CoercionManager(this._vm, this._tm);
213 final Map<Identifier, Wrapper> _topWrappers = <Identifier, Wrapper>{};
214 final Map<Identifier, Wrapper> _classWrappers = <Identifier, Wrapper>{};
215 Map<Identifier, Wrapper> _wrappers;
216
217 CoercionManager(this._vm, this._tm) {
218 _wrappers = _topWrappers;
219 }
220 185
221 // Call on entry to and exit from a compilation unit in order to properly 186 // Call on entry to and exit from a compilation unit in order to properly
222 // discharge the accumulated wrappers. 187 // discharge the accumulated wrappers.
223 void enterCompilationUnit(CompilationUnit unit) { 188 void enterCompilationUnit(CompilationUnit unit) {
224 _tm.enterCompilationUnit(unit); 189 _tm.enterCompilationUnit(unit);
225 _wrappers = _topWrappers;
226 } 190 }
227 void exitCompilationUnit(CompilationUnit unit) { 191 void exitCompilationUnit(CompilationUnit unit) {
228 for (Identifier i in _wrappers.keys) {
229 FunctionDeclaration f = _buildCoercion(i, _wrappers[i], true);
230 unit.declarations.add(f);
231 }
232 _wrappers.clear();
233 _wrappers = _topWrappers;
234 _tm.exitCompilationUnit(unit); 192 _tm.exitCompilationUnit(unit);
235 } 193 }
236 194
237 // Call on entry to and exit from a class in order to properly
238 // discharge the accumulated wrappers.
239 void enterClass() {
240 _wrappers = _classWrappers;
241 }
242 void exitClass(ClassDeclaration cl) {
243 for (Identifier i in _wrappers.keys) {
244 ClassMember f = _buildCoercion(i, _wrappers[i], false);
245 cl.members.add(f);
246 }
247 _wrappers.clear();
248 _wrappers = _topWrappers;
249 }
250
251 // The main entry point. Coerce e using c, returning a new expression, 195 // The main entry point. Coerce e using c, returning a new expression,
252 // possibly recording additional coercions functions and typedefs to 196 // possibly recording additional coercions functions and typedefs to
253 // be discharged at a higher level. 197 // be discharged at a higher level.
254 Expression coerceExpression(Expression e, Coercion c) { 198 Expression coerceExpression(Expression e, Coercion c) {
255 assert(c != null); 199 assert(c != null);
256 assert(c is! CoercionError); 200 assert(c is! CoercionError);
257 if (e is NamedExpression) { 201 if (e is NamedExpression) {
258 Expression inner = coerceExpression(e.expression, c); 202 Expression inner = coerceExpression(e.expression, c);
259 return new NamedExpression(e.name, inner); 203 return new NamedExpression(e.name, inner);
260 } 204 }
261 if (c is Cast) return _castExpression(e, c); 205 if (c is Cast) return _castExpression(e, c);
262 if (c is Wrapper) return _wrapExpression(e, c);
263 assert(c is Identity); 206 assert(c is Identity);
264 return e; 207 return e;
265 } 208 }
266 209
267 ///////////////// Private ////////////////////////////////// 210 ///////////////// Private //////////////////////////////////
268 211
269 Expression _wrapExpression(Expression e, Wrapper w) {
270 var q = _addWrapper(w);
271 var app = AstBuilder.application(q, <Expression>[e]);
272 app.staticType = w.toType;
273 return app;
274 }
275
276 Expression _castExpression(Expression e, Cast c) { 212 Expression _castExpression(Expression e, Cast c) {
277 var ttName = _tm.typeNameFromDartType(c.toType); 213 var ttName = _tm.typeNameFromDartType(c.toType);
278 var cast = AstBuilder.asExpression(e, ttName); 214 var cast = AstBuilder.asExpression(e, ttName);
279 cast.staticType = c.toType; 215 cast.staticType = c.toType;
280 return cast; 216 return cast;
281 } 217 }
282
283 Expression _addWrapper(Wrapper w) {
284 if (_hoistWrappers) {
285 var q = _vm.freshIdentifier("q");
286 _wrappers[q] = w;
287 return q;
288 } else {
289 return _buildCoercionExpression(w);
290 }
291 }
292
293 // Choose a canonical name for the ith coercion parameter
294 // with name "name".
295 Identifier _coercionParameter(String name, int index) {
296 String s = name + index.toString();
297 return AstBuilder.identifierFromString(s);
298 }
299
300 List<FormalParameter> _wrapperFormalParameters(Wrapper wrapper) {
301 var namedParameters = wrapper.namedParameters;
302 var normalParameters = wrapper.normalParameters;
303 var optionalParameters = wrapper.optionalParameters;
304 var params = new List<FormalParameter>();
305 for (int i = 0; i < normalParameters.length; i++) {
306 Identifier x = _coercionParameter("x", i);
307 // We use the toType to avoid changing the reified type
308 FormalParameter fp = _tm.typedFormal(x, normalParameters[i].toType);
309 params.add(AstBuilder.requiredFormal(fp));
310 }
311 for (int i = 0; i < optionalParameters.length; i++) {
312 Identifier y = _coercionParameter("y", i);
313 // We use the toType to avoid changing the reified type
314 FormalParameter fp = _tm.typedFormal(y, optionalParameters[i].toType);
315 params.add(AstBuilder.optionalFormal(fp));
316 }
317 for (String k in namedParameters.keys) {
318 // TODO(leafp): These could collide with the generated names.
319 Identifier z = AstBuilder.identifierFromString(k);
320 // We use the toType to avoid changing the reified type
321 FormalParameter fp = _tm.typedFormal(z, namedParameters[k].toType);
322 params.add(AstBuilder.namedFormal(fp));
323 }
324 return params;
325 }
326
327 List<Expression> _wrapperCoercedArguments(Wrapper wrapper) {
328 var namedParameters = wrapper.namedParameters;
329 var normalParameters = wrapper.normalParameters;
330 var optionalParameters = wrapper.optionalParameters;
331 var args = new List<Expression>();
332 for (int i = 0; i < normalParameters.length; i++) {
333 Identifier x = _coercionParameter("x", i);
334 Expression e = coerceExpression(x, normalParameters[i]);
335 args.add(e);
336 }
337 for (int i = 0; i < optionalParameters.length; i++) {
338 Identifier y = _coercionParameter("y", i);
339 Expression e = coerceExpression(y, optionalParameters[i]);
340 args.add(e);
341 }
342 for (String k in namedParameters.keys) {
343 // TODO(leafp): These could collide with the generated names.
344 Identifier z = AstBuilder.identifierFromString(k);
345 Expression e = coerceExpression(z, namedParameters[k]);
346 args.add(AstBuilder.namedParameter(k, e));
347 }
348 return args;
349 }
350
351 // Given an identifier c, a value f and a coercion q : T0 -> T1 => S0 -> S1
352 // wrap f using q and bind it to variable c
353 // T1 c(T0 x) => (f(x as T0) as S1)
354 // Note that we use the "fromType" to decorate the wrapper
355 // rather than the "toType" to avoid changing the reified type
356 // TODO(leafp): If we wrap non-function literals, we can still
357 // end up changing the runtime reified type, since we build a function
358 // literal based on the static type.
359 FunctionDeclarationStatement _wrapperMkInner(
360 Identifier c, Expression f, Wrapper wrapper) {
361 List<FormalParameter> params = _wrapperFormalParameters(wrapper);
362 List<Expression> args = _wrapperCoercedArguments(wrapper);
363 Expression app = AstBuilder.application(f, args);
364 Expression body = coerceExpression(app, wrapper.ret);
365 FunctionExpression ce = AstBuilder.expressionFunction(params, body, true);
366 TypeName rt =
367 _tm.typeNameFromDartType((wrapper.fromType as FunctionType).returnType);
368 Statement cDec = AstBuilder.functionDeclarationStatement(rt, c, ce);
369 return cDec;
370 }
371
372 Tuple2<List<FormalParameter>, List<Statement>> _buildCoercionBody(
373 Wrapper wrapper) {
374 var f = AstBuilder.identifierFromString("f");
375 var c = AstBuilder.identifierFromString("c");
376 var cDec = _wrapperMkInner(c, f, wrapper);
377 var comp = AstBuilder.binaryExpression(f, "==", AstBuilder.nullLiteral());
378 var n = AstBuilder.nullLiteral();
379 var cond = AstBuilder.conditionalExpression(comp, n, c);
380 var stmts = <Statement>[cDec, AstBuilder.returnExpression(cond)];
381 var fp = _tm.typedFormal(f, wrapper.fromType);
382 var params = <FormalParameter>[fp];
383 return new Tuple2<List<FormalParameter>, List<Statement>>(params, stmts);
384 }
385
386 Expression _buildCoercionExpression(Wrapper wrapper) {
387 var tup = _buildCoercionBody(wrapper);
388 return AstBuilder.blockFunction(tup.e0, tup.e1);
389 }
390
391 // Given a name g and coercion q : T0 -> T1 => S0 -> S1
392 // Bind g to a function or static method which maps
393 // T0 -> T1 functions to S0 -> S1 functions.
394 // T0 -> T1 g(S1 f(S0)) {
395 // T1 c(T0 x) => (f(x as T0) as S1);
396 // return (f == null) ? null : c;
397 // }
398 Declaration _buildCoercion(Identifier q, Wrapper wrapper, bool top) {
399 var tup = _buildCoercionBody(wrapper);
400 var params = tup.e0;
401 var stmts = tup.e1;
402 TypeName rt = _tm.typeNameFromDartType(wrapper.toType);
403 if (top) {
404 return AstBuilder.blockFunctionDeclaration(rt, q, params, stmts);
405 } else {
406 return AstBuilder.blockMethodDeclaration(rt, q, params, stmts);
407 }
408 }
409 } 218 }
410 219
411 // A class for managing the interaction between the DartType hierarchy 220 // A class for managing the interaction between the DartType hierarchy
412 // and the AST type representation. It provides utilities to translate 221 // and the AST type representation. It provides utilities to translate
413 // a DartType to AST. In order to do so, it maintains a map of typedefs 222 // a DartType to AST. In order to do so, it maintains a map of typedefs
414 // naming otherwise un-named types. These must be discharged at the top 223 // naming otherwise un-named types. These must be discharged at the top
415 // level of the compilation unit in order to produce well-formed dart code. 224 // level of the compilation unit in order to produce well-formed dart code.
416 // Note that in order to hoist the typedefs out of parameterized classes 225 // Note that in order to hoist the typedefs out of parameterized classes
417 // we must close over any type variables. 226 // we must close over any type variables.
418 class TypeManager { 227 class TypeManager {
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after
681 var t = _mkNewTypeName(dType, id, args); 490 var t = _mkNewTypeName(dType, id, args);
682 return t; 491 return t;
683 } 492 }
684 493
685 TypeName _mkNewTypeName(DartType type, Identifier id, List<TypeName> args) { 494 TypeName _mkNewTypeName(DartType type, Identifier id, List<TypeName> args) {
686 var t = AstBuilder.typeName(id, args); 495 var t = AstBuilder.typeName(id, args);
687 t.type = type; 496 t.type = type;
688 return t; 497 return t;
689 } 498 }
690 } 499 }
OLDNEW
« no previous file with comments | « lib/src/checker/rules.dart ('k') | lib/src/info.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698