blob: 8b6c231e88b5bf5fb33c48cad96ca6c8e6b3231e [file] [log] [blame]
// Copyright (c) 2026, 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.
// Anonymous methods using null-aware accesses.
// SharedOptions=--enable-experiment=anonymous-methods
import 'package:expect/expect.dart';
import '../../static_type_helper.dart';
StringBuffer? buffer = StringBuffer(''); // `length` remains 0.
StringBuffer? notBuffer = null;
int foo = 42;
int? notFoo = null;
extension<X extends Object> on X {
X? get orNull => this;
}
class A {
B? get b => B();
}
class B {
bool hasDays() => true;
int get days => 1;
}
A? a = A();
void main() {
// No dependency on `this` or parameters.
{
final v1 = buffer?.=> foo;
final v2 = (buffer?.=> foo)?.=> foo;
final v3 = buffer?.=> foo.orNull?.=> foo;
v1.expectStaticType<Exactly<int?>>;
v2.expectStaticType<Exactly<int?>>;
v3.expectStaticType<Exactly<int?>>;
Expect.equals(foo, v1);
Expect.equals(foo, v2);
Expect.equals(foo, v3);
}
// No dependency on `this` or parameters, condition fails.
{
final v1 = notBuffer?.=> foo;
final v2 = (notBuffer?.=> foo)?.=> foo;
final v3 = (buffer?.=> notFoo)?.=> foo;
final v4 = notBuffer?.=> foo.orNull?.=> foo;
final v5 = buffer?.=> notFoo?.=> foo;
v1.expectStaticType<Exactly<int?>>;
v2.expectStaticType<Exactly<int?>>;
v3.expectStaticType<Exactly<int?>>;
v4.expectStaticType<Exactly<int?>>;
v5.expectStaticType<Exactly<int?>>;
Expect.equals(null, v1);
Expect.equals(null, v2);
Expect.equals(null, v3);
Expect.equals(null, v4);
Expect.equals(null, v5);
}
// Dependency on `this`.
{
final v1 = buffer?.=> this.length;
final v2 = (buffer?.=> this.length)?.=> this.isEven ? 'true' : '';
final v3 = buffer?.=> this.length == buffer?.=> this.length;
v1.expectStaticType<Exactly<int?>>;
v2.expectStaticType<Exactly<String?>>;
v3.expectStaticType<Exactly<bool?>>;
Expect.equals(buffer?.length, v1);
Expect.equals('true', v2);
Expect.equals(true, v3);
}
// Dependency on implicit `this`.
{
final v1 = buffer?.=> length;
final v2 = (buffer?.=> length)?.=> isEven ? 'true' : '';
final v3 = buffer?.=> length.orNull?.=> isEven;
v1.expectStaticType<Exactly<int?>>;
v2.expectStaticType<Exactly<String?>>;
v3.expectStaticType<Exactly<bool?>>;
Expect.equals(buffer?.length, v1);
Expect.equals('true', v2);
Expect.equals(false, v3);
}
// Dependency on parameter.
{
final v1 = buffer?.(p) => p.length;
final v2 = (buffer?.(p) => p == buffer)?.(p) => p ? 'true' : '';
final v3 = (buffer?.(p) => p == buffer)?.(q) => q ? 'true' : '';
final v4 = buffer?.(p) => p == buffer?.(p) => p.length;
final v5 = buffer?.(p) => p == buffer?.(q) => p.length;
v1.expectStaticType<Exactly<int?>>;
v2.expectStaticType<Exactly<String?>>;
v3.expectStaticType<Exactly<String?>>;
v4.expectStaticType<Exactly<bool?>>;
v5.expectStaticType<Exactly<bool?>>;
Expect.equals(buffer?.length, v1);
Expect.equals('true', v2);
Expect.equals('true', v3);
Expect.equals(false, v4);
Expect.equals(false, v5);
}
// Dependency on parameter with type annotation.
{
final v1 = buffer?.(StringBuffer p) => p.length;
final v2 = (buffer?.(Object? p) => p == buffer)
?.(bool p) => p ? 'true' : '';
final v3 = (buffer?.(Object p) => p == buffer)?.(bool q) => q ? 'true' : '';
final v4 = buffer?.(Object p) => p == buffer?.(StringBuffer p) => p.length;
final v5 = buffer?.(StringBuffer p) => p == buffer?.(q) => p.length;
v1.expectStaticType<Exactly<int?>>;
v2.expectStaticType<Exactly<String?>>;
v3.expectStaticType<Exactly<String?>>;
v4.expectStaticType<Exactly<bool?>>;
v5.expectStaticType<Exactly<bool?>>;
Expect.equals(buffer?.length, v1);
Expect.equals('true', v2);
Expect.equals('true', v3);
Expect.equals(false, v4);
Expect.equals(false, v5);
}
// Example using two kinds of null aware access.
int? daysOfAThenB = a?.b?.=> hasDays() ? days : null;
Expect.equals(1, daysOfAThenB);
}