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

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

Issue 2623053004: Fix noSuchMethod handling of methods that are also extension methods. Fix noSuchMethod handling of … (Closed)
Patch Set: Fix noSuchMethod handling of methods that are also extension methods. Fix noSuchMethod handling of … Created 3 years, 11 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
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 2
3 // for details. All rights reserved. Use of this source code is governed by a 3 // for details. All rights reserved. Use of this source code is governed by a
4 // BSD-style license that can be found in the LICENSE file. 4 // BSD-style license that can be found in the LICENSE file.
5 5
6 import 'dart:collection' show HashMap, HashSet; 6 import 'dart:collection' show HashMap, HashSet;
7 import 'dart:math' show min, max; 7 import 'dart:math' show min, max;
8 8
9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator;
10 import 'package:analyzer/dart/ast/ast.dart'; 10 import 'package:analyzer/dart/ast/ast.dart';
(...skipping 1146 matching lines...) Expand 10 before | Expand all | Expand 10 after
1157 var nameProperties = new List<JS.Property>(fields.length); 1157 var nameProperties = new List<JS.Property>(fields.length);
1158 for (var i = 0; i < fields.length; ++i) { 1158 for (var i = 0; i < fields.length; ++i) {
1159 nameProperties[i] = new JS.Property( 1159 nameProperties[i] = new JS.Property(
1160 js.number(i), js.string('${type.name}.${fields[i].name}')); 1160 js.number(i), js.string('${type.name}.${fields[i].name}'));
1161 } 1161 }
1162 var nameMap = new JS.ObjectInitializer(nameProperties, multiline: true); 1162 var nameMap = new JS.ObjectInitializer(nameProperties, multiline: true);
1163 var toStringF = new JS.Method(js.string('toString'), 1163 var toStringF = new JS.Method(js.string('toString'),
1164 js.call('function() { return #[this.index]; }', nameMap) as JS.Fun); 1164 js.call('function() { return #[this.index]; }', nameMap) as JS.Fun);
1165 1165
1166 // Create enum class 1166 // Create enum class
1167 JS.Property build(String name, List<JS.Property> elements) {
1168 var o =
1169 new JS.ObjectInitializer(elements, multiline: elements.length > 1);
1170 // TODO(vsm): Remove
Jennifer Messerly 2017/01/24 03:51:03 was this code copied from somewhere else?
Jacob 2017/01/24 19:12:32 That is scary. I had moved that to a shared helper
1171 var e = js.call('() => #', o);
1172 return new JS.Property(_propertyName(name), e);
1173 }
1174
1167 var classExpr = new JS.ClassExpression(new JS.Identifier(type.name), 1175 var classExpr = new JS.ClassExpression(new JS.Identifier(type.name),
1168 _emitClassHeritage(element), [constructor, toStringF]); 1176 _emitClassHeritage(element), [constructor, toStringF]);
1169 var id = _emitTopLevelName(element); 1177 var id = _emitTopLevelName(element);
1178
1179 // Emit metadata for synthetic enum index member.
1180 // TODO(jacobr): make field readonly when that is supported.
1181 var tInstanceFields = <JS.Property>[new JS.Property(_emitMemberName('index') , _emitAnnotatedType(intClass.type, null))];
Jennifer Messerly 2017/01/24 03:51:03 format?
Jacob 2017/01/24 19:12:32 fixed.
1182 var sigFields = <JS.Property>[build('fields', tInstanceFields)];
1183 var sig = new JS.ObjectInitializer(sigFields);
1184
1170 var result = [ 1185 var result = [
1171 js.statement('# = #', [id, classExpr]) 1186 js.statement('# = #', [id, classExpr]),
1187 _callHelperStatement('setSignature(#, #);', [id, sig])
1172 ]; 1188 ];
1173 1189
1174 // defineEnumValues internally depends on dart.constList which uses 1190 // defineEnumValues internally depends on dart.constList which uses
1175 // _interceptors.JSArray. 1191 // _interceptors.JSArray.
1176 _declareBeforeUse(_jsArray); 1192 _declareBeforeUse(_jsArray);
1177 1193
1178 // Create static fields for each enum value, and the "values" getter 1194 // Create static fields for each enum value, and the "values" getter
1179 result.add(_callHelperStatement('defineEnumValues(#, #);', [ 1195 result.add(_callHelperStatement('defineEnumValues(#, #);', [
1180 id, 1196 id,
1181 new JS.ArrayInitializer(fields.map((f) => _propertyName(f.name)).toList(), 1197 new JS.ArrayInitializer(fields.map((f) => _propertyName(f.name)).toList(),
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after
1499 } else if (property.isSetter) { 1515 } else if (property.isSetter) {
1500 addProperty('isSetter', js.boolean(true)); 1516 addProperty('isSetter', js.boolean(true));
1501 1517
1502 fnArgs.add(args); 1518 fnArgs.add(args);
1503 positionalArgs = new JS.ArrayInitializer([args]); 1519 positionalArgs = new JS.ArrayInitializer([args]);
1504 } 1520 }
1505 } 1521 }
1506 1522
1507 var fnBody = js.call('this.noSuchMethod(new #.InvocationImpl(#, #, #))', [ 1523 var fnBody = js.call('this.noSuchMethod(new #.InvocationImpl(#, #, #))', [
1508 _runtimeModule, 1524 _runtimeModule,
1509 _declareMemberName(method), 1525 _declareMemberName(method, useDisplayName: true),
1510 positionalArgs, 1526 positionalArgs,
1511 new JS.ObjectInitializer(invocationProps) 1527 new JS.ObjectInitializer(invocationProps)
1512 ]); 1528 ]);
1513 1529
1514 if (!method.returnType.isDynamic) { 1530 if (!method.returnType.isDynamic) {
1515 fnBody = js.call('#._check(#)', [_emitType(method.returnType), fnBody]); 1531 fnBody = js.call('#._check(#)', [_emitType(method.returnType), fnBody]);
1516 } 1532 }
1517 1533
1518 var fn = new JS.Fun(fnArgs, js.statement('{ return #; }', [fnBody]), 1534 var fn = new JS.Fun(fnArgs, js.statement('{ return #; }', [fnBody]),
1519 typeParams: _emitTypeFormals(method.type.typeFormals)); 1535 typeParams: _emitTypeFormals(method.type.typeFormals));
(...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after
1942 } 1958 }
1943 } 1959 }
1944 if (dartxNames.isNotEmpty) { 1960 if (dartxNames.isNotEmpty) {
1945 body.add(_callHelperStatement('defineExtensionNames(#)', 1961 body.add(_callHelperStatement('defineExtensionNames(#)',
1946 [new JS.ArrayInitializer(dartxNames, multiline: true)])); 1962 [new JS.ArrayInitializer(dartxNames, multiline: true)]));
1947 } 1963 }
1948 } 1964 }
1949 } 1965 }
1950 1966
1951 List<ExecutableElement> _extensionsToImplement(ClassElement element) { 1967 List<ExecutableElement> _extensionsToImplement(ClassElement element) {
1952 var members = <ExecutableElement>[]; 1968 if (_extensionTypes.isNativeClass(element)) return [];
1953 if (_extensionTypes.isNativeClass(element)) return members;
1954 1969
1955 // Collect all extension types we implement. 1970 // Collect all extension types we implement.
1956 var type = element.type; 1971 var type = element.type;
1957 var types = _extensionTypes.collectNativeInterfaces(element); 1972 var types = _extensionTypes.collectNativeInterfaces(element);
1958 if (types.isEmpty) return members; 1973 if (types.isEmpty) return [];
1959 1974
1975 var members = new Set<ExecutableElement>();
1960 // Collect all possible extension method names. 1976 // Collect all possible extension method names.
1961 var extensionMembers = new HashSet<String>(); 1977 var extensionMembers = new HashSet<String>();
1962 for (var t in types) { 1978 for (var t in types) {
1963 for (var m in [t.methods, t.accessors].expand((e) => e)) { 1979 for (var m in [t.methods, t.accessors].expand((e) => e)) {
1964 if (!m.isStatic && m.isPublic) extensionMembers.add(m.name); 1980 if (!m.isStatic && m.isPublic) extensionMembers.add(m.name);
1965 } 1981 }
1966 } 1982 }
1967 1983
1968 // Collect all of extension methods this type implements. 1984 // Collect all of extension methods this type implements.
1969 for (var m in [type.methods, type.accessors].expand((e) => e)) { 1985 for (var m in [type.methods, type.accessors].expand((e) => e)) {
1970 if (!m.isStatic && !m.isAbstract && extensionMembers.contains(m.name)) { 1986 if (!m.isStatic && !m.isAbstract && extensionMembers.contains(m.name)) {
1971 members.add(m); 1987 members.add(m);
1972 } 1988 }
1973 } 1989 }
1974 return members; 1990 members.addAll(_collectMockMethods(type)
1991 .where((m) => extensionMembers.contains(m.name)));
1992 return members.toList();
1975 } 1993 }
1976 1994
1977 /// Generates the implicit default constructor for class C of the form 1995 /// Generates the implicit default constructor for class C of the form
1978 /// `C() : super() {}`. 1996 /// `C() : super() {}`.
1979 JS.Method _emitImplicitConstructor( 1997 JS.Method _emitImplicitConstructor(
1980 ClassDeclaration node, 1998 ClassDeclaration node,
1981 List<FieldDeclaration> fields, 1999 List<FieldDeclaration> fields,
1982 Map<FieldElement, JS.TemporaryId> virtualFields) { 2000 Map<FieldElement, JS.TemporaryId> virtualFields) {
1983 // If we don't have a method body, skip this. 2001 // If we don't have a method body, skip this.
1984 var superCall = _superConstructorCall(node.element); 2002 var superCall = _superConstructorCall(node.element);
(...skipping 3488 matching lines...) Expand 10 before | Expand all | Expand 10 after
5473 } 5491 }
5474 JS.Expression result = _visit(node); 5492 JS.Expression result = _visit(node);
5475 if (isNullable(node)) result = _callHelper('test(#)', result); 5493 if (isNullable(node)) result = _callHelper('test(#)', result);
5476 return result; 5494 return result;
5477 } 5495 }
5478 5496
5479 /// Like [_emitMemberName], but for declaration sites. 5497 /// Like [_emitMemberName], but for declaration sites.
5480 /// 5498 ///
5481 /// Unlike call sites, we always have an element available, so we can use it 5499 /// Unlike call sites, we always have an element available, so we can use it
5482 /// directly rather than computing the relevant options for [_emitMemberName]. 5500 /// directly rather than computing the relevant options for [_emitMemberName].
5483 JS.Expression _declareMemberName(ExecutableElement e, {bool useExtension}) { 5501 JS.Expression _declareMemberName(ExecutableElement e,
5484 String name; 5502 {bool useExtension, useDisplayName = false}) {
5485 if (e is PropertyAccessorElement) { 5503 var name = (e is PropertyAccessorElement) ? e.variable.name : e.name;
5486 name = e.variable.name;
5487 } else {
5488 name = e.name;
5489 }
5490 return _emitMemberName(name, 5504 return _emitMemberName(name,
5491 isStatic: e.isStatic, 5505 isStatic: e.isStatic,
5492 useExtension: 5506 useExtension:
5493 useExtension ?? _extensionTypes.isNativeClass(e.enclosingElement)); 5507 useExtension ?? _extensionTypes.isNativeClass(e.enclosingElement),
5508 useDisplayName: useDisplayName);
5494 } 5509 }
5495 5510
5496 /// This handles member renaming for private names and operators. 5511 /// This handles member renaming for private names and operators.
5497 /// 5512 ///
5498 /// Private names are generated using ES6 symbols: 5513 /// Private names are generated using ES6 symbols:
5499 /// 5514 ///
5500 /// // At the top of the module: 5515 /// // At the top of the module:
5501 /// let _x = Symbol('_x'); 5516 /// let _x = Symbol('_x');
5502 /// let _y = Symbol('_y'); 5517 /// let _y = Symbol('_y');
5503 /// ... 5518 /// ...
(...skipping 26 matching lines...) Expand all
5530 /// 5545 ///
5531 /// Unary minus looks like: `x._negate()`. 5546 /// Unary minus looks like: `x._negate()`.
5532 /// 5547 ///
5533 /// Equality is a bit special, it is generated via the Dart `equals` runtime 5548 /// Equality is a bit special, it is generated via the Dart `equals` runtime
5534 /// helper, that checks for null. The user defined method is called '=='. 5549 /// helper, that checks for null. The user defined method is called '=='.
5535 /// 5550 ///
5536 JS.Expression _emitMemberName(String name, 5551 JS.Expression _emitMemberName(String name,
5537 {DartType type, 5552 {DartType type,
5538 bool isStatic: false, 5553 bool isStatic: false,
5539 bool useExtension, 5554 bool useExtension,
5555 bool useDisplayName: false,
5540 Element element}) { 5556 Element element}) {
5541 // Static members skip the rename steps and may require JS interop renames. 5557 // Static members skip the rename steps and may require JS interop renames.
5542 if (isStatic) { 5558 if (isStatic) {
5543 return _emitJSInteropStaticMemberName(element) ?? _propertyName(name); 5559 return _emitJSInteropStaticMemberName(element) ?? _propertyName(name);
5544 } 5560 }
5545 5561
5546 if (name.startsWith('_')) { 5562 if (name.startsWith('_')) {
5547 return _emitPrivateNameSymbol(currentLibrary, name); 5563 return _emitPrivateNameSymbol(currentLibrary, name);
5548 } 5564 }
5549 5565
5550 // When generating synthetic names, we use _ as the prefix, since Dart names 5566 // When generating synthetic names, we use _ as the prefix, since Dart names
5551 // won't have this (eliminated above), nor will static names reach here. 5567 // won't have this (eliminated above), nor will static names reach here.
5552 switch (name) { 5568 if (!useDisplayName) {
5553 case '[]': 5569 switch (name) {
5554 name = '_get'; 5570 case '[]':
5555 break; 5571 name = '_get';
5556 case '[]=': 5572 break;
5557 name = '_set'; 5573 case '[]=':
5558 break; 5574 name = '_set';
5559 case 'unary-': 5575 break;
5560 name = '_negate'; 5576 case 'unary-':
5561 break; 5577 name = '_negate';
5562 case 'constructor': 5578 break;
5563 case 'prototype': 5579 case 'constructor':
5564 name = '_$name'; 5580 case 'prototype':
5565 break; 5581 name = '_$name';
5582 break;
5583 }
5566 } 5584 }
5567 5585
5568 var result = _propertyName(name); 5586 var result = _propertyName(name);
5569 5587
5570 if (useExtension == null) { 5588 if (useExtension == null) {
5571 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. 5589 // Dart "extension" methods. Used for JS Array, Boolean, Number, String.
5572 var baseType = type; 5590 var baseType = type;
5573 while (baseType is TypeParameterType) { 5591 while (baseType is TypeParameterType) {
5574 baseType = (baseType.element as TypeParameterElement).bound; 5592 baseType = (baseType.element as TypeParameterElement).bound;
5575 } 5593 }
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after
5831 if (targetIdentifier.staticElement is! PrefixElement) return false; 5849 if (targetIdentifier.staticElement is! PrefixElement) return false;
5832 var prefix = targetIdentifier.staticElement as PrefixElement; 5850 var prefix = targetIdentifier.staticElement as PrefixElement;
5833 5851
5834 // The library the prefix is referring to must come from a deferred import. 5852 // The library the prefix is referring to must come from a deferred import.
5835 var containingLibrary = resolutionMap 5853 var containingLibrary = resolutionMap
5836 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) 5854 .elementDeclaredByCompilationUnit(target.root as CompilationUnit)
5837 .library; 5855 .library;
5838 var imports = containingLibrary.getImportsWithPrefix(prefix); 5856 var imports = containingLibrary.getImportsWithPrefix(prefix);
5839 return imports.length == 1 && imports[0].isDeferred; 5857 return imports.length == 1 && imports[0].isDeferred;
5840 } 5858 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698