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 |