feat(change_detection): allow all legal programs in the dev mode

BEFORE:

The following would throw in the dev mode because `f` would return a new array when called by checkNoChanges.

@Component({
  template: `
    {{f()}}
  `
})
class A {
  f() { return [1]; }
}

AFTER:

The checkNoChanges function compares only primitives types for equality, and deeply compares iterables. Other objects cannot cause checkNoChanges to throw. This means that the dev mode would never fail given a legal program, but may allow some illegal programs.
This commit is contained in:
vsavkin
2016-01-05 13:42:21 -08:00
committed by Rado Kirov
parent db87baeb98
commit 42231f5719
10 changed files with 141 additions and 12 deletions

View File

@ -433,6 +433,7 @@ class _CodegenState {
var condition = '''!${pipe}.pure || (${contexOrArgCheck.join(" || ")})''';
var check = '''
${_genThrowOnChangeCheck(oldValue, newValue)}
if (${_genPrefix}$_UTIL.looseNotIdentical($oldValue, $newValue)) {
$newValue = ${_genPrefix}$_UTIL.unwrapValue($newValue);
${_genChangeMarker(r)}
@ -459,6 +460,7 @@ class _CodegenState {
''';
var check = '''
${_genThrowOnChangeCheck(oldValue, newValue)}
if (${_genPrefix}$_UTIL.looseNotIdentical($newValue, $oldValue)) {
${_genChangeMarker(r)}
${_genUpdateDirectiveOrElement(r)}
@ -492,7 +494,6 @@ class _CodegenState {
if (!r.lastInBinding) return '';
var newValue = _names.getLocalName(r.selfIndex);
var oldValue = _names.getFieldName(r.selfIndex);
var notifyDebug = _genConfig.logBindingUpdate
? "this.logBindingUpdate(${newValue});"
: "";
@ -502,14 +503,12 @@ class _CodegenState {
var directiveProperty =
'${_names.getDirectiveName(br.directiveRecord.directiveIndex)}.${br.target.name}';
return '''
${_genThrowOnChangeCheck(oldValue, newValue)}
$directiveProperty = $newValue;
${notifyDebug}
$_IS_CHANGED_LOCAL = true;
''';
} else {
return '''
${_genThrowOnChangeCheck(oldValue, newValue)}
this.notifyDispatcher(${newValue});
${notifyDebug}
''';
@ -518,7 +517,7 @@ class _CodegenState {
String _genThrowOnChangeCheck(String oldValue, String newValue) {
return '''
if(${_genPrefix}assertionsEnabled() && throwOnChange) {
if(${_genPrefix}assertionsEnabled() && throwOnChange && !${_genPrefix}${_UTIL}.devModeEqual(${oldValue}, ${newValue})) {
this.throwOnChangeError(${oldValue}, ${newValue});
}
''';