blob: 46f758baa6e39bd79a3a08c79f57735140a81d18 [file] [log] [blame]
// Copyright (c) 2011, 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.
/// @assertion Let d be the declaration of a variable v. If d is a local or
/// instance variable, then the invocation of the implicit getter of v
/// evaluates to the value stored in v.
/// If d is a static or library variable then the implicit getter method of v
/// executes as follows:
/// - Non-constant variable declaration with initializer. If d is of one of the
/// forms var v = e; , T v = e; , final v = e; , final T v = e; , static
/// v = e; , static T v = e; , static final v = e; or static final T v = e;
/// and no value has yet been stored into v then the initializer expression
/// e is evaluated. If, during the evaluation of e, the getter for v is
/// invoked, a CyclicInitializationError is thrown. If the evaluation
/// succeeded yielding an object o, let r = o, otherwise let r = null. In
/// any case, r is stored into v. The result of executing the getter is r.
/// - Constant variable declaration. If d is of one of the forms const v = e; ,
/// const T v = e; , static const v = e; or static const T v = e; the result
/// of the getter is the value of the compile time constant e. Note that a
/// compile time constant cannot depend on itself, so no cyclic references
/// can occur. Otherwise
/// - Variable declaration without initializer. The result of executing the
/// getter method is the value stored in v.
/// @note NNBD Spec now reads: If a variable or field is read from during the
/// process of evaluating its own initializer expression, and no write to the
/// variable has occurred, the read is treated as a first read and the
/// nitializer expression is evaluated again.
///
/// A toplevel or static variable with an initializer is evaluated as if it was
/// marked [late]. Note that this is a change from pre-NNBD semantics in that:
///
/// Throwing an exception during initializer evaluation no longer sets the
/// variable to [null]
///
/// Reading the variable during initializer evaluation is no longer checked for,
/// and does not cause an error.
///
/// @description Checks that if during the evaluation of [e], the getter for [v]
/// is invoked, a [CyclicInitializationError] is not thrown. Confirms that [func]
/// gets recursively called by incrementing a counter and stopping the infinite
/// recursion after 20 cycles. This avoids relying on particulars of the behavior
/// on stack overflow and makes the test cheaper to run.
/// @author msyabro
/// @Issue 42470
/// @issue 42642
import "../../../Utils/expect.dart";
int count = 0;
f(func) {
try {
throw 1; // caught exceptions do not matter
} on int catch (_) {
count++;
if (count < 20) func();
}
count = 0;
}
class C {
static int? sTyped = f(() => sTyped);
static final int? sFinalTyped = f(() => sFinalTyped);
}
main() {
() => C.sTyped;
Expect.equals(null, C.sTyped);
() => C.sFinalTyped;
Expect.throws(() { C.sFinalTyped; });
}