diff --git a/Language/Expressions/Function_Invocation/Function_Expression_Invocation/call_A04_t01.dart b/Language/Expressions/Function_Invocation/Function_Expression_Invocation/call_A04_t01.dart new file mode 100644 index 0000000000..44f057d0f0 --- /dev/null +++ b/Language/Expressions/Function_Invocation/Function_Expression_Invocation/call_A04_t01.dart @@ -0,0 +1,182 @@ +// Copyright (c) 2025, 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 A function expression invocation i has the form +/// ef (a1, . . . , an, xn+1: an+1, . . . , xn+k: an+k), +/// where ef is an expression. +/// ... +/// Let F be the static type of ef . If F is an interface type that has a method +/// named call, i is treated as the ordinary invocation +/// ef .call(a1, . . . , an, xn+1: an+1, . . . , xn+k: an+k) +/// +/// @description Checks that an implicit invocation of a `.call()` invokes an +/// appropriate function. +/// @author sgrekhov22@gmail.com +/// @author lrhn +/// @issue 59952 + +// See https://github.com/dart-lang/sdk/issues/55803#issuecomment-2124182059 + +import '../../../../Utils/expect.dart'; + +void main() { + // Real functions, invoked typed or dynamic. + check = expr(good, "function")(42); + check = expr(good, "function as Function")(42); + check = expr(good, "function as dynamic")(42); + + // These implicit `.call` invocations should work: + + // Callable types. + check = expr(C())(42); + check = expr(MC())(42); + check = expr(E.instance)(42); + check = expr(ET(null), "ET")(42); + check = expr(NSMC())(42); // NSM-forwarder as call method. + // Extension types inheriting those call methods. + check = expr(C())(42); + check = expr(MC())(42); + check = expr(E.instance)(42); + check = expr(ET(null), "ET")(42); + check = expr(NSMC())(42); // NSM-forwarder as call method. + // Callable extension methods. + check = expr(EC())(42); + check = expr(EMC())(42); + check = expr(EE.instance)(42); + check = expr(EET(null), "EET")(42); + + // These implicit tear-offs of callable types should work. + tearoff = expr(C()); + tearoff = expr(MC()); + tearoff = expr(E.instance); + tearoff = expr(ET(null), "ET"); + tearoff = expr(NSMC()); // NSM-forwarder as call method. + + // Dynamic invocations of callable (non-extension/extension-type types). + check = expr(C(), "C as dynamic")(42); + check = expr(MC(), "M as dynamic")(42); + check = expr(E.instance, "E as dynamic")(42); + check = expr(NSMC(), "NSMC as dynamic")(42); + // Dynamic invocation going to NSM with no forwarder, as method. + check = expr(NSMD(), "NSMD as dynamic")(42); + // Dynamic invocation going to NSM even if call getter, as method. + check = expr(BNSMC(), "BNSMC as dynamic")(42); // sdk#59952 +} + +String name = ""; + +int good(int x) => x; +int bad(int x) => 100 + x; + +T expr([Object? value, String? typeName]) { + name = typeName ?? "$T"; + return value as T; +} + +void set check(int result) { + Expect.isTrue(result < 100, "$name.call(): WRONG: $result"); +} + +void set tearoff(int Function(int) to) { + var result = to(42); + Expect.isTrue(result < 100, "$name.call(): WRONG: $result"); +} + +class C { + int call(int x) => x; +} + +mixin M { + int call(int x) => x; +} +class MC = Object with M; + +enum E { + instance; + + int call(int x) => x; +} + +extension type const ET(Object? _) { + int call(int x) => x; +} + +class NSMC { + int call(int x); + Object? noSuchMethod(Invocation i) { + if (i.memberName == #call) { + if (i.isMethod) { + return i.positionalArguments.first; + } else if (i.isGetter) { + return bad; + } + } + return super.noSuchMethod(i); + } +} + +// Inherited `call` methods on extension types. +extension type ETC(C _) implements C {} +extension type ETM(M _) implements M {} +extension type ETE(E _) implements E {} +extension type ETET(ET _) implements ET {} +extension type ETNSMC(NSMC _) implements NSMC {} + +class NSMD { + const NSMD(); + // No `call` member declared at all, can only be invoked dynamically. + noSuchMethod(i) { + if (i.memberName == #call) { + if (i.isMethod) { + return i.positionalArguments.first; + } else if (i.isGetter) { + return bad; + } + } + return super.noSuchMethod(i); + } +} + +class EC {} + +extension on EC { + int call(int x) => 43; +} + +enum EE { + instance; +} + +extension on EE { + int call(int x) => 43; +} + +mixin EM {} +class EMC = Object with EM; + +extension on EM { + int call(int x) => 43; +} + +extension type EET(Object? _) {} + +extension on EET { + int call(int x) => 43; +} + +// "Bad" type, no `call` method, only a call getter. +class BNSMC { + // Should be NSM-forwarder. + int Function(int) get call; + Object? noSuchMethod(Invocation i) { + if (i.memberName == #call) { + if (i.isMethod) { + return i.positionalArguments.first; + } else if (i.isGetter) { + return bad; + } + } + return super.noSuchMethod(i); + } +} diff --git a/Language/Expressions/Function_Invocation/Function_Expression_Invocation/call_A04_t02.dart b/Language/Expressions/Function_Invocation/Function_Expression_Invocation/call_A04_t02.dart new file mode 100644 index 0000000000..4b96a53c79 --- /dev/null +++ b/Language/Expressions/Function_Invocation/Function_Expression_Invocation/call_A04_t02.dart @@ -0,0 +1,59 @@ +// Copyright (c) 2025, 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 A function expression invocation i has the form +/// ef (a1, . . . , an, xn+1: an+1, . . . , xn+k: an+k), +/// where ef is an expression. +/// ... +/// Let F be the static type of ef . If F is an interface type that has a method +/// named call, i is treated as the ordinary invocation +/// ef .call(a1, . . . , an, xn+1: an+1, . . . , xn+k: an+k) +/// +/// @description Checks that it is a runtime error to implicitly invoke a +/// `.call()` method on a type which has a `call` getter only. +/// @author sgrekhov22@gmail.com +/// @author lrhn +/// @issue 59965 + +// See https://github.com/dart-lang/sdk/issues/55803#issuecomment-2124182059 + +import '../../../../Utils/expect.dart'; + +void main() { + // These dynamic invocations should fail at runtime + // (dynamic invocation with `call` getter). + Expect.throws(() { + (BC() as dynamic)(42); + }, null, "BC as dynamic did not throw"); + Expect.throws(() { + (BMC() as dynamic)(42); + }, null, "BM as dynamic did not throw"); + Expect.throws(() { + (BE.instance as dynamic)(42); + }, null, "BE as dynamic did not throw"); + Expect.throws(() { + (rec as dynamic)(42); + }, null, "Record as dynamic did not throw"); +} + +int foo(int x) => x; + + +// "Bad" types, no `call` method, only a call getter. +class BC { + int Function(int) get call => foo; +} + +mixin BM { + int Function(int) get call => foo; +} +class BMC = Object with BM; + +enum BE { + instance; + + int Function(int) get call => foo; +} + +({int Function(int) call}) rec = (call: foo); diff --git a/Language/Expressions/Function_Invocation/Function_Expression_Invocation/call_A04_t03.dart b/Language/Expressions/Function_Invocation/Function_Expression_Invocation/call_A04_t03.dart new file mode 100644 index 0000000000..9f446b51fe --- /dev/null +++ b/Language/Expressions/Function_Invocation/Function_Expression_Invocation/call_A04_t03.dart @@ -0,0 +1,100 @@ +// Copyright (c) 2025, 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 A function expression invocation i has the form +/// ef (a1, . . . , an, xn+1: an+1, . . . , xn+k: an+k), +/// where ef is an expression. +/// ... +/// Let F be the static type of ef . If F is an interface type that has a method +/// named call, i is treated as the ordinary invocation +/// ef .call(a1, . . . , an, xn+1: an+1, . . . , xn+k: an+k) +/// +/// @description Checks that it is a compile-time error to invoke a `call()` +/// method on a type which has an instance getter named `call`. +/// @author sgrekhov22@gmail.com +/// @author lrhn +/// @issue 59963 +/// @issue 59964 + +// See https://github.com/dart-lang/sdk/issues/55803#issuecomment-2124182059 + +void main() { + // These should not compile, call is a getter. + // Instance getter. + expr(BC())(42); +//^^^^^^^^^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + expr(BMC())(42); +//^^^^^^^^^^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + expr(BE.instance)(42); +//^^^^^^^^^^^^^^^^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + expr(BET(null), "BET")(42); // sdk#59963 +//^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + expr(BERT(bad), "BERT")(42); // sdk#59963 +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + expr(BNSMC())(42); +//^^^^^^^^^^^^^^^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + expr(NSMD())(42); +//^^^^^^^^^^^^^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + expr<({int Function(int) call})>(rec, "record")(42); // sdk#59964 +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified +} + +T expr([Object? value, String? typeName]) { + return value as T; +} + +int foo(int x) => x; + +({int Function(int) call}) rec = (call: foo); + +// "Bad" types, no `call` method, only a call getter. +class BC { + int Function(int) get call => foo; +} + +mixin BM { + int Function(int) get call => foo; +} +class BMC = Object with BM; + +enum BE { + instance; + + int Function(int) get call => foo; +} + +extension type BET(Null _) { + int Function(int) get call => foo; +} + +// Representation type getter is a getter. +extension type BERT(int Function(int) call) {} + +class BNSMC { + // Should be NSM-forwarder. + int Function(int) get call; + Object? noSuchMethod(Invocation i) => null; +} + +class NSMD { + const NSMD(); + // No `call` member declared at all, can only be invoked dynamically. + Object? noSuchMethod(i) => null; +} diff --git a/Language/Expressions/Function_Invocation/Function_Expression_Invocation/call_A04_t04.dart b/Language/Expressions/Function_Invocation/Function_Expression_Invocation/call_A04_t04.dart new file mode 100644 index 0000000000..68ef8faa24 --- /dev/null +++ b/Language/Expressions/Function_Invocation/Function_Expression_Invocation/call_A04_t04.dart @@ -0,0 +1,75 @@ +// Copyright (c) 2025, 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 A function expression invocation i has the form +/// ef (a1, . . . , an, xn+1: an+1, . . . , xn+k: an+k), +/// where ef is an expression. +/// ... +/// Let F be the static type of ef . If F is an interface type that has a method +/// named call, i is treated as the ordinary invocation +/// ef .call(a1, . . . , an, xn+1: an+1, . . . , xn+k: an+k) +/// +/// @description Checks that it is a compile-time error to invoke a `call()` +/// method on a type which has an extension getter named `call`. +/// @author sgrekhov22@gmail.com +/// @author lrhn +/// @issue 59962 + +// See https://github.com/dart-lang/sdk/issues/55803#issuecomment-2124182059 + +void main() { + // These should not compile, call is a getter. + // Extension getter. + expr(BEC())(42); +//^^^^^^^^^^^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + expr(BEMC())(42); +//^^^^^^^^^^^^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + expr(BEE.instance)(42); +//^^^^^^^^^^^^^^^^^^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + expr(BEET(null), "EET")(42); +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified +} + +T expr([Object? value, String? typeName]) { + return value as T; +} + +// "Bad" types, no `call` method, only a call getter. +// Empty types with `call` extension getters. +class BEC {} + +extension on BEC { + int Function(int) get call => foo; +} + +enum BEE { + instance; +} + +extension on BEE { + int Function(int) get call => foo; +} + +mixin BEM {} +class BEMC = Object with BEM; + +extension on BEM { + int Function(int) get call => foo; +} + +extension type const BEET(Null _) {} + +extension on BEET { + int Function(int) get call => foo; +} + +int foo(int x) => x; diff --git a/Language/Expressions/Function_Invocation/Function_Expression_Invocation/call_A04_t05.dart b/Language/Expressions/Function_Invocation/Function_Expression_Invocation/call_A04_t05.dart new file mode 100644 index 0000000000..fce9c56ae4 --- /dev/null +++ b/Language/Expressions/Function_Invocation/Function_Expression_Invocation/call_A04_t05.dart @@ -0,0 +1,75 @@ +// Copyright (c) 2025, 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 A function expression invocation i has the form +/// ef (a1, . . . , an, xn+1: an+1, . . . , xn+k: an+k), +/// where ef is an expression. +/// ... +/// Let F be the static type of ef . If F is an interface type that has a method +/// named call, i is treated as the ordinary invocation +/// ef .call(a1, . . . , an, xn+1: an+1, . . . , xn+k: an+k) +/// +/// @description Checks that it is a compile-time error to invoke a `call()` +/// method on an implicit tear-off of extension method. +/// @author sgrekhov22@gmail.com +/// @author lrhn + +// See https://github.com/dart-lang/sdk/issues/55803#issuecomment-2124182059 + +void main() { + // These should not compile, call is a getter. + // Tear-offs that should not work: + // Callable extension methods. (No implicit tear-off of extension methods!) + tearoff = expr(EC()); +// ^^^^^^^^^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + tearoff = expr(EMC()); +// ^^^^^^^^^^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + tearoff = expr(EE.instance); +// ^^^^^^^^^^^^^^^^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + tearoff = expr(EET(null), "EET"); +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified +} + +void set tearoff(int Function(int) to) { + to(42); +} + +T expr([Object? value, String? typeName]) { + return value as T; +} + +class EC {} + +extension on EC { + int call(int x) => 43; +} + +enum EE { + instance; +} + +extension on EE { + int call(int x) => 43; +} + +mixin EM {} +class EMC = Object with EM; + +extension on EM { + int call(int x) => 43; +} + +extension type EET(Object? _) {} + +extension on EET { + int call(int x) => 43; +} diff --git a/Language/Expressions/Function_Invocation/Function_Expression_Invocation/call_A04_t06.dart b/Language/Expressions/Function_Invocation/Function_Expression_Invocation/call_A04_t06.dart new file mode 100644 index 0000000000..a888911937 --- /dev/null +++ b/Language/Expressions/Function_Invocation/Function_Expression_Invocation/call_A04_t06.dart @@ -0,0 +1,93 @@ +// Copyright (c) 2025, 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 A function expression invocation i has the form +/// ef (a1, . . . , an, xn+1: an+1, . . . , xn+k: an+k), +/// where ef is an expression. +/// ... +/// Let F be the static type of ef . If F is an interface type that has a method +/// named call, i is treated as the ordinary invocation +/// ef .call(a1, . . . , an, xn+1: an+1, . . . , xn+k: an+k) +/// +/// @description Checks that it is a compile-time error to invoke a `call()` +/// method on a tear-off of an instance getter. +/// @author sgrekhov22@gmail.com +/// @author lrhn + +// See https://github.com/dart-lang/sdk/issues/55803#issuecomment-2124182059 + +void main() { + // These should not compile, call is a getter. + // Tear-offs that should not work: + // Instance getter. + tearoff = expr(BC()); +// ^^^^^^^^^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + tearoff = expr(BMC()); +// ^^^^^^^^^^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + tearoff = expr(BE.instance); +// ^^^^^^^^^^^^^^^^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + tearoff = expr(BET(null), "BET"); +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + tearoff = expr(BERT(bad), "BERT"); +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + tearoff = expr(BNSMC()); +// ^^^^^^^^^^^^^^^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + tearoff = expr<({int Function(int) call})>(rec, "record"); // Record field getter. +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified +} + +void set tearoff(int Function(int) to) { + to(42); +} + +T expr([Object? value, String? typeName]) { + return value as T; +} + +// "Bad" types, no `call` method, only a call getter. +class BC { + int Function(int) get call => foo; +} + +mixin BM { + int Function(int) get call => foo; +} +class BMC = Object with BM; + +enum BE { + instance; + + int Function(int) get call => foo; +} + +extension type BET(Null _) { + int Function(int) get call => foo; +} + +// Representation type getter is a getter. +extension type BERT(int Function(int) call) {} + +class BNSMC { + // Should be NSM-forwarder. + int Function(int) get call; + Object? noSuchMethod(Invocation i) => null; +} + +int foo(int x) => x; + +({int Function(int) call}) rec = (call: foo); diff --git a/Language/Expressions/Function_Invocation/Function_Expression_Invocation/call_A04_t07.dart b/Language/Expressions/Function_Invocation/Function_Expression_Invocation/call_A04_t07.dart new file mode 100644 index 0000000000..23b3587306 --- /dev/null +++ b/Language/Expressions/Function_Invocation/Function_Expression_Invocation/call_A04_t07.dart @@ -0,0 +1,81 @@ +// Copyright (c) 2025, 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 A function expression invocation i has the form +/// ef (a1, . . . , an, xn+1: an+1, . . . , xn+k: an+k), +/// where ef is an expression. +/// ... +/// Let F be the static type of ef . If F is an interface type that has a method +/// named call, i is treated as the ordinary invocation +/// ef .call(a1, . . . , an, xn+1: an+1, . . . , xn+k: an+k) +/// +/// @description Checks that it is a compile-time error to invoke a `call()` +/// method on a tear-off of an extension getter. +/// @author sgrekhov22@gmail.com +/// @author lrhn + +// See https://github.com/dart-lang/sdk/issues/55803#issuecomment-2124182059 + +void main() { + // These should not compile, call is a getter. + // Tear-offs that should not work: + // Extension getter. + tearoff = expr(BEC())(42); +// ^^^^^^^^^^^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + tearoff = expr(BEMC())(42); +// ^^^^^^^^^^^^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + tearoff = expr(BEE.instance)(42); +// ^^^^^^^^^^^^^^^^^^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + tearoff = expr(BEET(null), "EET")(42); +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified +} + +void set tearoff(int Function(int) to) { + to(42); +} + +T expr([Object? value, String? typeName]) { + return value as T; +} + +// "Bad" types, no `call` method, only a call getter. +// Empty types with `call` extension getters. +class BEC {} + +extension on BEC { + int Function(int) get call => foo; +} + +enum BEE { + instance; +} + +extension on BEE { + int Function(int) get call => foo; +} + +mixin BEM {} +class BEMC = Object with BEM; + +extension on BEM { + int Function(int) get call => foo; +} + +extension type const BEET(Null _) {} + +extension on BEET { + int Function(int) get call => foo; +} + +int foo(int x) => x; + +({int Function(int) call}) rec = (call: foo);