blob: 20920568b9489f2dae05f0c8cba33e18dae0127e [file] [log] [blame]
// Copyright (c) 2021, 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 The language specification says 'If, during the evaluation of [e]
* (which is the initializing expression for [v]), the getter for [v] is invoked,
* a [CyclicInitializationError] is thrown', but this is overridden by the
* following text in the nnbd feature specification: '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 initializer expression is evaluated again.'
* So CyclicInitializationErrors are gone here when null safety is enabled.
* In the test, [f] returns [null] (typed as [dynamic]), and the evaluation of
* the initializing expression for [sVar] as well as [sFinal] discards the
* function literal (() => sVar respectively () => sFinal) without ever
* executing it. So we do not have a situation where the getter for
* [sVar]/[sFinal] is invoked during the evaluation of its initializing
* expression, and both variables just get initialized to the value [null]. No
* recursion and no errors.
*
* @description Checks that [CyclicInitializationError] is not thrown with null
* safety turned on.
*
* @author sgrekhov@unipro.ru
*/
f(func) {}
class C {
static var sVar = f(() => sVar);
static final sFinal = f(() => sFinal);
}
main() {
C? c;
}