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

Side by Side Diff: lib/src/compiler/code_generator.dart

Issue 2164763005: Library custom formatters (Closed) Base URL: https://github.com/dart-lang/dev_compiler.git@master
Patch Set: Revert test files Created 4 years, 5 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_sdk.js ('k') | tool/input_sdk/private/ddc_runtime/classes.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 'dart:collection' show HashMap, HashSet; 5 import 'dart:collection' show HashMap, HashSet;
6 import 'dart:math' show min, max; 6 import 'dart:math' show min, max;
7 7
8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; 8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator;
9 import 'package:analyzer/dart/ast/ast.dart'; 9 import 'package:analyzer/dart/ast/ast.dart';
10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; 10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType;
(...skipping 527 matching lines...) Expand 10 before | Expand all | Expand 10 after
538 emitExport(export); 538 emitExport(export);
539 } 539 }
540 } 540 }
541 541
542 @override 542 @override
543 visitAsExpression(AsExpression node) { 543 visitAsExpression(AsExpression node) {
544 Expression fromExpr = node.expression; 544 Expression fromExpr = node.expression;
545 var from = getStaticType(fromExpr); 545 var from = getStaticType(fromExpr);
546 var to = node.type.type; 546 var to = node.type.type;
547 547
548 JS.Expression jsFrom = _visit(fromExpr); 548 var jsFrom = _visit(fromExpr);
549 if (_inWhitelistCode(node)) return jsFrom;
550 549
551 // Skip the cast if it's not needed. 550 // Skip the cast if it's not needed.
552 if (rules.isSubtypeOf(from, to)) return jsFrom; 551 if (rules.isSubtypeOf(from, to)) return jsFrom;
553 552
554 // All Dart number types map to a JS double. 553 // All Dart number types map to a JS double.
555 if (_isNumberInJS(from) && _isNumberInJS(to)) { 554 if (_isNumberInJS(from) && _isNumberInJS(to)) {
556 // Make sure to check when converting to int. 555 // Make sure to check when converting to int.
557 if (from != types.intType && to == types.intType) { 556 if (from != types.intType && to == types.intType) {
558 // TODO(jmesserly): fuse this with notNull check. 557 // TODO(jmesserly): fuse this with notNull check.
559 return js.call('dart.asInt(#)', jsFrom); 558 return js.call('dart.asInt(#)', jsFrom);
560 } 559 }
561 560
562 // A no-op in JavaScript. 561 // A no-op in JavaScript.
563 return jsFrom; 562 return jsFrom;
564 } 563 }
565 564
566 var type = _emitType(to, 565 var type = _emitType(to,
567 nameType: options.nameTypeTests || options.hoistTypeTests, 566 nameType: options.nameTypeTests || options.hoistTypeTests,
568 hoistType: options.hoistTypeTests); 567 hoistType: options.hoistTypeTests);
568 if (_inWhitelistCode(node)) return jsFrom;
569 if (isReifiedCoercion(node)) { 569 if (isReifiedCoercion(node)) {
570 return js.call('#._check(#)', [type, jsFrom]); 570 return js.call('#._check(#)', [type, jsFrom]);
571 } else { 571 } else {
572 return js.call('#.as(#)', [type, jsFrom]); 572 return js.call('#.as(#)', [type, jsFrom]);
573 } 573 }
574 } 574 }
575 575
576 bool isReifiedCoercion(AstNode node) { 576 bool isReifiedCoercion(AstNode node) {
577 // TODO(sra): Find a better way to recognize reified coercion, since we 577 // TODO(sra): Find a better way to recognize reified coercion, since we
578 // can't set the isSynthetic attribute. 578 // can't set the isSynthetic attribute.
(...skipping 725 matching lines...) Expand 10 before | Expand all | Expand 10 after
1304 } 1304 }
1305 if (m.isStatic) continue; 1305 if (m.isStatic) continue;
1306 for (VariableDeclaration field in m.fields.variables) { 1306 for (VariableDeclaration field in m.fields.variables) {
1307 if (virtualFields.containsKey(field.element)) { 1307 if (virtualFields.containsKey(field.element)) {
1308 jsMethods.addAll(_emitVirtualFieldAccessor(field, virtualFields)); 1308 jsMethods.addAll(_emitVirtualFieldAccessor(field, virtualFields));
1309 } 1309 }
1310 } 1310 }
1311 } 1311 }
1312 } 1312 }
1313 1313
1314 jsMethods.addAll(_implementMockInterfaces(type));
1315
1316 // If the type doesn't have an `iterator`, but claims to implement Iterable, 1314 // If the type doesn't have an `iterator`, but claims to implement Iterable,
1317 // we inject the adaptor method here, as it's less code size to put the 1315 // we inject the adaptor method here, as it's less code size to put the
1318 // helper on a parent class. This pattern is common in the core libraries 1316 // helper on a parent class. This pattern is common in the core libraries
1319 // (e.g. IterableMixin<E> and IterableBase<E>). 1317 // (e.g. IterableMixin<E> and IterableBase<E>).
1320 // 1318 //
1321 // (We could do this same optimization for any interface with an `iterator` 1319 // (We could do this same optimization for any interface with an `iterator`
1322 // method, but that's more expensive to check for, so it doesn't seem worth 1320 // method, but that's more expensive to check for, so it doesn't seem worth
1323 // it. The above case for an explicit `iterator` method will catch those.) 1321 // it. The above case for an explicit `iterator` method will catch those.)
1324 if (!hasJsPeer && !hasIterator && _implementsIterable(type)) { 1322 if (!hasJsPeer && !hasIterator && _implementsIterable(type)) {
1325 jsMethods.add(_emitIterable(type)); 1323 jsMethods.add(_emitIterable(type));
1326 } 1324 }
1327 1325
1328 // Add all of the super helper methods 1326 // Add all of the super helper methods
1329 jsMethods.addAll(_superHelpers); 1327 jsMethods.addAll(_superHelpers);
1330 _superHelpers.clear(); 1328 _superHelpers.clear();
1331 1329
1332 return jsMethods.where((m) => m != null).toList(growable: false); 1330 return jsMethods.where((m) => m != null).toList(growable: false);
1333 } 1331 }
1334 1332
1335 Iterable<ExecutableElement> _collectMockMethods(InterfaceType type) {
1336 var element = type.element;
1337 if (!_hasNoSuchMethod(element)) {
1338 return [];
1339 }
1340
1341 // Collect all unimplemented members.
1342 //
1343 // Initially, we track abstract and concrete members separately, then
1344 // remove concrete from the abstract set. This is done because abstract
1345 // members are allowed to "override" concrete ones in Dart.
1346 // (In that case, it will still be treated as a concrete member and can be
1347 // called at run time.)
1348 var abstractMembers = new Map<String, ExecutableElement>();
1349 var concreteMembers = new HashSet<String>();
1350
1351 void visit(InterfaceType type, bool isAbstract) {
1352 if (type == null) return;
1353 visit(type.superclass, isAbstract);
1354 for (var m in type.mixins) visit(m, isAbstract);
1355 for (var i in type.interfaces) visit(i, true);
1356
1357 var members = <ExecutableElement>[]
1358 ..addAll(type.methods)
1359 ..addAll(type.accessors);
1360 for (var m in members) {
1361 if (isAbstract || m.isAbstract) {
1362 // Inconsistent signatures are disallowed, even with nSM, so we don't
1363 // need to worry too much about which abstract member we save.
1364 abstractMembers[m.name] = m;
1365 } else {
1366 concreteMembers.add(m.name);
1367 }
1368 }
1369 }
1370
1371 visit(type, false);
1372
1373 concreteMembers.forEach(abstractMembers.remove);
1374 return abstractMembers.values;
1375 }
1376
1377 Iterable<JS.Method> _implementMockInterfaces(InterfaceType type) {
1378 // TODO(jmesserly): every type with nSM will generate new stubs for all
1379 // abstract members. For example:
1380 //
1381 // class C { m(); noSuchMethod(...) { ... } }
1382 // class D extends C { m(); noSuchMethod(...) { ... } }
1383 //
1384 // We'll generate D.m even though it is not necessary.
1385 //
1386 // Doing better is a bit tricky, as our current codegen strategy for the
1387 // mock methods encodes information about the number of arguments (and type
1388 // arguments) that D expects.
1389 return _collectMockMethods(type).map(_implementMockMethod);
1390 }
1391
1392 /// Given a class C that implements method M from interface I, but does not
1393 /// declare M, this will generate an implementation that forwards to
1394 /// noSuchMethod.
1395 ///
1396 /// For example:
1397 ///
1398 /// class Cat {
1399 /// bool eatFood(String food) => true;
1400 /// }
1401 /// class MockCat implements Cat {
1402 /// noSuchMethod(Invocation invocation) => 3;
1403 /// }
1404 ///
1405 /// It will generate an `eatFood` that looks like:
1406 ///
1407 /// eatFood(food) {
1408 /// return core.bool.as(this.noSuchMethod(
1409 /// new dart.InvocationImpl('eatFood', [food])));
1410 /// }
1411 JS.Method _implementMockMethod(ExecutableElement method) {
1412 var positionalArgs = <JS.Identifier>[]
1413 ..addAll(
1414 method.type.normalParameterNames.map((a) => new JS.Identifier(a)))
1415 ..addAll(
1416 method.type.optionalParameterNames.map((a) => new JS.Identifier(a)));
1417
1418 var fnArgs = positionalArgs.toList();
1419
1420 var invocationProps = <JS.Property>[];
1421 addProperty(String name, JS.Expression value) {
1422 invocationProps.add(new JS.Property(js.string(name), value));
1423 }
1424
1425 if (method.type.namedParameterTypes.isNotEmpty) {
1426 fnArgs.add(namedArgumentTemp);
1427 addProperty('namedArguments', namedArgumentTemp);
1428 }
1429
1430 if (method is MethodElement) {
1431 addProperty('isMethod', js.boolean(true));
1432 } else {
1433 var property = method as PropertyAccessorElement;
1434 if (property.isGetter) {
1435 addProperty('isGetter', js.boolean(true));
1436 } else if (property.isSetter) {
1437 addProperty('isSetter', js.boolean(true));
1438 }
1439 }
1440
1441 var fnBody =
1442 js.call('this.noSuchMethod(new dart.InvocationImpl(#, #, #))', [
1443 _elementMemberName(method),
1444 new JS.ArrayInitializer(positionalArgs),
1445 new JS.ObjectInitializer(invocationProps)
1446 ]);
1447
1448 if (!method.returnType.isDynamic) {
1449 fnBody = js.call('#._check(#)', [_emitType(method.returnType), fnBody]);
1450 }
1451
1452 var fn = new JS.Fun(fnArgs, js.statement('{ return #; }', [fnBody]),
1453 typeParams: _emitTypeFormals(method.type.typeFormals));
1454
1455 // TODO(jmesserly): generic type arguments will get dropped.
1456 // We have a similar issue with `dgsend` helpers.
1457 return new JS.Method(
1458 _elementMemberName(method,
1459 useExtension:
1460 _extensionTypes.isNativeClass(method.enclosingElement)),
1461 _makeGenericFunction(fn),
1462 isGetter: method is PropertyAccessorElement && method.isGetter,
1463 isSetter: method is PropertyAccessorElement && method.isSetter,
1464 isStatic: false);
1465 }
1466
1467 /// Return `true` if the given [classElement] has a noSuchMethod() method
1468 /// distinct from the one declared in class Object, as per the Dart Language
1469 /// Specification (section 10.4).
1470 // TODO(jmesserly): this was taken from error_verifier.dart
1471 bool _hasNoSuchMethod(ClassElement classElement) {
1472 // TODO(jmesserly): this is slow in Analyzer. It's a linear scan through all
1473 // methods, up through the class hierarchy.
1474 MethodElement method = classElement.lookUpMethod(
1475 FunctionElement.NO_SUCH_METHOD_METHOD_NAME, classElement.library);
1476 var definingClass = method?.enclosingElement;
1477 return definingClass != null && !definingClass.type.isObject;
1478 }
1479
1480 /// This is called whenever a derived class needs to introduce a new field, 1333 /// This is called whenever a derived class needs to introduce a new field,
1481 /// shadowing a field or getter/setter pair on its parent. 1334 /// shadowing a field or getter/setter pair on its parent.
1482 /// 1335 ///
1483 /// This is important because otherwise, trying to read or write the field 1336 /// This is important because otherwise, trying to read or write the field
1484 /// would end up calling the getter or setter, and one of those might not even 1337 /// would end up calling the getter or setter, and one of those might not even
1485 /// exist, resulting in a runtime error. Even if they did exist, that's the 1338 /// exist, resulting in a runtime error. Even if they did exist, that's the
1486 /// wrong behavior if a new field was declared. 1339 /// wrong behavior if a new field was declared.
1487 List<JS.Method> _emitVirtualFieldAccessor(VariableDeclaration field, 1340 List<JS.Method> _emitVirtualFieldAccessor(VariableDeclaration field,
1488 Map<FieldElement, JS.TemporaryId> virtualFields) { 1341 Map<FieldElement, JS.TemporaryId> virtualFields) {
1489 var virtualField = virtualFields[field.element]; 1342 var virtualField = virtualFields[field.element];
(...skipping 3872 matching lines...) Expand 10 before | Expand all | Expand 10 after
5362 } 5215 }
5363 5216
5364 bool isLibraryPrefix(Expression node) => 5217 bool isLibraryPrefix(Expression node) =>
5365 node is SimpleIdentifier && node.staticElement is PrefixElement; 5218 node is SimpleIdentifier && node.staticElement is PrefixElement;
5366 5219
5367 LibraryElement _getLibrary(AnalysisContext c, String uri) => 5220 LibraryElement _getLibrary(AnalysisContext c, String uri) =>
5368 c.computeLibraryElement(c.sourceFactory.forUri(uri)); 5221 c.computeLibraryElement(c.sourceFactory.forUri(uri));
5369 5222
5370 bool _isDartRuntime(LibraryElement l) => 5223 bool _isDartRuntime(LibraryElement l) =>
5371 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; 5224 l.isInSdk && l.source.uri.toString() == 'dart:_runtime';
OLDNEW
« no previous file with comments | « lib/runtime/dart_sdk.js ('k') | tool/input_sdk/private/ddc_runtime/classes.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698