Skip to content

Commit b296d55

Browse files
committed
Issue 39709. Disable implicit 'call' tear-off for nullable objects.
Bug: #39709 Change-Id: I5dcb139f99d3d1e7ef43c6e463e01b665e655b77 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/127740 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
1 parent ded753a commit b296d55

File tree

5 files changed

+238
-1
lines changed

5 files changed

+238
-1
lines changed

pkg/analyzer/lib/src/generated/type_system.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -862,7 +862,9 @@ class Dart2TypeSystem extends TypeSystem {
862862
}
863863

864864
// A call method tearoff
865-
if (fromType is InterfaceType && acceptsFunctionType(toType)) {
865+
if (fromType is InterfaceType &&
866+
!isNullable(fromType) &&
867+
acceptsFunctionType(toType)) {
866868
var callMethodType = getCallMethodType(fromType);
867869
if (callMethodType != null && isAssignableTo(callMethodType, toType)) {
868870
return true;
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Copyright (c) 2019, 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+
import 'package:analyzer/dart/analysis/features.dart';
6+
import 'package:analyzer/src/error/codes.dart';
7+
import 'package:analyzer/src/generated/engine.dart';
8+
import 'package:test_reflective_loader/test_reflective_loader.dart';
9+
10+
import 'driver_resolution.dart';
11+
12+
main() {
13+
defineReflectiveSuite(() {
14+
defineReflectiveTests(PrefixedIdentifierResolutionTest);
15+
defineReflectiveTests(PrefixedIdentifierResolutionWithNnbdTest);
16+
});
17+
}
18+
19+
@reflectiveTest
20+
class PrefixedIdentifierResolutionTest extends DriverResolutionTest {
21+
test_implicitCall_tearOff() async {
22+
newFile('/test/lib/a.dart', content: r'''
23+
class A {
24+
int call() => 0;
25+
}
26+
27+
A a;
28+
''');
29+
await assertNoErrorsInCode('''
30+
import 'a.dart';
31+
32+
int Function() foo() {
33+
return a;
34+
}
35+
''');
36+
37+
var identifier = findNode.simple('a;');
38+
assertElement(
39+
identifier,
40+
findElement.importFind('package:test/a.dart').topGet('a'),
41+
);
42+
assertType(identifier, 'A');
43+
}
44+
}
45+
46+
@reflectiveTest
47+
class PrefixedIdentifierResolutionWithNnbdTest
48+
extends PrefixedIdentifierResolutionTest {
49+
@override
50+
AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
51+
..contextFeatures = FeatureSet.forTesting(
52+
sdkVersion: '2.6.0', additionalFeatures: [Feature.non_nullable]);
53+
54+
@override
55+
bool get typeToStringWithNullability => true;
56+
57+
test_implicitCall_tearOff_nullable() async {
58+
newFile('/test/lib/a.dart', content: r'''
59+
class A {
60+
int call() => 0;
61+
}
62+
63+
A? a;
64+
''');
65+
await assertErrorsInCode('''
66+
import 'a.dart';
67+
68+
int Function() foo() {
69+
return a;
70+
}
71+
''', [
72+
error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION, 50, 1),
73+
]);
74+
75+
var identifier = findNode.simple('a;');
76+
assertElement(
77+
identifier,
78+
findElement.importFind('package:test/a.dart').topGet('a'),
79+
);
80+
assertType(identifier, 'A?');
81+
}
82+
}

pkg/analyzer/test/src/dart/resolution/property_access_test.dart

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,17 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
import 'package:analyzer/dart/analysis/features.dart';
56
import 'package:analyzer/src/error/codes.dart';
7+
import 'package:analyzer/src/generated/engine.dart';
68
import 'package:test_reflective_loader/test_reflective_loader.dart';
79

810
import 'driver_resolution.dart';
911

1012
main() {
1113
defineReflectiveSuite(() {
1214
defineReflectiveTests(PropertyAccessResolutionTest);
15+
defineReflectiveTests(PropertyAccessResolutionWithNnbdTest);
1316
});
1417
}
1518

@@ -100,4 +103,54 @@ class B extends A {
100103
);
101104
assertSuperExpression(access.target);
102105
}
106+
107+
test_tearOff_method() async {
108+
await assertNoErrorsInCode('''
109+
class A {
110+
void foo(int a) {}
111+
}
112+
113+
bar() {
114+
A().foo;
115+
}
116+
''');
117+
118+
var identifier = findNode.simple('foo;');
119+
assertElement(identifier, findElement.method('foo'));
120+
assertType(identifier, 'void Function(int)');
121+
}
122+
}
123+
124+
@reflectiveTest
125+
class PropertyAccessResolutionWithNnbdTest
126+
extends PropertyAccessResolutionTest {
127+
@override
128+
AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
129+
..contextFeatures = FeatureSet.forTesting(
130+
sdkVersion: '2.6.0', additionalFeatures: [Feature.non_nullable]);
131+
132+
@override
133+
bool get typeToStringWithNullability => true;
134+
135+
test_implicitCall_tearOff_nullable() async {
136+
await assertErrorsInCode('''
137+
class A {
138+
int call() => 0;
139+
}
140+
141+
class B {
142+
A? a;
143+
}
144+
145+
int Function() foo() {
146+
return B().a; // ref
147+
}
148+
''', [
149+
error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION, 85, 5),
150+
]);
151+
152+
var identifier = findNode.simple('a; // ref');
153+
assertElement(identifier, findElement.getter('a'));
154+
assertType(identifier, 'A?');
155+
}
103156
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Copyright (c) 2019, 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+
import 'package:analyzer/dart/analysis/features.dart';
6+
import 'package:analyzer/src/error/codes.dart';
7+
import 'package:analyzer/src/generated/engine.dart';
8+
import 'package:test_reflective_loader/test_reflective_loader.dart';
9+
10+
import 'driver_resolution.dart';
11+
12+
main() {
13+
defineReflectiveSuite(() {
14+
defineReflectiveTests(SimpleIdentifierResolutionTest);
15+
defineReflectiveTests(SimpleIdentifierResolutionWithNnbdTest);
16+
});
17+
}
18+
19+
@reflectiveTest
20+
class SimpleIdentifierResolutionTest extends DriverResolutionTest {
21+
test_implicitCall_tearOff() async {
22+
await assertNoErrorsInCode('''
23+
class A {
24+
int call() => 0;
25+
}
26+
27+
int Function() foo(A a) {
28+
return a;
29+
}
30+
''');
31+
32+
var identifier = findNode.simple('a;');
33+
assertElement(identifier, findElement.parameter('a'));
34+
assertType(identifier, 'A');
35+
}
36+
37+
test_tearOff_function_topLevel() async {
38+
await assertNoErrorsInCode('''
39+
void foo(int a) {}
40+
41+
main() {
42+
foo;
43+
}
44+
''');
45+
46+
var identifier = findNode.simple('foo;');
47+
assertElement(identifier, findElement.topFunction('foo'));
48+
assertType(identifier, 'void Function(int)');
49+
}
50+
51+
test_tearOff_method() async {
52+
await assertNoErrorsInCode('''
53+
class A {
54+
void foo(int a) {}
55+
56+
bar() {
57+
foo;
58+
}
59+
}
60+
''');
61+
62+
var identifier = findNode.simple('foo;');
63+
assertElement(identifier, findElement.method('foo'));
64+
assertType(identifier, 'void Function(int)');
65+
}
66+
}
67+
68+
@reflectiveTest
69+
class SimpleIdentifierResolutionWithNnbdTest
70+
extends SimpleIdentifierResolutionTest {
71+
@override
72+
AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
73+
..contextFeatures = FeatureSet.forTesting(
74+
sdkVersion: '2.6.0', additionalFeatures: [Feature.non_nullable]);
75+
76+
@override
77+
bool get typeToStringWithNullability => true;
78+
79+
test_implicitCall_tearOff_nullable() async {
80+
await assertErrorsInCode('''
81+
class A {
82+
int call() => 0;
83+
}
84+
85+
int Function() foo(A? a) {
86+
return a;
87+
}
88+
''', [
89+
error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION, 68, 1),
90+
]);
91+
92+
var identifier = findNode.simple('a;');
93+
assertElement(identifier, findElement.parameter('a'));
94+
assertType(identifier, 'A?');
95+
}
96+
}

pkg/analyzer/test/src/dart/resolution/test_all.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ import 'mixin_test.dart' as mixin_resolution;
3838
import 'namespace_test.dart' as namespace;
3939
import 'non_nullable_test.dart' as non_nullable;
4040
import 'optional_const_test.dart' as optional_const;
41+
import 'prefixed_identifier_test.dart' as prefixed_identifier;
4142
import 'property_access_test.dart' as property_access;
43+
import 'simple_identifier_test.dart' as simple_identifier;
4244
import 'top_type_inference_test.dart' as top_type_inference;
4345
import 'type_inference/test_all.dart' as type_inference;
4446

@@ -75,7 +77,9 @@ main() {
7577
namespace.main();
7678
non_nullable.main();
7779
optional_const.main();
80+
prefixed_identifier.main();
7881
property_access.main();
82+
simple_identifier.main();
7983
top_type_inference.main();
8084
type_inference.main();
8185
}, name: 'resolution');

0 commit comments

Comments
 (0)