Skip to content

Commit

Permalink
implement null aware ops, fixes #249
Browse files Browse the repository at this point in the history
this also implements multitest support, which fixes #280

Fixes some other preexisting bugs:
* MetaLets did not simplify themselves correctly in some nested cases
* Library prefixed identifiers did not work as lvalues in opassign
* dsetindex/dput/[]= methods did not return a value
* checker did not correctly handle invalid constructor field initializers
* cascades did not correctly work with method invocations(?)
* postfix ++/-- did not correctly generate lvalues in some cases

The good news: because this reuses on our existing lvalue/metalet helpers, it managed to flush out a lot of bugs in other features that use them.

R=vsm@google.com

Review URL: https://codereview.chromium.org/1316723003 .
  • Loading branch information
John Messerly committed Aug 25, 2015
1 parent 50eb282 commit 74c7600
Show file tree
Hide file tree
Showing 31 changed files with 1,490 additions and 59 deletions.
1 change: 1 addition & 0 deletions pkg/dev_compiler/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ node_modules
test/codegen/expect/dev_compiler/
test/codegen/expect/language/
test/codegen/expect/sunflower/dev_compiler/
test/codegen/language/*_multi.dart

# Created by ./tool/build_sdk.sh
tool/generated_sdk/
Expand Down
21 changes: 20 additions & 1 deletion pkg/dev_compiler/lib/runtime/_operations.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ dart_library.library('dart_runtime/_operations', null, /* Imports */[
// TODO(vsm): Implement NSM and type checks.
// See: https://github.com/dart-lang/dev_compiler/issues/170
obj[field] = value;
return value;
}
exports.dput = dput;

