|  | // TODO(multitest): This was automatically migrated from a multitest and may | 
|  | // contain strange or dead code. | 
|  |  | 
|  | // Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file | 
|  | // for details. All rights reserved. Use of this source code is governed by a | 
|  | // BSD-style license that can be found in the LICENSE file. | 
|  |  | 
|  | // Verify semantics of the ??= operator, including order of operations, by | 
|  | // keeping track of the operations performed. | 
|  |  | 
|  | import "package:expect/expect.dart"; | 
|  | import "assignment_helper.dart" as h; | 
|  |  | 
|  | bad() { | 
|  | Expect.fail('Should not be executed'); | 
|  | } | 
|  |  | 
|  | var xGetValue = null; | 
|  |  | 
|  | get x { | 
|  | h.operations.add('x'); | 
|  | var tmp = xGetValue; | 
|  | xGetValue = null; | 
|  | return tmp; | 
|  | } | 
|  |  | 
|  | void set x(value) { | 
|  | h.operations.add('x=$value'); | 
|  | } | 
|  |  | 
|  | var yGetValue = null; | 
|  |  | 
|  | get y { | 
|  | h.operations.add('y'); | 
|  | var tmp = yGetValue; | 
|  | yGetValue = null; | 
|  | return tmp; | 
|  | } | 
|  |  | 
|  | void set y(value) { | 
|  | h.operations.add('y=$value'); | 
|  | } | 
|  |  | 
|  | var zGetValue = null; | 
|  |  | 
|  | get z { | 
|  | h.operations.add('z'); | 
|  | var tmp = zGetValue; | 
|  | zGetValue = null; | 
|  | return tmp; | 
|  | } | 
|  |  | 
|  | void set z(value) { | 
|  | h.operations.add('z=$value'); | 
|  | } | 
|  |  | 
|  | var fValue = null; | 
|  |  | 
|  | f() { | 
|  | h.operations.add('f()'); | 
|  | var tmp = fValue; | 
|  | fValue = null; | 
|  | return tmp; | 
|  | } | 
|  |  | 
|  | void check(expectedValue, f(), expectedOperations) { | 
|  | Expect.equals(expectedValue, f()); | 
|  | Expect.listEquals(expectedOperations, h.operations); | 
|  | h.operations = []; | 
|  | } | 
|  |  | 
|  | class C { | 
|  | final String s; | 
|  |  | 
|  | C(this.s); | 
|  |  | 
|  | @override | 
|  | String toString() => s; | 
|  |  | 
|  | static var xGetValue = null; | 
|  |  | 
|  | static get x { | 
|  | h.operations.add('C.x'); | 
|  | var tmp = xGetValue; | 
|  | xGetValue = null; | 
|  | return tmp; | 
|  | } | 
|  |  | 
|  | static void set x(value) { | 
|  | h.operations.add('C.x=$value'); | 
|  | } | 
|  |  | 
|  | var vGetValue = null; | 
|  |  | 
|  | get v { | 
|  | h.operations.add('$s.v'); | 
|  | var tmp = vGetValue; | 
|  | vGetValue = null; | 
|  | return tmp; | 
|  | } | 
|  |  | 
|  | void set v(value) { | 
|  | h.operations.add('$s.v=$value'); | 
|  | } | 
|  |  | 
|  | var indexGetValue = null; | 
|  |  | 
|  | operator [](index) { | 
|  | h.operations.add('$s[$index]'); | 
|  | var tmp = indexGetValue; | 
|  | indexGetValue = null; | 
|  | return tmp; | 
|  | } | 
|  |  | 
|  | void operator []=(index, value) { | 
|  | h.operations.add('$s[$index]=$value'); | 
|  | } | 
|  |  | 
|  | final finalOne = 1; | 
|  | final finalNull = null; | 
|  |  | 
|  | void instanceTest() { | 
|  | // v ??= e is equivalent to ((x) => x == null ? v = e : x)(v) | 
|  |  | 
|  |  | 
|  |  | 
|  | yGetValue = 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | class D extends C { | 
|  | D(String s) : super(s); | 
|  |  | 
|  | get v => bad(); | 
|  |  | 
|  | void set v(value) { | 
|  | bad(); | 
|  | } | 
|  |  | 
|  | void derivedInstanceTest() { | 
|  | // super.v ??= e is equivalent to | 
|  | // ((x) => x == null ? super.v = e : x)(super.v) | 
|  |  | 
|  |  | 
|  | } | 
|  | } | 
|  |  | 
|  | main() { | 
|  | // Make sure the "none" test fails if "??=" is not implemented.  This makes | 
|  | // status files easier to maintain. | 
|  | var _; | 
|  | _ ??= null; | 
|  |  | 
|  | new C('c').instanceTest(); | 
|  | new D('d').derivedInstanceTest(); | 
|  |  | 
|  | // v ??= e is equivalent to ((x) => x == null ? v = e : x)(v) | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | { dynamic l = 1; check(1, () => l ??= bad(), []); } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | // C.v ??= e is equivalent to ((x) => x == null ? C.v = e : x)(C.v) | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | // e1.v ??= e2 is equivalent to | 
|  | // ((x) => ((y) => y == null ? x.v = e2 : y)(x.v))(e1) | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | // e1[e2] ??= e3 is equivalent to | 
|  | // ((a, i) => ((x) => x == null ? a[i] = e3 : x)(a[i]))(e1, e2) | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | // e1?.v ??= e2 is equivalent to ((x) => x == null ? null : x.v ??= e2)(e1). | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | // C?.v ??= e2 is equivalent to C.v ??= e2. | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | } |