blob: 1999e17cc6e2d7adc8747d891202c80750a0d7cc [file]
// 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, cascaded 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?..{
return foo;
};
final v2 = (buffer?..{
return foo;
})?..{
return foo;
};
final v3 = (buffer?..{
return foo;
})?.{
return foo;
};
final v4 = (buffer?.{
return foo.orNull;
})?..{
return foo;
};
final v5 = buffer?..{
return foo..{
return foo;
};
};
final v6 = buffer?..{
return foo?..{
return foo;
};
};
final v7 = buffer?..{
return foo.{
return foo;
};
};
final v8 = buffer?.{
return foo?..{
return foo;
};
};
v1.expectStaticType<Exactly<StringBuffer?>>;
v2.expectStaticType<Exactly<StringBuffer?>>;
v3.expectStaticType<Exactly<int?>>;
v4.expectStaticType<Exactly<int?>>;
v5.expectStaticType<Exactly<StringBuffer?>>;
v6.expectStaticType<Exactly<StringBuffer?>>;
v7.expectStaticType<Exactly<StringBuffer?>>;
v8.expectStaticType<Exactly<int?>>;
Expect.equals(buffer, v1);
Expect.equals(buffer, v2);
Expect.equals(foo, v3);
Expect.equals(foo, v4);
Expect.equals(buffer, v5);
Expect.equals(buffer, v6);
Expect.equals(buffer, v7);
Expect.equals(foo, v8);
}
// Dependency on `this`.
{
final v1 = buffer?..{
return this.length;
};
final v2 = (buffer?..{
return this.length;
})?..{
return this.length.isEven ? 'true' : '';
};
final v3 = buffer?..{
return this == buffer;
}..{
return this.length;
};
final v4 = buffer?..{
return this == (buffer?..{
return this.length;
});
};
v1.expectStaticType<Exactly<StringBuffer?>>;
v2.expectStaticType<Exactly<StringBuffer?>>;
v3.expectStaticType<Exactly<StringBuffer?>>;
v4.expectStaticType<Exactly<StringBuffer?>>;
Expect.equals(buffer, v1);
Expect.equals(buffer, v2);
Expect.equals(buffer, v3);
Expect.equals(buffer, v4);
}
// Dependency on implicit `this`.
{
final v1 = buffer?..{
return length;
};
final v2 = (buffer?..{
return length;
})?..{
return length.isEven ? 'true' : '';
};
final v3 = buffer?..{
return length;
}..{
return length;
};
final v4 = buffer?..{
return length.orNull?..{
return isEven;
};
};
v1.expectStaticType<Exactly<StringBuffer?>>;
v2.expectStaticType<Exactly<StringBuffer?>>;
v3.expectStaticType<Exactly<StringBuffer?>>;
v4.expectStaticType<Exactly<StringBuffer?>>;
Expect.equals(buffer, v1);
Expect.equals(buffer, v2);
Expect.equals(buffer, v3);
Expect.equals(buffer, v4);
}
// Dependency on parameter.
{
final v1 = buffer?..(p) {
return p.length;
};
final v2 = (buffer?..(p) {
return p == buffer;
})?..(p) {
return p == buffer ? 'true' : '';
};
final v3 = (buffer?..(p) {
return p == buffer;
})?..(q) {
return q == buffer ? 'true' : '';
};
final v4 = buffer?..(p) {
return p == buffer;
}..(p) {
return p.length;
};
final v5 = buffer?..(p) {
return p == (buffer?..(p) {
return p.length;
});
};
final v6 = buffer?..(p) {
return p == (buffer?..(q) {
return p.length;
});
};
v1.expectStaticType<Exactly<StringBuffer?>>;
v2.expectStaticType<Exactly<StringBuffer?>>;
v3.expectStaticType<Exactly<StringBuffer?>>;
v4.expectStaticType<Exactly<StringBuffer?>>;
v5.expectStaticType<Exactly<StringBuffer?>>;
v6.expectStaticType<Exactly<StringBuffer?>>;
Expect.equals(buffer, v1);
Expect.equals(buffer, v2);
Expect.equals(buffer, v3);
Expect.equals(buffer, v4);
Expect.equals(buffer, v5);
Expect.equals(buffer, v6);
}
// Dependency on parameter with type annotation.
{
final v1 = buffer?..(StringBuffer p) {
return p.length;
};
final v2 = (buffer?..(Object? p) {
return p == buffer;
})?..(StringBuffer p) {
return p.isEmpty ? 'true' : '';
};
final v3 = (buffer?..(Object p) {
return p == buffer;
})?..(StringBuffer q) {
return q.isEmpty ? 'true' : '';
};
final v4 = buffer?..(Object p) {
return p == 1;
}..(StringBuffer p) {
return p.length;
};
final v5 = buffer?..(Object p) {
return p == (1?..(int p) {
return p.isEven;
});
};
final v6 = buffer?..(StringBuffer p) {
return p == (1?..(q) {
return p.length;
});
};
v1.expectStaticType<Exactly<StringBuffer?>>;
v2.expectStaticType<Exactly<StringBuffer?>>;
v3.expectStaticType<Exactly<StringBuffer?>>;
v4.expectStaticType<Exactly<StringBuffer?>>;
v5.expectStaticType<Exactly<StringBuffer?>>;
v6.expectStaticType<Exactly<StringBuffer?>>;
Expect.equals(buffer, v1);
Expect.equals(buffer, v2);
Expect.equals(buffer, v3);
Expect.equals(buffer, v4);
Expect.equals(buffer, v5);
Expect.equals(buffer, v6);
}
// Example using two kinds of null aware access.
final aThenBIgnoringBody = a?.b?..{
return hasDays() ? days : null;
};
aThenBIgnoringBody.expectStaticType<Exactly<B?>>;
}