Index: pkg/dev_compiler/lib/src/compiler/code_generator.dart |
diff --git a/pkg/dev_compiler/lib/src/compiler/code_generator.dart b/pkg/dev_compiler/lib/src/compiler/code_generator.dart |
index 9deaaa4fa053320d93a13df21a5d4f3fb4bdeee7..31b30abeed87b429e427b5061b08dbed5a715a20 100644 |
--- a/pkg/dev_compiler/lib/src/compiler/code_generator.dart |
+++ b/pkg/dev_compiler/lib/src/compiler/code_generator.dart |
@@ -44,7 +44,7 @@ import 'js_interop.dart'; |
import 'js_metalet.dart' as JS; |
import 'js_names.dart' as JS; |
import 'js_typeref_codegen.dart' show JsTypeRefCodegen; |
-import 'js_typerep.dart' show JSTypeRep; |
+import 'js_typerep.dart' show JSTypeRep, JSType; |
import 'module_builder.dart' show pathToJSIdentifier; |
import 'nullable_type_inference.dart' show NullableTypeInference; |
import 'property_model.dart'; |
@@ -135,8 +135,11 @@ class CodeGenerator extends Object |
/// The dart:core `identical` element. |
final FunctionElement _coreIdentical; |
- /// The dart:_interceptors JSArray element. |
+ /// The dart:_interceptors implementation elements. |
final ClassElement _jsArray; |
+ final ClassElement _jsBool; |
+ final ClassElement _jsNumber; |
+ final ClassElement _jsString; |
final ClassElement boolClass; |
final ClassElement intClass; |
@@ -205,6 +208,9 @@ class CodeGenerator extends Object |
_coreIdentical = |
_getLibrary(c, 'dart:core').publicNamespace.get('identical'), |
_jsArray = _getLibrary(c, 'dart:_interceptors').getType('JSArray'), |
+ _jsBool = _getLibrary(c, 'dart:_interceptors').getType('JSBool'), |
+ _jsString = _getLibrary(c, 'dart:_interceptors').getType('JSString'), |
+ _jsNumber = _getLibrary(c, 'dart:_interceptors').getType('JSNumber'), |
interceptorClass = |
_getLibrary(c, 'dart:_interceptors').getType('Interceptor'), |
dartCoreLibrary = _getLibrary(c, 'dart:core'), |
@@ -2432,6 +2438,9 @@ class CodeGenerator extends Object |
var castType = _emitType(paramElement.type); |
body.add(js.statement('#._check(#);', [castType, jsParam])); |
} |
+ if (_annotatedNullCheck(paramElement)) { |
+ body.add(nullParameterCheck(jsParam)); |
+ } |
} |
return body.isEmpty ? null : _statement(body); |
} |
@@ -3267,6 +3276,9 @@ class CodeGenerator extends Object |
// (for example, x is IndexExpression) we evaluate those once. |
var vars = <JS.MetaLetVariable, JS.Expression>{}; |
var lhs = _bindLeftHandSide(vars, left, context: context); |
+ // TODO(leafp): The element for lhs here will be the setter element |
+ // instead of the getter element if lhs is a property access. This |
+ // interferes with nullability analysis. |
Jennifer Messerly
2017/08/22 21:54:41
FYI ... I think it would be safe to fix _bindLeftH
Leaf
2017/08/23 17:26:14
Not super high priority, but good to fix at some p
|
Expression inc = AstBuilder.binaryExpression(lhs, op, right) |
..staticElement = element |
..staticType = getStaticType(lhs); |
@@ -4050,7 +4062,10 @@ class CodeGenerator extends Object |
var v = variables[0]; |
if (v.initializer != null) { |
var name = new JS.Identifier(v.name.name); |
- return _visit<JS.Expression>(v.initializer).toVariableDeclaration(name); |
+ var value = _annotatedNullCheck(v.element) |
+ ? notNull(v.initializer) |
+ : _visit<JS.Expression>(v.initializer); |
+ return value.toVariableDeclaration(name); |
} |
} |
return _visit<JS.Expression>(node.variables).toStatement(); |
@@ -4093,7 +4108,9 @@ class CodeGenerator extends Object |
} |
JS.Expression _visitInitializer(VariableDeclaration node) { |
- var value = _visit(node.initializer); |
+ var value = _annotatedNullCheck(node.element) |
+ ? notNull(node.initializer) |
+ : _visit(node.initializer); |
// explicitly initialize to null, to avoid getting `undefined`. |
// TODO(jmesserly): do this only for vars that aren't definitely assigned. |
return value ?? new JS.LiteralNull(); |
@@ -4254,6 +4271,20 @@ class CodeGenerator extends Object |
bool isPrimitiveType(DartType t) => typeRep.isPrimitive(t); |
+ InterfaceType getImplementationType(DartType t) { |
Jennifer Messerly
2017/08/22 21:54:41
add a doc comment?
/// Given a Dart type for `boo
Leaf
2017/08/23 17:26:14
Done.
|
+ JSType rep = typeRep.typeFor(t); |
+ // Number, String, and Bool are final |
+ if (rep == JSType.jsNumber) return _jsNumber.type; |
+ if (rep == JSType.jsBoolean) return _jsBool.type; |
+ if (rep == JSType.jsString) return _jsString.type; |
+ return null; |
+ } |
+ |
+ JS.Statement nullParameterCheck(JS.Expression param) { |
+ var call = _callHelper('throwArgumentErrorValue((#))', [param]); |
Jennifer Messerly
2017/08/22 21:54:41
if these are really common, consider a shorter nam
Leaf
2017/08/23 17:26:13
Done.
|
+ return js.statement('if (# == null) #;', [param, call]); |
+ } |
+ |
JS.Expression notNull(Expression expr) { |
if (expr == null) return null; |
var jsExpr = _visit(expr); |
@@ -5116,10 +5147,17 @@ class CodeGenerator extends Object |
} |
var init = _visit(node.identifier); |
+ var iterable = _visit(node.iterable); |
+ var body = _visitScope(node.body); |
if (init == null) { |
- init = js.call('let #', node.loopVariable.identifier.name); |
+ var name = node.loopVariable.identifier.name; |
+ init = js.call('let #', name); |
+ if (_annotatedNullCheck(node.loopVariable.element)) { |
+ body = |
+ new JS.Block([nullParameterCheck(new JS.Identifier(name)), body]); |
+ } |
} |
- return new JS.ForOf(init, _visit(node.iterable), _visitScope(node.body)); |
+ return new JS.ForOf(init, iterable, body); |
} |
JS.Statement _emitAwaitFor(ForEachStatement node) { |
@@ -5999,3 +6037,6 @@ bool _isDeferredLoadLibrary(Expression target, SimpleIdentifier name) { |
var imports = containingLibrary.getImportsWithPrefix(prefix); |
return imports.length == 1 && imports[0].isDeferred; |
} |
+ |
+bool _annotatedNullCheck(Element e) => |
+ (e != null) && (findAnnotation(e, isNullCheckAnnotation) != null); |
Jennifer Messerly
2017/08/22 21:54:41
fyi, parens not necessary
Leaf
2017/08/23 17:26:14
Done.
|