Skip to content

Commit 4dff1b3

Browse files
chloestefantsovaCommit Queue
authored and
Commit Queue
committed
[cfe] Report errors on attempts to call a record type
Closes #54616 Change-Id: Ib0a74ae139a56e0660b3cfb00127c898d693a03c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/349000 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Chloe Stefantsova <[email protected]>
1 parent 8ea636f commit 4dff1b3

22 files changed

+1184
-8
lines changed

pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12672,6 +12672,15 @@ const MessageCode messageRecordTypeZeroFieldsButTrailingComma =
1267212672
r"""A record type without fields can't have a trailing comma.""",
1267312673
correctionMessage: r"""Try removing the trailing comma.""");
1267412674

12675+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
12676+
const Code<Null> codeRecordUsedAsCallable = messageRecordUsedAsCallable;
12677+
12678+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
12679+
const MessageCode messageRecordUsedAsCallable = const MessageCode(
12680+
"RecordUsedAsCallable",
12681+
problemMessage:
12682+
r"""The 'call' property on the record type isn't directly callable but could be invoked by `.call(...)`""");
12683+
1267512684
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
1267612685
const Code<Null> codeRedirectingConstructorWithAnotherInitializer =
1267712686
messageRedirectingConstructorWithAnotherInitializer;

pkg/front_end/lib/src/fasta/type_inference/inference_visitor_base.dart

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis_operations.d
99
import 'package:_fe_analyzer_shared/src/type_inference/assigned_variables.dart';
1010
import 'package:_fe_analyzer_shared/src/testing/id.dart';
1111
import 'package:_fe_analyzer_shared/src/util/link.dart';
12-
import 'package:front_end/src/fasta/source/source_field_builder.dart';
13-
import 'package:front_end/src/fasta/source/source_procedure_builder.dart';
1412
import 'package:kernel/ast.dart';
1513
import 'package:kernel/class_hierarchy.dart'
1614
show ClassHierarchyBase, ClassHierarchyMembers;
@@ -43,8 +41,10 @@ import '../kernel/type_algorithms.dart' show hasAnyTypeVariables;
4341
import '../names.dart';
4442
import '../problems.dart' show internalProblem, unhandled;
4543
import '../source/source_constructor_builder.dart';
44+
import '../source/source_field_builder.dart';
4645
import '../source/source_library_builder.dart'
4746
show FieldNonPromotabilityInfo, SourceLibraryBuilder;
47+
import '../source/source_procedure_builder.dart';
4848
import '../util/helpers.dart';
4949
import 'closure_context.dart';
5050
import 'external_ast_helper.dart';
@@ -3380,6 +3380,10 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
33803380
hoistedExpressions: hoistedExpressions);
33813381
case ObjectAccessTargetKind.recordNamed:
33823382
case ObjectAccessTargetKind.nullableRecordNamed:
3383+
if (isImplicitCall && !target.isNullable) {
3384+
libraryBuilder.addProblem(messageRecordUsedAsCallable,
3385+
receiver.fileOffset, noLength, libraryBuilder.fileUri);
3386+
}
33833387
DartType type = target.getGetterType(this);
33843388
Expression read = new RecordNameGet(receiver,
33853389
target.receiverType as RecordType, target.recordFieldName!)