Expand Down Expand Up @@ -168,7 +169,8 @@ dart_library.library('dart_runtime/_operations', null, /* Imports */[
exports.dindex = dindex;

function dsetindex(obj, index, value) {
return callMethod(obj, 'set', [index, value], '[]=');
callMethod(obj, 'set', [index, value], '[]=');
return value;
}
exports.dsetindex = dsetindex;

Expand Down Expand Up @@ -318,6 +320,23 @@ dart_library.library('dart_runtime/_operations', null, /* Imports */[
}
exports.stackTrace = stackTrace;

/**
* Implements a sequence of .? operations.
*
* Will call each successive callback, unless one returns null, which stops
* the sequence.
*/
function nullSafe(obj /*, ...callbacks*/) {
let callbacks = slice.call(arguments, 1);
if (obj == null) return obj;
for (const callback of callbacks) {
obj = callback(obj);
if (obj == null) break;
}
return obj;
}
exports.nullSafe = nullSafe;

let _value = Symbol('_value');
/**
* Looks up a sequence of [keys] in [map], recursively, and
Expand Down
1 change: 1 addition & 0 deletions pkg/dev_compiler/lib/runtime/dart/_interceptors.js
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ dart_library.library('dart/_interceptors', null, /* Imports */[
if (dart.notNull(index) >= dart.notNull(this[dartx.length]) || dart.notNull(index) < 0)
dart.throw(new core.RangeError.value(index));
this[index] = value;
return value;
}
[dartx.asMap]() {
return new (_internal.IterableMixinWorkaround$(E))().asMapList(this);
Expand Down
2 changes: 2 additions & 0 deletions pkg/dev_compiler/lib/runtime/dart/_internal.js
Original file line number Diff line number Diff line change
Expand Up @@ -1655,6 +1655,7 @@ dart_library.library('dart/_internal', null, /* Imports */[
set(index, value) {
dart.as(value, E);
dart.throw(new core.UnsupportedError("Cannot modify an unmodifiable list"));
return value;
}
set length(newLength) {
dart.throw(new core.UnsupportedError("Cannot change the length of an unmodifiable list"));
Expand Down Expand Up @@ -1857,6 +1858,7 @@ dart_library.library('dart/_internal', null, /* Imports */[
set(key, value) {
dart.as(value, E);
dart.throw(new core.UnsupportedError("Cannot modify an unmodifiable map"));
return value;
}
putIfAbsent(key, ifAbsent) {
dart.as(ifAbsent, dart.functionType(E, []));
Expand Down
5 changes: 5 additions & 0 deletions pkg/dev_compiler/lib/runtime/dart/_native_typed_data.js
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ dart_library.library('dart/_native_typed_data', null, /* Imports */[
this[_storage].set(dart.notNull(index) * 4 + 1, value.y);
this[_storage].set(dart.notNull(index) * 4 + 2, value.z);
this[_storage].set(dart.notNull(index) * 4 + 3, value.w);
return value;
}
sublist(start, end) {
if (end === void 0)
Expand Down Expand Up @@ -340,6 +341,7 @@ dart_library.library('dart/_native_typed_data', null, /* Imports */[
this[_storage].set(dart.notNull(index) * 4 + 1, value.y);
this[_storage].set(dart.notNull(index) * 4 + 2, value.z);
this[_storage].set(dart.notNull(index) * 4 + 3, value.w);
return value;
}
sublist(start, end) {
if (end === void 0)
Expand Down Expand Up @@ -442,6 +444,7 @@ dart_library.library('dart/_native_typed_data', null, /* Imports */[
this[_checkIndex](index, this.length);
this[_storage].set(dart.notNull(index) * 2 + 0, value.x);
this[_storage].set(dart.notNull(index) * 2 + 1, value.y);
return value;
}
sublist(start, end) {
if (end === void 0)
Expand Down Expand Up @@ -745,6 +748,7 @@ dart_library.library('dart/_native_typed_data', null, /* Imports */[
set(index, value) {
this[_checkIndex](index, this.length);
this[index] = value;
return value;
}
setRange(start, end, iterable, skipCount) {
if (skipCount === void 0)
Expand All @@ -771,6 +775,7 @@ dart_library.library('dart/_native_typed_data', null, /* Imports */[
set(index, value) {
this[_checkIndex](index, this.length);
this[index] = value;
return value;
}
setRange(start, end, iterable, skipCount) {
if (skipCount === void 0)
Expand Down
4 changes: 2 additions & 2 deletions pkg/dev_compiler/lib/runtime/dart/async.js
Original file line number Diff line number Diff line change
Expand Up @@ -863,8 +863,8 @@ dart_library.library('dart/async', null, /* Imports */[
let _cancelFuture = Symbol('_cancelFuture');
let _pending = Symbol('_pending');
let _setPendingEvents = Symbol('_setPendingEvents');
let _extractPending = Symbol('_extractPending');
let _isCanceled = Symbol('_isCanceled');
let _extractPending = Symbol('_extractPending');
let _isPaused = Symbol('_isPaused');
let _isInputPaused = Symbol('_isInputPaused');
let _inCallback = Symbol('_inCallback');
Expand All @@ -884,8 +884,8 @@ dart_library.library('dart/async', null, /* Imports */[
let _sendData = Symbol('_sendData');
let _addPending = Symbol('_addPending');
let _sendError = Symbol('_sendError');
let _close = Symbol('_close');
let _sendDone = Symbol('_sendDone');
let _close = Symbol('_close');
let _checkState = Symbol('_checkState');
let _BufferingStreamSubscription$ = dart.generic(function(T) {
class _BufferingStreamSubscription extends core.Object {
Expand Down
33 changes: 21 additions & 12 deletions pkg/dev_compiler/lib/runtime/dart/collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -2290,6 +2290,7 @@ dart_library.library('dart/collection', null, /* Imports */[
dart.as(key, K);
dart.as(value, V);
dart.throw(new core.UnsupportedError("Cannot modify unmodifiable map"));
return value;
}
addAll(other) {
dart.as(other, core.Map$(K, V));
Expand Down Expand Up @@ -2414,6 +2415,7 @@ dart_library.library('dart/collection', null, /* Imports */[
dart.as(key, K);
dart.as(value, V);
this[_map].set(key, value);
return value;
}
addAll(other) {
dart.as(other, core.Map$(K, V));
Expand Down Expand Up @@ -3324,8 +3326,8 @@ dart_library.library('dart/collection', null, /* Imports */[
let _root = Symbol('_root');
let _count = Symbol('_count');
let _splayCount = Symbol('_splayCount');
let _splay = Symbol('_splay');
let _compare = Symbol('_compare');
let _splay = Symbol('_splay');
let _splayMin = Symbol('_splayMin');
let _splayMax = Symbol('_splayMax');
let _addNewRoot = Symbol('_addNewRoot');
Expand Down Expand Up @@ -3561,17 +3563,20 @@ dart_library.library('dart/collection', null, /* Imports */[
return null;
}
set(key, value) {
dart.as(key, K);
dart.as(value, V);
if (key == null)
dart.throw(new core.ArgumentError(key));
let comp = this[_splay](key);
if (comp == 0) {
let mapRoot = dart.as(this[_root], _SplayTreeMapNode);
mapRoot.value = value;
return;
}
this[_addNewRoot](new (_SplayTreeMapNode$(K, dart.dynamic))(key, value), comp);
((() => {
dart.as(key, K);
dart.as(value, V);
if (key == null)
dart.throw(new core.ArgumentError(key));
let comp = this[_splay](key);
if (comp == 0) {
let mapRoot = dart.as(this[_root], _SplayTreeMapNode);
mapRoot.value = value;
return;
}
this[_addNewRoot](new (_SplayTreeMapNode$(K, dart.dynamic))(key, value), comp);
}).bind(this))();
return value;
}
putIfAbsent(key, ifAbsent) {
dart.as(key, K);
Expand Down Expand Up @@ -4227,6 +4232,7 @@ dart_library.library('dart/collection', null, /* Imports */[
} else {
this[_set](key, value);
}
return value;
}
[_set](key, value) {
dart.as(key, K);
Expand Down Expand Up @@ -4489,6 +4495,7 @@ dart_library.library('dart/collection', null, /* Imports */[
dart.as(key, K);
dart.as(value, V);
super[_set](key, value);
return value;
}
containsKey(key) {
if (!dart.notNull(this[_validKey](key)))
Expand Down Expand Up @@ -4718,6 +4725,7 @@ dart_library.library('dart/collection', null, /* Imports */[
} else {
this[_set](key, value);
}
return value;
}
[_set](key, value) {
dart.as(key, K);
Expand Down Expand Up @@ -4970,6 +4978,7 @@ dart_library.library('dart/collection', null, /* Imports */[
dart.as(key, K);
dart.as(value, V);
super[_set](key, value);
return value;
}
containsKey(key) {
if (!dart.notNull(this[_validKey](key)))
Expand Down
1 change: 1 addition & 0 deletions pkg/dev_compiler/lib/runtime/dart/convert.js
Original file line number Diff line number Diff line change
Expand Up @@ -2665,6 +2665,7 @@ dart_library.library('dart/convert', null, /* Imports */[
} else {
this[_upgrade]().set(key, value);
}
return value;
}
addAll(other) {
other.forEach(dart.fn(((key, value) => {
Expand Down
1 change: 1 addition & 0 deletions pkg/dev_compiler/lib/runtime/dart/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -1179,6 +1179,7 @@ dart_library.library('dart/core', null, /* Imports */[
_js_helper.Primitives.setProperty(object, Expando$()._EXPANDO_PROPERTY_NAME, values);
}
_js_helper.Primitives.setProperty(values, this[_getKey](), value);
return value;
}
[_getKey]() {
let key = dart.as(_js_helper.Primitives.getProperty(this, Expando$()._KEY_PROPERTY_NAME), String);
Expand Down
2 changes: 2 additions & 0 deletions pkg/dev_compiler/lib/runtime/dart/js.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ dart_library.library('dart/js', null, /* Imports */[
dart.throw(new core.ArgumentError("property is not a String or num"));
}
this[_jsObject][property] = _convertToJS(value);
return value;
}
get hashCode() {
return 0;
Expand Down Expand Up @@ -212,6 +213,7 @@ dart_library.library('dart/js', null, /* Imports */[
this[_checkIndex](index);
}
super.set(index, value);
return value;
}
get length() {
let len = this[_jsObject].length;
Expand Down
1 change: 1 addition & 0 deletions pkg/dev_compiler/lib/runtime/dart_runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ dart_library.library('dart_runtime/dart', null, /* Imports */[
'map',
'noSuchMethod',
'notNull',
'nullSafe',
'stackPrint',
'stackTrace',
'strongInstanceOf',
Expand Down
5 changes: 4 additions & 1 deletion pkg/dev_compiler/lib/src/checker/checker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,8 @@ class CodeChecker extends RecursiveAstVisitor {
@override
void visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
var field = node.fieldName;
DartType staticType = rules.elementType(field.staticElement);
var element = field.staticElement;
DartType staticType = rules.elementType(element);
checkAssignment(node.expression, staticType);
node.visitChildren(this);
}
Expand Down Expand Up @@ -792,6 +793,8 @@ class CodeChecker extends RecursiveAstVisitor {
break;
case TokenType.BANG_EQ:
break;
case TokenType.QUESTION_QUESTION:
break;
default:
assert(false);
}
Expand Down
16 changes: 16 additions & 0 deletions pkg/dev_compiler/lib/src/codegen/ast_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,18 @@ class AstBuilder {
return parenthesizedExpression(exp);
}

static PropertyAccess propertyAccess(
Expression target, SimpleIdentifier name) {
var p = new Token(TokenType.PERIOD, 0);
return new PropertyAccess(target, p, name);
}

static MethodInvocation methodInvoke(
Expression target, SimpleIdentifier name, NodeList<Expression> args) {
var p = new Token(TokenType.PERIOD, 0);
return new MethodInvocation(target, p, name, null, argumentList(args));
}

static TokenType getTokenType(String lexeme) {
switch (lexeme) {
case "&":
Expand Down Expand Up @@ -218,6 +230,10 @@ class AstBuilder {
return TokenType.BACKSLASH;
case "...":
return TokenType.PERIOD_PERIOD_PERIOD;
case "??":
return TokenType.QUESTION_QUESTION;
case "??=":
return TokenType.QUESTION_QUESTION_EQ;
default:
return null;
}
Expand Down
Loading

0 comments on commit 74c7600

Please sign in to comment.