| OLD | NEW |
| 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 1376 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1387 var type = element.type; | 1387 var type = element.type; |
| 1388 var virtualFields = _classProperties.virtualFields; | 1388 var virtualFields = _classProperties.virtualFields; |
| 1389 | 1389 |
| 1390 var jsMethods = <JS.Method>[]; | 1390 var jsMethods = <JS.Method>[]; |
| 1391 bool hasJsPeer = findAnnotation(element, isJsPeerInterface) != null; | 1391 bool hasJsPeer = findAnnotation(element, isJsPeerInterface) != null; |
| 1392 bool hasIterator = false; | 1392 bool hasIterator = false; |
| 1393 | 1393 |
| 1394 if (type.isObject) { | 1394 if (type.isObject) { |
| 1395 // Dart does not use ES6 constructors. | 1395 // Dart does not use ES6 constructors. |
| 1396 // Add an error to catch any invalid usage. | 1396 // Add an error to catch any invalid usage. |
| 1397 jsMethods.add(new JS.Method( | 1397 jsMethods.add( |
| 1398 _propertyName('constructor'), | 1398 new JS.Method(_propertyName('constructor'), js.call(r'''function() { |
| 1399 js.call( | |
| 1400 r'''function() { | |
| 1401 throw Error("use `new " + #.typeName(#.getReifiedType(this)) + | 1399 throw Error("use `new " + #.typeName(#.getReifiedType(this)) + |
| 1402 ".new(...)` to create a Dart object"); | 1400 ".new(...)` to create a Dart object"); |
| 1403 }''', | 1401 }''', [_runtimeModule, _runtimeModule]))); |
| 1404 [_runtimeModule, _runtimeModule]))); | |
| 1405 } | 1402 } |
| 1406 for (var m in node.members) { | 1403 for (var m in node.members) { |
| 1407 if (m is ConstructorDeclaration) { | 1404 if (m is ConstructorDeclaration) { |
| 1408 if (m.factoryKeyword != null && !_externalOrNative(m)) { | 1405 if (m.factoryKeyword != null && !_externalOrNative(m)) { |
| 1409 jsMethods.add(_emitFactoryConstructor(m)); | 1406 jsMethods.add(_emitFactoryConstructor(m)); |
| 1410 } | 1407 } |
| 1411 } else if (m is MethodDeclaration) { | 1408 } else if (m is MethodDeclaration) { |
| 1412 jsMethods.add(_emitMethodDeclaration(type, m)); | 1409 jsMethods.add(_emitMethodDeclaration(type, m)); |
| 1413 | 1410 |
| 1414 if (m.element is PropertyAccessorElement) { | 1411 if (m.element is PropertyAccessorElement) { |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1615 | 1612 |
| 1616 positionalArgs = new JS.ArrayInitializer([]); | 1613 positionalArgs = new JS.ArrayInitializer([]); |
| 1617 } else if (property.isSetter) { | 1614 } else if (property.isSetter) { |
| 1618 addProperty('isSetter', js.boolean(true)); | 1615 addProperty('isSetter', js.boolean(true)); |
| 1619 | 1616 |
| 1620 fnArgs.add(args); | 1617 fnArgs.add(args); |
| 1621 positionalArgs = new JS.ArrayInitializer([args]); | 1618 positionalArgs = new JS.ArrayInitializer([args]); |
| 1622 } | 1619 } |
| 1623 } | 1620 } |
| 1624 | 1621 |
| 1622 var typeParams = _emitTypeFormals(method.type.typeFormals); |
| 1623 if (typeParams.isNotEmpty) { |
| 1624 addProperty('typeArguments', new JS.ArrayInitializer(typeParams)); |
| 1625 } |
| 1626 |
| 1625 var fnBody = | 1627 var fnBody = |
| 1626 js.call('this.noSuchMethod(new #.InvocationImpl.new(#, #, #))', [ | 1628 js.call('this.noSuchMethod(new #.InvocationImpl.new(#, #, #))', [ |
| 1627 _runtimeModule, | 1629 _runtimeModule, |
| 1628 _declareMemberName(method), | 1630 _declareMemberName(method), |
| 1629 positionalArgs, | 1631 positionalArgs, |
| 1630 new JS.ObjectInitializer(invocationProps) | 1632 new JS.ObjectInitializer(invocationProps) |
| 1631 ]); | 1633 ]); |
| 1632 | 1634 |
| 1633 if (!method.returnType.isDynamic) { | 1635 if (!method.returnType.isDynamic) { |
| 1634 fnBody = js.call('#._check(#)', [_emitType(method.returnType), fnBody]); | 1636 fnBody = js.call('#._check(#)', [_emitType(method.returnType), fnBody]); |
| 1635 } | 1637 } |
| 1636 | 1638 |
| 1637 var fn = _makeGenericFunction(new JS.Fun( | 1639 var fn = _makeGenericFunction(new JS.Fun( |
| 1638 fnArgs, js.statement('{ return #; }', [fnBody]), | 1640 fnArgs, js.statement('{ return #; }', [fnBody]), |
| 1639 typeParams: _emitTypeFormals(method.type.typeFormals))); | 1641 typeParams: typeParams)); |
| 1640 | 1642 |
| 1641 // TODO(jmesserly): generic type arguments will get dropped. | |
| 1642 // We have a similar issue with `dgsend` helpers. | |
| 1643 return new JS.Method( | 1643 return new JS.Method( |
| 1644 _declareMemberName(method, | 1644 _declareMemberName(method, |
| 1645 useExtension: _extensionTypes.isNativeClass(type.element)), | 1645 useExtension: _extensionTypes.isNativeClass(type.element)), |
| 1646 fn, | 1646 fn, |
| 1647 isGetter: method is PropertyAccessorElement && method.isGetter, | 1647 isGetter: method is PropertyAccessorElement && method.isGetter, |
| 1648 isSetter: method is PropertyAccessorElement && method.isSetter, | 1648 isSetter: method is PropertyAccessorElement && method.isSetter, |
| 1649 isStatic: false); | 1649 isStatic: false); |
| 1650 } | 1650 } |
| 1651 | 1651 |
| 1652 /// This is called whenever a derived class needs to introduce a new field, | 1652 /// This is called whenever a derived class needs to introduce a new field, |
| (...skipping 519 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2172 | 2172 |
| 2173 return _finishConstructorFunction(params, body, isCallable); | 2173 return _finishConstructorFunction(params, body, isCallable); |
| 2174 } | 2174 } |
| 2175 | 2175 |
| 2176 JS.Expression _finishConstructorFunction( | 2176 JS.Expression _finishConstructorFunction( |
| 2177 List<JS.Parameter> params, JS.Block body, isCallable) { | 2177 List<JS.Parameter> params, JS.Block body, isCallable) { |
| 2178 // We consider a class callable if it inherits from anything with a `call` | 2178 // We consider a class callable if it inherits from anything with a `call` |
| 2179 // method. As a result, we can know the callable JS function was created | 2179 // method. As a result, we can know the callable JS function was created |
| 2180 // at the first constructor that was hit. | 2180 // at the first constructor that was hit. |
| 2181 if (!isCallable) return new JS.Fun(params, body); | 2181 if (!isCallable) return new JS.Fun(params, body); |
| 2182 return js.call( | 2182 return js.call(r'''function callableClass(#) { |
| 2183 r'''function callableClass(#) { | |
| 2184 if (typeof this !== "function") { | 2183 if (typeof this !== "function") { |
| 2185 function self(...args) { | 2184 function self(...args) { |
| 2186 return self.call.apply(self, args); | 2185 return self.call.apply(self, args); |
| 2187 } | 2186 } |
| 2188 self.__proto__ = this.__proto__; | 2187 self.__proto__ = this.__proto__; |
| 2189 callableClass.call(self, #); | 2188 callableClass.call(self, #); |
| 2190 return self; | 2189 return self; |
| 2191 } | 2190 } |
| 2192 # | 2191 # |
| 2193 }''', | 2192 }''', [params, params, body]); |
| 2194 [params, params, body]); | |
| 2195 } | 2193 } |
| 2196 | 2194 |
| 2197 JS.Expression _constructorName(ConstructorElement ctor) { | 2195 JS.Expression _constructorName(ConstructorElement ctor) { |
| 2198 var name = ctor.name; | 2196 var name = ctor.name; |
| 2199 if (name == '') { | 2197 if (name == '') { |
| 2200 // Default constructors (factory or not) use `new` as their name. | 2198 // Default constructors (factory or not) use `new` as their name. |
| 2201 return _propertyName('new'); | 2199 return _propertyName('new'); |
| 2202 } | 2200 } |
| 2203 return _emitMemberName(name, isStatic: true); | 2201 return _emitMemberName(name, isStatic: true); |
| 2204 } | 2202 } |
| (...skipping 3107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5312 return js | 5310 return js |
| 5313 .call('#.new(#)', [_emitConstructorAccess(types.symbolType), name]); | 5311 .call('#.new(#)', [_emitConstructorAccess(types.symbolType), name]); |
| 5314 } | 5312 } |
| 5315 } | 5313 } |
| 5316 | 5314 |
| 5317 return _emitConst(emitSymbol); | 5315 return _emitConst(emitSymbol); |
| 5318 } | 5316 } |
| 5319 | 5317 |
| 5320 @override | 5318 @override |
| 5321 visitListLiteral(ListLiteral node) { | 5319 visitListLiteral(ListLiteral node) { |
| 5322 var isConst = node.constKeyword != null; | 5320 var elementType = (node.staticType as InterfaceType).typeArguments[0]; |
| 5323 JS.Expression emitList() { | 5321 if (node.constKeyword == null) { |
| 5324 JS.Expression list = new JS.ArrayInitializer(_visitList(node.elements)); | 5322 return _emitList(elementType, _visitList(node.elements)); |
| 5325 ParameterizedType type = node.staticType; | |
| 5326 var elementType = type.typeArguments.single; | |
| 5327 // TODO(jmesserly): analyzer will usually infer `List<Object>` because | |
| 5328 // that is the least upper bound of the element types. So we rarely | |
| 5329 // generate a plain `List<dynamic>` anymore. | |
| 5330 if (!elementType.isDynamic || isConst) { | |
| 5331 // dart.list helper internally depends on _interceptors.JSArray. | |
| 5332 _declareBeforeUse(_jsArray); | |
| 5333 if (isConst) { | |
| 5334 var typeRep = _emitType(elementType); | |
| 5335 list = _callHelper('constList(#, #)', [list, typeRep]); | |
| 5336 } else { | |
| 5337 // Call `new JSArray<E>.of(list)` | |
| 5338 var jsArrayType = _jsArray.type.instantiate(type.typeArguments); | |
| 5339 list = js.call('#.of(#)', [_emitType(jsArrayType), list]); | |
| 5340 } | |
| 5341 } | |
| 5342 return list; | |
| 5343 } | 5323 } |
| 5324 return _cacheConst(() { |
| 5325 // dart.constList helper internally depends on _interceptors.JSArray. |
| 5326 _declareBeforeUse(_jsArray); |
| 5327 return _callHelper('constList(#, #)', [ |
| 5328 new JS.ArrayInitializer(_visitList(node.elements)), |
| 5329 _emitType(elementType) |
| 5330 ]); |
| 5331 }); |
| 5332 } |
| 5344 | 5333 |
| 5345 if (isConst) return _cacheConst(emitList); | 5334 JS.Expression _emitList(DartType itemType, List<JS.Expression> items) { |
| 5346 return emitList(); | 5335 var list = new JS.ArrayInitializer(items); |
| 5336 |
| 5337 // TODO(jmesserly): analyzer will usually infer `List<Object>` because |
| 5338 // that is the least upper bound of the element types. So we rarely |
| 5339 // generate a plain `List<dynamic>` anymore. |
| 5340 if (itemType.isDynamic) return list; |
| 5341 |
| 5342 // Call `new JSArray<E>.of(list)` |
| 5343 var arrayType = _jsArray.type.instantiate([itemType]); |
| 5344 return js.call('#.of(#)', [_emitType(arrayType), list]); |
| 5347 } | 5345 } |
| 5348 | 5346 |
| 5349 @override | 5347 @override |
| 5350 visitMapLiteral(MapLiteral node) { | 5348 visitMapLiteral(MapLiteral node) { |
| 5351 // TODO(jmesserly): we can likely make these faster. | 5349 // TODO(jmesserly): we can likely make these faster. |
| 5352 JS.Expression emitMap() { | 5350 JS.Expression emitMap() { |
| 5353 var entries = node.entries; | 5351 var entries = node.entries; |
| 5354 Object mapArguments = null; | 5352 Object mapArguments = null; |
| 5355 var type = node.staticType as InterfaceType; | 5353 var type = node.staticType as InterfaceType; |
| 5356 var typeArgs = type.typeArguments; | 5354 var typeArgs = type.typeArguments; |
| (...skipping 621 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5978 if (targetIdentifier.staticElement is! PrefixElement) return false; | 5976 if (targetIdentifier.staticElement is! PrefixElement) return false; |
| 5979 var prefix = targetIdentifier.staticElement as PrefixElement; | 5977 var prefix = targetIdentifier.staticElement as PrefixElement; |
| 5980 | 5978 |
| 5981 // The library the prefix is referring to must come from a deferred import. | 5979 // The library the prefix is referring to must come from a deferred import. |
| 5982 var containingLibrary = resolutionMap | 5980 var containingLibrary = resolutionMap |
| 5983 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) | 5981 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) |
| 5984 .library; | 5982 .library; |
| 5985 var imports = containingLibrary.getImportsWithPrefix(prefix); | 5983 var imports = containingLibrary.getImportsWithPrefix(prefix); |
| 5986 return imports.length == 1 && imports[0].isDeferred; | 5984 return imports.length == 1 && imports[0].isDeferred; |
| 5987 } | 5985 } |
| OLD | NEW |