pkg/front_end/messages.status

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,12 @@ JsInteropExternalExtensionMemberWithStaticDisallowed/analyzerCode: Fail # Web co
631631
JsInteropExternalExtensionMemberWithStaticDisallowed/example: Fail # Web compiler specific
632632
JsInteropExternalMemberNotJSAnnotated/analyzerCode: Fail # Web compiler specific
633633
JsInteropExternalMemberNotJSAnnotated/example: Fail # Web compiler specific
634+
JsInteropFunctionToJSRequiresStaticType/analyzerCode: Fail # Web compiler specific
635+
JsInteropFunctionToJSRequiresStaticType/example: Fail # Web compiler specific
636+
JsInteropFunctionToJSTypeParameters/analyzerCode: Fail # Web compiler specific
637+
JsInteropFunctionToJSTypeParameters/example: Fail # Web compiler specific
638+
JsInteropInvalidStaticClassMemberName/analyzerCode: Fail
639+
JsInteropInvalidStaticClassMemberName/example: Fail
634640
JsInteropIsAInvalidType/analyzerCode: Fail # Web compiler specific
635641
JsInteropIsAInvalidType/example: Fail # Web compiler specific
636642
JsInteropIsAObjectLiteralType/analyzerCode: Fail # Web compiler specific
@@ -639,12 +645,6 @@ JsInteropIsAPrimitiveExtensionType/analyzerCode: Fail # Web compiler specific
639645
JsInteropIsAPrimitiveExtensionType/example: Fail # Web compiler specific
640646
JsInteropIsATearoff/analyzerCode: Fail # Web compiler specific
641647
JsInteropIsATearoff/example: Fail # Web compiler specific
642-
JsInteropFunctionToJSRequiresStaticType/analyzerCode: Fail # Web compiler specific
643-
JsInteropFunctionToJSRequiresStaticType/example: Fail # Web compiler specific
644-
JsInteropFunctionToJSTypeParameters/analyzerCode: Fail # Web compiler specific
645-
JsInteropFunctionToJSTypeParameters/example: Fail # Web compiler specific
646-
JsInteropInvalidStaticClassMemberName/analyzerCode: Fail
647-
JsInteropInvalidStaticClassMemberName/example: Fail
648648
JsInteropJSClassExtendsDartClass/analyzerCode: Fail # Web compiler specific
649649
JsInteropJSClassExtendsDartClass/example: Fail # Web compiler specific
650650
JsInteropNamedParameters/analyzerCode: Fail # Web compiler specific
@@ -930,6 +930,9 @@ PrefixAfterCombinator/example: Fail
930930
PreviousUseOfName/analyzerCode: Fail
931931
PreviousUseOfName/example: Fail
932932
PrivateNamedParameter/example: Fail
933+
RecordUsedAsCallable/analyzerCode: Fail
934+
RecordUsedAsCallable/part_wrapped_script: Fail
935+
RecordUsedAsCallable/script: Fail
933936
RedirectingConstructorWithBody/part_wrapped_script1: Fail
934937
RedirectingConstructorWithBody/script1: Fail
935938
RedirectingFactoryIncompatibleTypeArgumentWarning/example: Fail

