| 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 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 143 | 143 |
| 144 final ClassElement boolClass; | 144 final ClassElement boolClass; |
| 145 final ClassElement intClass; | 145 final ClassElement intClass; |
| 146 final ClassElement interceptorClass; | 146 final ClassElement interceptorClass; |
| 147 final ClassElement nullClass; | 147 final ClassElement nullClass; |
| 148 final ClassElement numClass; | 148 final ClassElement numClass; |
| 149 final ClassElement objectClass; | 149 final ClassElement objectClass; |
| 150 final ClassElement stringClass; | 150 final ClassElement stringClass; |
| 151 final ClassElement functionClass; | 151 final ClassElement functionClass; |
| 152 final ClassElement privateSymbolClass; | 152 final ClassElement privateSymbolClass; |
| 153 final PropertyAccessorElement _undefinedConstant; |
| 153 | 154 |
| 154 ConstFieldVisitor _constants; | 155 ConstFieldVisitor _constants; |
| 155 | 156 |
| 156 /// The current function body being compiled. | 157 /// The current function body being compiled. |
| 157 FunctionBody _currentFunction; | 158 FunctionBody _currentFunction; |
| 158 | 159 |
| 159 HashMap<TypeDefiningElement, AstNode> _declarationNodes; | 160 HashMap<TypeDefiningElement, AstNode> _declarationNodes; |
| 160 | 161 |
| 161 /// The stack of currently emitting elements, if generating top-level code | 162 /// The stack of currently emitting elements, if generating top-level code |
| 162 /// for them. This is not used when inside method bodies, because order does | 163 /// for them. This is not used when inside method bodies, because order does |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 216 dartCoreLibrary = _getLibrary(c, 'dart:core'), | 217 dartCoreLibrary = _getLibrary(c, 'dart:core'), |
| 217 boolClass = _getLibrary(c, 'dart:core').getType('bool'), | 218 boolClass = _getLibrary(c, 'dart:core').getType('bool'), |
| 218 intClass = _getLibrary(c, 'dart:core').getType('int'), | 219 intClass = _getLibrary(c, 'dart:core').getType('int'), |
| 219 numClass = _getLibrary(c, 'dart:core').getType('num'), | 220 numClass = _getLibrary(c, 'dart:core').getType('num'), |
| 220 nullClass = _getLibrary(c, 'dart:core').getType('Null'), | 221 nullClass = _getLibrary(c, 'dart:core').getType('Null'), |
| 221 objectClass = _getLibrary(c, 'dart:core').getType('Object'), | 222 objectClass = _getLibrary(c, 'dart:core').getType('Object'), |
| 222 stringClass = _getLibrary(c, 'dart:core').getType('String'), | 223 stringClass = _getLibrary(c, 'dart:core').getType('String'), |
| 223 functionClass = _getLibrary(c, 'dart:core').getType('Function'), | 224 functionClass = _getLibrary(c, 'dart:core').getType('Function'), |
| 224 privateSymbolClass = | 225 privateSymbolClass = |
| 225 _getLibrary(c, 'dart:_internal').getType('PrivateSymbol'), | 226 _getLibrary(c, 'dart:_internal').getType('PrivateSymbol'), |
| 226 dartJSLibrary = _getLibrary(c, 'dart:js') { | 227 dartJSLibrary = _getLibrary(c, 'dart:js'), |
| 228 _undefinedConstant = |
| 229 _getLibrary(c, 'dart:_runtime').publicNamespace.get('undefined') { |
| 230 assert(_undefinedConstant != null); |
| 227 typeRep = new JSTypeRep(rules, types); | 231 typeRep = new JSTypeRep(rules, types); |
| 228 } | 232 } |
| 229 | 233 |
| 230 Element get currentElement => _currentElements.last; | 234 Element get currentElement => _currentElements.last; |
| 231 | 235 |
| 232 LibraryElement get currentLibrary => currentElement.library; | 236 LibraryElement get currentLibrary => currentElement.library; |
| 233 | 237 |
| 234 /// The main entry point to JavaScript code generation. | 238 /// The main entry point to JavaScript code generation. |
| 235 /// | 239 /// |
| 236 /// Takes the metadata for the build unit, as well as resolved trees and | 240 /// Takes the metadata for the build unit, as well as resolved trees and |
| (...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 586 // per-compilation-unit state. Declarations can be visited out of order, | 590 // per-compilation-unit state. Declarations can be visited out of order, |
| 587 // this is only to catch things that haven't been emitted yet. | 591 // this is only to catch things that haven't been emitted yet. |
| 588 // | 592 // |
| 589 // See _emitTypeDeclaration. | 593 // See _emitTypeDeclaration. |
| 590 _currentElements.add(unit.element); | 594 _currentElements.add(unit.element); |
| 591 var isInternalSdk = isSdkInternalRuntime(currentLibrary); | 595 var isInternalSdk = isSdkInternalRuntime(currentLibrary); |
| 592 List<VariableDeclaration> fields; | 596 List<VariableDeclaration> fields; |
| 593 for (var declaration in unit.declarations) { | 597 for (var declaration in unit.declarations) { |
| 594 if (declaration is TopLevelVariableDeclaration) { | 598 if (declaration is TopLevelVariableDeclaration) { |
| 595 inferNullableTypes(declaration); | 599 inferNullableTypes(declaration); |
| 596 if (isInternalSdk && declaration.variables.isFinal) { | 600 if (isInternalSdk && |
| 601 (declaration.variables.isFinal || declaration.variables.isConst)) { |
| 597 _emitInternalSdkFields(declaration.variables.variables); | 602 _emitInternalSdkFields(declaration.variables.variables); |
| 598 } else { | 603 } else { |
| 599 (fields ??= []).addAll(declaration.variables.variables); | 604 (fields ??= []).addAll(declaration.variables.variables); |
| 600 } | 605 } |
| 601 continue; | 606 continue; |
| 602 } | 607 } |
| 603 | 608 |
| 604 if (fields != null) { | 609 if (fields != null) { |
| 605 _emitTopLevelFields(fields); | 610 _emitTopLevelFields(fields); |
| 606 fields = null; | 611 fields = null; |
| (...skipping 1797 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2404 // than always when we visit the function body, so we control it explicitly. | 2409 // than always when we visit the function body, so we control it explicitly. |
| 2405 if (node is ConstructorDeclaration != constructor) return null; | 2410 if (node is ConstructorDeclaration != constructor) return null; |
| 2406 | 2411 |
| 2407 var parameters = _parametersOf(node); | 2412 var parameters = _parametersOf(node); |
| 2408 if (parameters == null) return null; | 2413 if (parameters == null) return null; |
| 2409 | 2414 |
| 2410 var body = <JS.Statement>[]; | 2415 var body = <JS.Statement>[]; |
| 2411 for (var param in parameters.parameters) { | 2416 for (var param in parameters.parameters) { |
| 2412 var jsParam = _emitSimpleIdentifier(param.identifier); | 2417 var jsParam = _emitSimpleIdentifier(param.identifier); |
| 2413 | 2418 |
| 2414 if (!options.destructureNamedParams) { | 2419 if (!options.destructureNamedParams && |
| 2420 param.kind != ParameterKind.REQUIRED) { |
| 2415 if (param.kind == ParameterKind.NAMED) { | 2421 if (param.kind == ParameterKind.NAMED) { |
| 2416 // Parameters will be passed using their real names, not the (possibly | 2422 // Parameters will be passed using their real names, not the (possibly |
| 2417 // renamed) local variable. | 2423 // renamed) local variable. |
| 2418 var paramName = js.string(param.identifier.name, "'"); | 2424 var paramName = js.string(param.identifier.name, "'"); |
| 2419 | 2425 var defaultValue = _defaultParamValue(param); |
| 2420 // TODO(ochafik): Fix `'prop' in obj` to please Closure's renaming. | 2426 if (defaultValue != null) { |
| 2421 body.add(js.statement('let # = # && # in # ? #.# : #;', [ | 2427 // TODO(ochafik): Fix `'prop' in obj` to please Closure's renaming. |
| 2422 jsParam, | 2428 body.add(js.statement('let # = # && # in # ? #.# : #;', [ |
| 2423 namedArgumentTemp, | 2429 jsParam, |
| 2424 paramName, | 2430 namedArgumentTemp, |
| 2425 namedArgumentTemp, | 2431 paramName, |
| 2426 namedArgumentTemp, | 2432 namedArgumentTemp, |
| 2427 paramName, | 2433 namedArgumentTemp, |
| 2428 _defaultParamValue(param), | 2434 paramName, |
| 2429 ])); | 2435 defaultValue, |
| 2436 ])); |
| 2437 } else { |
| 2438 body.add(js.statement('let # = # && #.#;', [ |
| 2439 jsParam, |
| 2440 namedArgumentTemp, |
| 2441 namedArgumentTemp, |
| 2442 paramName, |
| 2443 ])); |
| 2444 } |
| 2430 } else if (param.kind == ParameterKind.POSITIONAL) { | 2445 } else if (param.kind == ParameterKind.POSITIONAL) { |
| 2431 body.add(js.statement('if (# === void 0) # = #;', | 2446 var defaultValue = _defaultParamValue(param); |
| 2432 [jsParam, jsParam, _defaultParamValue(param)])); | 2447 if (defaultValue != null) { |
| 2448 body.add(js.statement( |
| 2449 'if (# === void 0) # = #;', [jsParam, jsParam, defaultValue])); |
| 2450 } |
| 2433 } | 2451 } |
| 2434 } | 2452 } |
| 2435 | 2453 |
| 2436 var paramElement = resolutionMap.elementDeclaredByFormalParameter(param); | 2454 var paramElement = resolutionMap.elementDeclaredByFormalParameter(param); |
| 2437 if (_isCovariant(paramElement)) { | 2455 if (_isCovariant(paramElement)) { |
| 2438 var castType = _emitType(paramElement.type); | 2456 var castType = _emitType(paramElement.type); |
| 2439 body.add(js.statement('#._check(#);', [castType, jsParam])); | 2457 body.add(js.statement('#._check(#);', [castType, jsParam])); |
| 2440 } | 2458 } |
| 2441 if (_annotatedNullCheck(paramElement)) { | 2459 if (_annotatedNullCheck(paramElement)) { |
| 2442 body.add(nullParameterCheck(jsParam)); | 2460 body.add(nullParameterCheck(jsParam)); |
| 2443 } | 2461 } |
| 2444 } | 2462 } |
| 2445 return body.isEmpty ? null : _statement(body); | 2463 return body.isEmpty ? null : _statement(body); |
| 2446 } | 2464 } |
| 2447 | 2465 |
| 2448 bool _isCovariant(ParameterElement p) { | 2466 bool _isCovariant(ParameterElement p) { |
| 2449 if (p.isCovariant) return true; | 2467 if (p.isCovariant) return true; |
| 2450 var covariantParams = _classProperties?.covariantParameters; | 2468 var covariantParams = _classProperties?.covariantParameters; |
| 2451 return covariantParams != null && covariantParams.contains(p); | 2469 return covariantParams != null && covariantParams.contains(p); |
| 2452 } | 2470 } |
| 2453 | 2471 |
| 2454 JS.Expression _defaultParamValue(FormalParameter param) { | 2472 JS.Expression _defaultParamValue(FormalParameter param) { |
| 2455 if (param is DefaultFormalParameter && param.defaultValue != null) { | 2473 if (param is DefaultFormalParameter && param.defaultValue != null) { |
| 2474 var defaultValue = param.defaultValue; |
| 2475 if (defaultValue is Identifier && |
| 2476 defaultValue.staticElement == _undefinedConstant) { |
| 2477 return null; |
| 2478 } |
| 2456 return _visit(param.defaultValue); | 2479 return _visit(param.defaultValue); |
| 2457 } else { | 2480 } else { |
| 2458 return new JS.LiteralNull(); | 2481 return new JS.LiteralNull(); |
| 2459 } | 2482 } |
| 2460 } | 2483 } |
| 2461 | 2484 |
| 2462 JS.Fun _emitNativeFunctionBody(MethodDeclaration node) { | 2485 JS.Fun _emitNativeFunctionBody(MethodDeclaration node) { |
| 2463 String name = | 2486 String name = |
| 2464 getAnnotationName(node.element, isJSAnnotation) ?? node.name.name; | 2487 getAnnotationName(node.element, isJSAnnotation) ?? node.name.name; |
| 2465 if (node.isGetter) { | 2488 if (node.isGetter) { |
| (...skipping 1446 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3912 } | 3935 } |
| 3913 JS.Expression name; | 3936 JS.Expression name; |
| 3914 JS.SimpleBindingPattern structure = null; | 3937 JS.SimpleBindingPattern structure = null; |
| 3915 String paramName = param.identifier.name; | 3938 String paramName = param.identifier.name; |
| 3916 if (JS.invalidVariableName(paramName)) { | 3939 if (JS.invalidVariableName(paramName)) { |
| 3917 name = js.string(paramName); | 3940 name = js.string(paramName); |
| 3918 structure = new JS.SimpleBindingPattern(_visit(param.identifier)); | 3941 structure = new JS.SimpleBindingPattern(_visit(param.identifier)); |
| 3919 } else { | 3942 } else { |
| 3920 name = _visit(param.identifier); | 3943 name = _visit(param.identifier); |
| 3921 } | 3944 } |
| 3945 |
| 3946 var defaultValue = _defaultParamValue(param); |
| 3922 namedVars.add(new JS.DestructuredVariable( | 3947 namedVars.add(new JS.DestructuredVariable( |
| 3923 name: name, | 3948 name: name, structure: structure, defaultValue: defaultValue)); |
| 3924 structure: structure, | |
| 3925 defaultValue: _defaultParamValue(param))); | |
| 3926 } else { | 3949 } else { |
| 3927 needsOpts = true; | 3950 needsOpts = true; |
| 3928 } | 3951 } |
| 3929 } else { | 3952 } else { |
| 3930 var jsParam = _visit(param); | 3953 var jsParam = _visit(param); |
| 3931 result.add(param is DefaultFormalParameter && destructure | 3954 var defaultValue = _defaultParamValue(param); |
| 3955 result.add(destructure && defaultValue != null |
| 3932 ? new JS.DestructuredVariable( | 3956 ? new JS.DestructuredVariable( |
| 3933 name: jsParam, defaultValue: _defaultParamValue(param)) | 3957 name: jsParam, defaultValue: defaultValue) |
| 3934 : jsParam); | 3958 : jsParam); |
| 3935 } | 3959 } |
| 3936 } | 3960 } |
| 3937 | 3961 |
| 3938 if (needsOpts) { | 3962 if (needsOpts) { |
| 3939 result.add(namedArgumentTemp); | 3963 result.add(namedArgumentTemp); |
| 3940 } else if (namedVars.isNotEmpty) { | 3964 } else if (namedVars.isNotEmpty) { |
| 3941 // Note: `var {valueOf} = {}` extracts `Object.prototype.valueOf`, so | 3965 // Note: `var {valueOf} = {}` extracts `Object.prototype.valueOf`, so |
| 3942 // in case there are conflicting names we create an object without | 3966 // in case there are conflicting names we create an object without |
| 3943 // any prototype. | 3967 // any prototype. |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4031 // A normal yield in a sync* | 4055 // A normal yield in a sync* |
| 4032 return jsExpr.toYieldStatement(star: star); | 4056 return jsExpr.toYieldStatement(star: star); |
| 4033 } | 4057 } |
| 4034 | 4058 |
| 4035 @override | 4059 @override |
| 4036 JS.Expression visitAwaitExpression(AwaitExpression node) { | 4060 JS.Expression visitAwaitExpression(AwaitExpression node) { |
| 4037 return new JS.Yield(_visit(node.expression)); | 4061 return new JS.Yield(_visit(node.expression)); |
| 4038 } | 4062 } |
| 4039 | 4063 |
| 4040 /// This is not used--we emit top-level fields as we are emitting the | 4064 /// This is not used--we emit top-level fields as we are emitting the |
| 4041 /// compilation unit, see [_emitCompilationUnit]. | 4065 /// compilation unit, see [visitCompilationUnit]. |
| 4042 @override | 4066 @override |
| 4043 visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { | 4067 visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { |
| 4044 assert(false); | 4068 assert(false); |
| 4045 } | 4069 } |
| 4046 | 4070 |
| 4047 /// This is not used--we emit fields as we are emitting the class, | 4071 /// This is not used--we emit fields as we are emitting the class, |
| 4048 /// see [visitClassDeclaration]. | 4072 /// see [visitClassDeclaration]. |
| 4049 @override | 4073 @override |
| 4050 visitFieldDeclaration(FieldDeclaration node) { | 4074 visitFieldDeclaration(FieldDeclaration node) { |
| 4051 assert(false); | 4075 assert(false); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4092 | 4116 |
| 4093 /// Emits a list of top-level field. | 4117 /// Emits a list of top-level field. |
| 4094 void _emitTopLevelFields(List<VariableDeclaration> fields) { | 4118 void _emitTopLevelFields(List<VariableDeclaration> fields) { |
| 4095 _moduleItems.add(_emitLazyFields(currentLibrary, fields)); | 4119 _moduleItems.add(_emitLazyFields(currentLibrary, fields)); |
| 4096 } | 4120 } |
| 4097 | 4121 |
| 4098 /// Treat dart:_runtime fields as safe to eagerly evaluate. | 4122 /// Treat dart:_runtime fields as safe to eagerly evaluate. |
| 4099 // TODO(jmesserly): it'd be nice to avoid this special case. | 4123 // TODO(jmesserly): it'd be nice to avoid this special case. |
| 4100 void _emitInternalSdkFields(List<VariableDeclaration> fields) { | 4124 void _emitInternalSdkFields(List<VariableDeclaration> fields) { |
| 4101 for (var field in fields) { | 4125 for (var field in fields) { |
| 4126 // Skip our magic undefined constant. |
| 4127 var element = field.element as TopLevelVariableElement; |
| 4128 if (element.getter == _undefinedConstant) continue; |
| 4102 _moduleItems.add(annotate( | 4129 _moduleItems.add(annotate( |
| 4103 js.statement('# = #;', | 4130 js.statement('# = #;', |
| 4104 [_emitTopLevelName(field.element), _visitInitializer(field)]), | 4131 [_emitTopLevelName(field.element), _visitInitializer(field)]), |
| 4105 field, | 4132 field, |
| 4106 field.element)); | 4133 field.element)); |
| 4107 } | 4134 } |
| 4108 } | 4135 } |
| 4109 | 4136 |
| 4110 JS.Expression _visitInitializer(VariableDeclaration node) { | 4137 JS.Expression _visitInitializer(VariableDeclaration node) { |
| 4111 var value = _annotatedNullCheck(node.element) | 4138 var value = _annotatedNullCheck(node.element) |
| (...skipping 1925 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6037 // The library the prefix is referring to must come from a deferred import. | 6064 // The library the prefix is referring to must come from a deferred import. |
| 6038 var containingLibrary = resolutionMap | 6065 var containingLibrary = resolutionMap |
| 6039 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) | 6066 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) |
| 6040 .library; | 6067 .library; |
| 6041 var imports = containingLibrary.getImportsWithPrefix(prefix); | 6068 var imports = containingLibrary.getImportsWithPrefix(prefix); |
| 6042 return imports.length == 1 && imports[0].isDeferred; | 6069 return imports.length == 1 && imports[0].isDeferred; |
| 6043 } | 6070 } |
| 6044 | 6071 |
| 6045 bool _annotatedNullCheck(Element e) => | 6072 bool _annotatedNullCheck(Element e) => |
| 6046 e != null && findAnnotation(e, isNullCheckAnnotation) != null; | 6073 e != null && findAnnotation(e, isNullCheckAnnotation) != null; |
| OLD | NEW |