@@ -40,7 +40,7 @@ import 'js_names.dart';
40
40
import 'js_printer.dart' show writeJsLibrary;
41
41
import 'js_typeref_codegen.dart' ;
42
42
import 'module_builder.dart' ;
43
- import 'nullability_inferrer .dart' ;
43
+ import 'nullable_type_inference .dart' ;
44
44
import 'side_effect_analysis.dart' ;
45
45
46
46
// Various dynamic helpers we call.
@@ -111,6 +111,8 @@ class JSCodegenVisitor extends GeneralizingAstVisitor
111
111
112
112
bool _isDartRuntime;
113
113
114
+ NullableTypeInference _nullInference;
115
+
114
116
JSCodegenVisitor (AbstractCompiler compiler, this .rules, this .currentLibrary,
115
117
this ._extensionTypes, this ._fieldsNeedingStorage)
116
118
: compiler = compiler,
@@ -127,8 +129,6 @@ class JSCodegenVisitor extends GeneralizingAstVisitor
127
129
128
130
TypeProvider get types => _types;
129
131
130
- NullableExpressionPredicate _isNullable;
131
-
132
132
JS .Program emitLibrary (LibraryUnit library) {
133
133
// Modify the AST to make coercions explicit.
134
134
new CoercionReifier (library, rules).reify ();
@@ -142,24 +142,25 @@ class JSCodegenVisitor extends GeneralizingAstVisitor
142
142
143
143
library.library.directives.forEach (_visit);
144
144
145
+ var units = library.partsThenLibrary;
146
+
145
147
// Rather than directly visit declarations, we instead use [_loader] to
146
148
// visit them. It has the ability to sort elements on demand, so
147
149
// dependencies between top level items are handled with a minimal
148
150
// reordering of the user's input code. The loader will call back into
149
151
// this visitor via [_emitModuleItem] when it's ready to visit the item
150
152
// for real.
151
- _loader.collectElements (currentLibrary, library.partsThenLibrary );
153
+ _loader.collectElements (currentLibrary, units );
152
154
153
- var units = library.partsThenLibrary;
154
- // TODO(ochafik): Move this down to smaller scopes (method, top-levels) to
155
- // save memory.
156
- _isNullable = new NullabilityInferrer (units,
157
- getStaticType: getStaticType, isJSBuiltinType: _isJSBuiltinType)
158
- .buildNullabilityPredicate ();
155
+ // TODO(jmesserly): ideally we could do this at a smaller granularity.
156
+ // We'll need to be consistent about when we're generating functions, and
157
+ // only run this on the outermost function.
158
+ _nullInference =
159
+ new NullableTypeInference .forLibrary (_isPrimitiveType, units);
159
160
160
- for (var unit in units) {
161
- _constField = new ConstFieldVisitor (types, unit);
161
+ _constField = new ConstFieldVisitor (types, library.library.element.source);
162
162
163
+ for (var unit in units) {
163
164
for (var decl in unit.declarations) {
164
165
if (decl is TopLevelVariableDeclaration ) {
165
166
visitTopLevelVariableDeclaration (decl);
@@ -1245,8 +1246,6 @@ class JSCodegenVisitor extends GeneralizingAstVisitor
1245
1246
JS .Statement _initializeFields (
1246
1247
ClassDeclaration cls, List <FieldDeclaration > fieldDecls,
1247
1248
[ConstructorDeclaration ctor]) {
1248
- var unit = cls.getAncestor ((a) => a is CompilationUnit ) as CompilationUnit ;
1249
- var constField = new ConstFieldVisitor (types, unit);
1250
1249
bool isConst = ctor != null && ctor.constKeyword != null ;
1251
1250
if (isConst) _loader.startTopLevel (cls.element);
1252
1251
@@ -1256,7 +1255,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor
1256
1255
for (var declaration in fieldDecls) {
1257
1256
for (var fieldNode in declaration.fields.variables) {
1258
1257
var element = fieldNode.element;
1259
- if (constField .isFieldInitConstant (fieldNode)) {
1258
+ if (_constField .isFieldInitConstant (fieldNode)) {
1260
1259
unsetFields[element as FieldElement ] = fieldNode;
1261
1260
} else {
1262
1261
fields[element as FieldElement ] = _visitInitializer (fieldNode);
@@ -1617,7 +1616,6 @@ class JSCodegenVisitor extends GeneralizingAstVisitor
1617
1616
1618
1617
if (body is ExpressionFunctionBody && ! destructureNamed) {
1619
1618
// An arrow function can use the expression directly.
1620
- // Note: this only works if we don't need to emit argument initializers.
1621
1619
jsBody = _visit (body.expression);
1622
1620
} else {
1623
1621
jsBody = _visit (body);
@@ -2642,7 +2640,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor
2642
2640
/// For these types we generate a calling convention via static
2643
2641
/// "extension methods". This allows types to be extended without adding
2644
2642
/// extensions directly on the prototype.
2645
- bool _isJSBuiltinType (DartType t) =>
2643
+ bool _isPrimitiveType (DartType t) =>
2646
2644
typeIsPrimitiveInJS (t) || t == _types.stringType;
2647
2645
2648
2646
bool typeIsPrimitiveInJS (DartType t) =>
@@ -2660,6 +2658,13 @@ class JSCodegenVisitor extends GeneralizingAstVisitor
2660
2658
return js.call ('dart.notNull(#)' , jsExpr);
2661
2659
}
2662
2660
2661
+ /// Returns true if [expr] can be null, optionally using [localIsNullable]
2662
+ /// for locals.
2663
+ ///
2664
+ /// This analysis is conservative and incomplete, but it can optimize many
2665
+ /// common patterns.
2666
+ bool _isNullable (Expression expr) => _nullInference.isNullable (expr);
2667
+
2663
2668
@override
2664
2669
JS .Expression visitBinaryExpression (BinaryExpression node) {
2665
2670
var op = node.operator ;
@@ -2732,12 +2737,13 @@ class JSCodegenVisitor extends GeneralizingAstVisitor
2732
2737
2733
2738
var leftType = _canonicalizeNumTypes (getStaticType (left));
2734
2739
var rightType = _canonicalizeNumTypes (getStaticType (right));
2735
- return _isJSBuiltinType (leftType) && leftType == rightType;
2740
+ return _isPrimitiveType (leftType) && leftType == rightType;
2736
2741
}
2737
2742
2738
2743
bool _isNull (Expression expr) => expr is NullLiteral ;
2739
2744
2740
- SimpleIdentifier _createTemporary (String name, DartType type) {
2745
+ SimpleIdentifier _createTemporary (String name, DartType type,
2746
+ {bool nullable: true }) {
2741
2747
// We use an invalid source location to signal that this is a temporary.
2742
2748
// See [_isTemporary].
2743
2749
// TODO(jmesserly): alternatives are
@@ -2750,6 +2756,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor
2750
2756
id.staticElement = new TemporaryVariableElement .forNode (id);
2751
2757
id.staticType = type;
2752
2758
DynamicInvoke .set (id, type.isDynamic);
2759
+ _nullInference.addVariable (id.staticElement, nullable: nullable);
2753
2760
return id;
2754
2761
}
2755
2762
@@ -2847,7 +2854,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor
2847
2854
/// // psuedocode mix of Scheme and JS:
2848
2855
/// (let* (x1=expr1, x2=expr2, t=expr1[expr2]) { x1[x2] = t + 1; t })
2849
2856
///
2850
- /// The [JS.JS. MetaLet] nodes automatically simplify themselves if they can.
2857
+ /// The [JS.MetaLet] nodes automatically simplify themselves if they can.
2851
2858
/// For example, if the result value is not used, then `t` goes away.
2852
2859
@override
2853
2860
JS .Expression visitPostfixExpression (PostfixExpression node) {
@@ -2992,7 +2999,8 @@ class JSCodegenVisitor extends GeneralizingAstVisitor
2992
2999
break ;
2993
3000
}
2994
3001
2995
- var param = _createTemporary ('_' , nodeTarget.staticType);
3002
+ var param =
3003
+ _createTemporary ('_' , nodeTarget.staticType, nullable: false );
2996
3004
var baseNode = _stripNullAwareOp (node, param);
2997
3005
tail.add (new JS .ArrowFun ([_visit (param)], _visit (baseNode)));
2998
3006
node = nodeTarget;
@@ -3227,7 +3235,8 @@ class JSCodegenVisitor extends GeneralizingAstVisitor
3227
3235
null ,
3228
3236
AstBuilder .argumentList ([node.iterable]),
3229
3237
false );
3230
- var iter = _visit (_createTemporary ('it' , StreamIterator_T ));
3238
+ var iter =
3239
+ _visit (_createTemporary ('it' , StreamIterator_T , nullable: false ));
3231
3240
3232
3241
var init = _visit (node.identifier);
3233
3242
if (init == null ) {
@@ -3643,9 +3652,6 @@ class JSCodegenVisitor extends GeneralizingAstVisitor
3643
3652
library, () => new JS .TemporaryId (jsLibraryName (library)));
3644
3653
}
3645
3654
3646
- DartType getStaticType (Expression e) =>
3647
- e.staticType ?? DynamicTypeImpl .instance;
3648
-
3649
3655
JS .Node annotate (JS .Node node, AstNode original, [Element element]) {
3650
3656
if (options.closure && element != null ) {
3651
3657
node = node.withClosureAnnotation (closureAnnotationFor (
0 commit comments