pkg/front_end/messages.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7619,3 +7619,8 @@ ExtensionTypeImplementsDeferred:
76197619
extension type ET(d.A id) implements d.A {}
76207620
lib.dart: |
76217621
class A {}
7622+
7623+
RecordUsedAsCallable:
7624+
problemMessage: "The 'call' property on the record type isn't directly callable but could be invoked by `.call(...)`"
7625+
script: |
7626+
test(({dynamic call} r) => r(0);
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
void main() {
6+
var c = (call: (int x) => x);
7+
var v = c(1); // Error.
8+
9+
var c2 = (call: intId);
10+
var v2 = c2(1); // Error.
11+
12+
var c3 = (call: <T>(T x) => x);
13+
var v3a = c3(1); // Error.
14+
var v3b = c3("a"); // Error.
15+
}
16+
17+
int intId(int x) => x;
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/records/issue54616.dart:7:11: Error: The 'call' property on the record type isn't directly callable but could be invoked by `.call(...)`
6+
// var v = c(1); // Error.
7+
// ^
8+
//
9+
// pkg/front_end/testcases/records/issue54616.dart:10:12: Error: The 'call' property on the record type isn't directly callable but could be invoked by `.call(...)`
10+
// var v2 = c2(1); // Error.
11+
// ^
12+
//
13+
// pkg/front_end/testcases/records/issue54616.dart:13:13: Error: The 'call' property on the record type isn't directly callable but could be invoked by `.call(...)`
14+
// var v3a = c3(1); // Error.
15+
// ^
16+
//
17+
// pkg/front_end/testcases/records/issue54616.dart:14:13: Error: The 'call' property on the record type isn't directly callable but could be invoked by `.call(...)`
18+
// var v3b = c3("a"); // Error.
19+
// ^
20+
//
21+
import self as self;
22+
import "dart:core" as core;
23+
24+
static method main() → void {
25+
({call: (core::int) → core::int}) c = ({call: (core::int x) → core::int => x});
26+
core::int v = c.call{(core::int) → core::int}(1){(core::int) → core::int};
27+
({call: (core::int) → core::int}) c2 = #C2;
28+
core::int v2 = c2.call{(core::int) → core::int}(1){(core::int) → core::int};
29+
({call: <T extends core::Object? = dynamic>(T%) → T%}) c3 = ({call: <T extends core::Object? = dynamic>(T% x) → T% => x});
30+
core::int v3a = c3.call{<T extends core::Object? = dynamic>(T%) → T%}<core::int>(1){(core::int) → core::int};
31+
core::String v3b = c3.call{<T extends core::Object? = dynamic>(T%) → T%}<core::String>("a"){(core::String) → core::String};
32+
}
33+
static method intId(core::int x) → core::int
34+
return x;
35+
36+
constants {
37+
#C1 = static-tearoff self::intId
38+
#C2 = ({call:#C1})
39+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/records/issue54616.dart:7:11: Error: The 'call' property on the record type isn't directly callable but could be invoked by `.call(...)`
6+
// var v = c(1); // Error.
7+
// ^
8+
//
9+
// pkg/front_end/testcases/records/issue54616.dart:10:12: Error: The 'call' property on the record type isn't directly callable but could be invoked by `.call(...)`
10+
// var v2 = c2(1); // Error.
11+
// ^
12+
//
13+
// pkg/front_end/testcases/records/issue54616.dart:13:13: Error: The 'call' property on the record type isn't directly callable but could be invoked by `.call(...)`
14+
// var v3a = c3(1); // Error.
15+
// ^
16+
//
17+
// pkg/front_end/testcases/records/issue54616.dart:14:13: Error: The 'call' property on the record type isn't directly callable but could be invoked by `.call(...)`
18+
// var v3b = c3("a"); // Error.
19+
// ^
20+
//
21+
import self as self;
22+
import "dart:core" as core;
23+
24+
static method main() → void {
25+
({call: (core::int) → core::int}) c = ({call: (core::int x) → core::int => x});
26+
core::int v = c.call{(core::int) → core::int}(1){(core::int) → core::int};
27+
({call: (core::int) → core::int}) c2 = #C2;
28+
core::int v2 = c2.call{(core::int) → core::int}(1){(core::int) → core::int};
29+
({call: <T extends core::Object? = dynamic>(T%) → T%}) c3 = ({call: <T extends core::Object? = dynamic>(T% x) → T% => x});
30+
core::int v3a = c3.call{<T extends core::Object? = dynamic>(T%) → T%}<core::int>(1){(core::int) → core::int};
31+
core::String v3b = c3.call{<T extends core::Object? = dynamic>(T%) → T%}<core::String>("a"){(core::String) → core::String};
32+
}
33+
static method intId(core::int x) → core::int
34+
return x;
35+
36+
constants {
37+
#C1 = static-tearoff self::intId
38+
#C2 = ({call:#C1})
39+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
void main() {}
2+
3+
int intId(int x) => x;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
int intId(int x) => x;
2+
3+
void main() {}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/records/issue54616.dart:7:11: Error: The 'call' property on the record type isn't directly callable but could be invoked by `.call(...)`
6+
// var v = c(1); // Error.
7+
// ^
8+
//
9+
// pkg/front_end/testcases/records/issue54616.dart:10:12: Error: The 'call' property on the record type isn't directly callable but could be invoked by `.call(...)`
10+
// var v2 = c2(1); // Error.
11+
// ^
12+
//
13+
// pkg/front_end/testcases/records/issue54616.dart:13:13: Error: The 'call' property on the record type isn't directly callable but could be invoked by `.call(...)`
14+
// var v3a = c3(1); // Error.
15+
// ^
16+
//
17+
// pkg/front_end/testcases/records/issue54616.dart:14:13: Error: The 'call' property on the record type isn't directly callable but could be invoked by `.call(...)`
18+
// var v3b = c3("a"); // Error.
19+
// ^
20+
//
21+
import self as self;
22+
import "dart:core" as core;
23+
24+
static method main() → void {
25+
({call: (core::int) → core::int}) c = ({call: (core::int x) → core::int => x});
26+
core::int v = c.call{(core::int) → core::int}(1){(core::int) → core::int};
27+
({call: (core::int) → core::int}) c2 = #C2;
28+
core::int v2 = c2.call{(core::int) → core::int}(1){(core::int) → core::int};
29+
({call: <T extends core::Object? = dynamic>(T%) → T%}) c3 = ({call: <T extends core::Object? = dynamic>(T% x) → T% => x});
30+
core::int v3a = c3.call{<T extends core::Object? = dynamic>(T%) → T%}<core::int>(1){(core::int) → core::int};
31+
core::String v3b = c3.call{<T extends core::Object? = dynamic>(T%) → T%}<core::String>("a"){(core::String) → core::String};
32+
}
33+
static method intId(core::int x) → core::int
34+
return x;
35+
36+
constants {
37+
#C1 = static-tearoff self::intId
38+
#C2 = ({call:#C1})
39+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/records/issue54616.dart:7:11: Error: The 'call' property on the record type isn't directly callable but could be invoked by `.call(...)`
6+
// var v = c(1); // Error.
7+
// ^
8+
//
9+
// pkg/front_end/testcases/records/issue54616.dart:10:12: Error: The 'call' property on the record type isn't directly callable but could be invoked by `.call(...)`
10+
// var v2 = c2(1); // Error.
11+
// ^
12+
//
13+
// pkg/front_end/testcases/records/issue54616.dart:13:13: Error: The 'call' property on the record type isn't directly callable but could be invoked by `.call(...)`
14+
// var v3a = c3(1); // Error.
15+
// ^
16+
//
17+
// pkg/front_end/testcases/records/issue54616.dart:14:13: Error: The 'call' property on the record type isn't directly callable but could be invoked by `.call(...)`
18+
// var v3b = c3("a"); // Error.
19+
// ^
20+
//
21+
import self as self;
22+
import "dart:core" as core;
23+
24+
static method main() → void {
25+
({call: (core::int) → core::int}) c = ({call: (core::int x) → core::int => x});
26+
core::int v = c.call{(core::int) → core::int}(1){(core::int) → core::int};
27+
({call: (core::int) → core::int}) c2 = #C2;
28+
core::int v2 = c2.call{(core::int) → core::int}(1){(core::int) → core::int};
29+
({call: <T extends core::Object? = dynamic>(T%) → T%}) c3 = ({call: <T extends core::Object? = dynamic>(T% x) → T% => x});
30+
core::int v3a = c3.call{<T extends core::Object? = dynamic>(T%) → T%}<core::int>(1){(core::int) → core::int};
31+
core::String v3b = c3.call{<T extends core::Object? = dynamic>(T%) → T%}<core::String>("a"){(core::String) → core::String};
32+
}
33+
static method intId(core::int x) → core::int
34+
return x;
35+
36+
constants {
37+
#C1 = static-tearoff self::intId
38+
#C2 = ({call:#C1})
39+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
static method main() → void
6+
;
7+
static method intId(core::int x) → core::int
8+
;
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/records/issue54616.dart:7:11: Error: The 'call' property on the record type isn't directly callable but could be invoked by `.call(...)`
6+
// var v = c(1); // Error.
7+
// ^
8+
//
9+
// pkg/front_end/testcases/records/issue54616.dart:10:12: Error: The 'call' property on the record type isn't directly callable but could be invoked by `.call(...)`
10+
// var v2 = c2(1); // Error.
11+
// ^
12+
//
13+
// pkg/front_end/testcases/records/issue54616.dart:13:13: Error: The 'call' property on the record type isn't directly callable but could be invoked by `.call(...)`
14+
// var v3a = c3(1); // Error.
15+
// ^
16+
//
17+
// pkg/front_end/testcases/records/issue54616.dart:14:13: Error: The 'call' property on the record type isn't directly callable but could be invoked by `.call(...)`
18+
// var v3b = c3("a"); // Error.
19+
// ^
20+
//
21+
import self as self;
22+
import "dart:core" as core;
23+
24+
static method main() → void {
25+
({call: (core::int) → core::int}) c = ({call: (core::int x) → core::int => x});
26+
core::int v = c.call{(core::int) → core::int}(1){(core::int) → core::int};
27+
({call: (core::int) → core::int}) c2 = #C2;
28+
core::int v2 = c2.call{(core::int) → core::int}(1){(core::int) → core::int};
29+
({call: <T extends core::Object? = dynamic>(T%) → T%}) c3 = ({call: <T extends core::Object? = dynamic>(T% x) → T% => x});
30+
core::int v3a = c3.call{<T extends core::Object? = dynamic>(T%) → T%}<core::int>(1){(core::int) → core::int};
31+
core::String v3b = c3.call{<T extends core::Object? = dynamic>(T%) → T%}<core::String>("a"){(core::String) → core::String};
32+
}
33+
static method intId(core::int x) → core::int
34+
return x;
35+
36+
constants {
37+
#C1 = static-tearoff self::intId
38+
#C2 = ({call:#C1})
39+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
extension EInt on (int,) {
6+
dynamic call(dynamic x) => x;
7+
}
8+
9+
extension EIntIntCallInt on (int, int, {dynamic Function(dynamic) call}) {
10+
dynamic call(dynamic x) => x;
11+
}
12+
13+
test<X1 extends (int,), X2 extends (int, {dynamic Function(dynamic) call}), X3 extends (int, int, {dynamic Function(dynamic) call}), X4 extends (String,)>(
14+
(int,) r1,
15+
(int, {dynamic Function(dynamic) call}) r2,
16+
(int, int, {dynamic Function(dynamic) call}) r3,
17+
(String,) r4,
18+
X1 x1,
19+
X2 x2,
20+
X3 x3,
21+
X4 x4,
22+
X1? x1n,
23+
X2? x2n,
24+
X3? x3n,
25+
X4? x4n) {
26+
r1(0); // Ok.
27+
r2(0); // Error.
28+
r3(0); // Error.
29+
r4(0); // Error.
30+
r1.call(0); // Ok.
31+
r2.call(0); // Ok.
32+
r3.call(0); // Ok.
33+
r4.call(0); // Error.
34+
35+
x1(0); // Ok.
36+
x2(0); // Error.
37+
x3(0); // Error.
38+
x4(0); // Error.
39+
x1n(0); // Error.
40+
x2n(0); // Error.
41+
x3n(0); // Error.
42+
x4n(0); // Error.
43+
44+
x1.call(0); // Ok.
45+
x2.call(0); // Ok.
46+
x3.call(0); // Ok.
47+
x4.call(0); // Error.
48+
x1n.call(0); // Error.
49+
x2n.call(0); // Error.
50+
x3n.call(0); // Error.
51+
x4n.call(0); // Error.
52+
}

0 commit comments

Comments
 (0)