Skip to content

Commit 5574b1e

Browse files
johnniwinthercommit-bot@chromium.org
authored and
commit-bot@chromium.org
committed
[cfe] Support implicit tear off in explicit instantiation
Part of #46232 Change-Id: I578ae9d78dd71da40630a3d6da75c4344876944b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/215021 Commit-Queue: Johnni Winther <johnniwinther@google.com> Reviewed-by: Chloe Stefantsova <dmitryas@google.com>
1 parent 81839dd commit 5574b1e

10 files changed

+1030
-6
lines changed

pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,8 +364,50 @@ class InferenceVisitor
364364
ExpressionInferenceResult operandResult = inferrer.inferExpression(
365365
node.expression, const UnknownType(), true,
366366
isVoidAllowed: true);
367-
node.expression = operandResult.expression..parent = node;
367+
Expression operand = operandResult.expression;
368368
DartType operandType = operandResult.inferredType;
369+
if (operandType is! FunctionType) {
370+
ObjectAccessTarget callMember = inferrer.findInterfaceMember(
371+
operandType, callName, operand.fileOffset,
372+
callSiteAccessKind: CallSiteAccessKind.getterInvocation,
373+
includeExtensionMethods: true);
374+
switch (callMember.kind) {
375+
case ObjectAccessTargetKind.instanceMember:
376+
Member? target = callMember.member;
377+
if (target is Procedure && target.kind == ProcedureKind.Method) {
378+
operandType = inferrer.getGetterType(callMember, operandType);
379+
operand = new InstanceTearOff(
380+
InstanceAccessKind.Instance, operand, callName,
381+
interfaceTarget: target, resultType: operandType)
382+
..fileOffset = operand.fileOffset;
383+
}
384+
break;
385+
case ObjectAccessTargetKind.extensionMember:
386+
if (callMember.tearoffTarget != null &&
387+
callMember.extensionMethodKind == ProcedureKind.Method) {
388+
operandType = inferrer.getGetterType(callMember, operandType);
389+
operand = new StaticInvocation(
390+
callMember.tearoffTarget as Procedure,
391+
new Arguments(<Expression>[operand],
392+
types: callMember.inferredExtensionTypeArguments)
393+
..fileOffset = operand.fileOffset)
394+
..fileOffset = operand.fileOffset;
395+
}
396+
break;
397+
case ObjectAccessTargetKind.nullableInstanceMember:
398+
case ObjectAccessTargetKind.objectMember:
399+
case ObjectAccessTargetKind.nullableCallFunction:
400+
case ObjectAccessTargetKind.nullableExtensionMember:
401+
case ObjectAccessTargetKind.dynamic:
402+
case ObjectAccessTargetKind.never:
403+
case ObjectAccessTargetKind.invalid:
404+
case ObjectAccessTargetKind.missing:
405+
case ObjectAccessTargetKind.ambiguous:
406+
case ObjectAccessTargetKind.callFunction:
407+
break;
408+
}
409+
}
410+
node.expression = operand..parent = node;
369411
Expression result = node;
370412
DartType resultType = const InvalidType();
371413
if (operandType is FunctionType) {
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Copyright (c) 2021, 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 'dart:async';
6+
7+
method<T extends Class, S extends int>(Class c, int i, T t, S s) {
8+
c<int>; // ok
9+
i<int>; // ok
10+
t<int>; // ok
11+
s<int>; // ok
12+
}
13+
14+
test<T extends Class?, S extends int>(
15+
Class? c1,
16+
GetterCall c2,
17+
int? i,
18+
T t1,
19+
T? t2,
20+
S? s,
21+
void Function<T>()? f1,
22+
Never n,
23+
dynamic d,
24+
String a,
25+
double b,
26+
bool c,
27+
FutureOr<Class> f2,
28+
Function f3) {
29+
c1<int>; // error
30+
c2<int>; // error
31+
i<int>; // error
32+
t1<int>; // error
33+
t2<int>; // error
34+
s<int>; // error
35+
f1<int>; // error
36+
n<int>; // error
37+
d<int>; // error
38+
a<int>; // error
39+
b<int>; // error
40+
c<int>; // error
41+
f2<int>; // error
42+
f3<int>; // error
43+
}
44+
45+
class Class {
46+
call<T>() {}
47+
}
48+
49+
class GetterCall {
50+
void Function<T>() get call => <T>() {};
51+
}
52+
53+
extension Extension on int {
54+
call<T>() {}
55+
}
56+
57+
extension ExtensionGetter on double {
58+
void Function<T>() get call => <T>() {};
59+
}
60+
61+
extension ExtensionSetter on bool {
62+
set call(void Function<T>() value) {}
63+
}
64+
65+
extension Ambiguous1 on String {
66+
call<T>() {}
67+
}
68+
69+
extension Ambiguous2 on String {
70+
call<T>() {}
71+
}
72+
73+
main() {
74+
method(Class(), 0, Class(), 0);
75+
}
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart:29:5: Error: The static type of the explicit instantiation operand must be a generic function type but is 'Class?'.
6+
// - 'Class' is from 'pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart'.
7+
// Try changing the operand or remove the type arguments.
8+
// c1<int>; // error
9+
// ^
10+
//
11+
// pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart:30:5: Error: The static type of the explicit instantiation operand must be a generic function type but is 'GetterCall'.
12+
// - 'GetterCall' is from 'pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart'.
13+
// Try changing the operand or remove the type arguments.
14+
// c2<int>; // error
15+
// ^
16+
//
17+
// pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart:31:4: Error: The static type of the explicit instantiation operand must be a generic function type but is 'int?'.
18+
// Try changing the operand or remove the type arguments.
19+
// i<int>; // error
20+
// ^
21+
//
22+
// pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart:32:5: Error: The static type of the explicit instantiation operand must be a generic function type but is 'T'.
23+
// Try changing the operand or remove the type arguments.
24+
// t1<int>; // error
25+
// ^
26+
//
27+
// pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart:33:5: Error: The static type of the explicit instantiation operand must be a generic function type but is 'T?'.
28+
// Try changing the operand or remove the type arguments.
29+
// t2<int>; // error
30+
// ^
31+
//
32+
// pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart:34:4: Error: The static type of the explicit instantiation operand must be a generic function type but is 'S?'.
33+
// Try changing the operand or remove the type arguments.
34+
// s<int>; // error
35+
// ^
36+
//
37+
// pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart:36:4: Error: The static type of the explicit instantiation operand must be a generic function type but is 'Never'.
38+
// Try changing the operand or remove the type arguments.
39+
// n<int>; // error
40+
// ^
41+
//
42+
// pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart:37:4: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic'.
43+
// Try changing the operand or remove the type arguments.
44+
// d<int>; // error
45+
// ^
46+
//
47+
// pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart:38:4: Error: The static type of the explicit instantiation operand must be a generic function type but is 'String'.
48+
// Try changing the operand or remove the type arguments.
49+
// a<int>; // error
50+
// ^
51+
//
52+
// pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart:39:4: Error: The static type of the explicit instantiation operand must be a generic function type but is 'double'.
53+
// Try changing the operand or remove the type arguments.
54+
// b<int>; // error
55+
// ^
56+
//
57+
// pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart:40:4: Error: The static type of the explicit instantiation operand must be a generic function type but is 'bool'.
58+
// Try changing the operand or remove the type arguments.
59+
// c<int>; // error
60+
// ^
61+
//
62+
// pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart:41:5: Error: The static type of the explicit instantiation operand must be a generic function type but is 'FutureOr<Class>'.
63+
// - 'Class' is from 'pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart'.
64+
// Try changing the operand or remove the type arguments.
65+
// f2<int>; // error
66+
// ^
67+
//
68+
// pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart:42:5: Error: The static type of the explicit instantiation operand must be a generic function type but is 'Function'.
69+
// - 'Function' is from 'dart:core'.
70+
// Try changing the operand or remove the type arguments.
71+
// f3<int>; // error
72+
// ^
73+
//
74+
import self as self;
75+
import "dart:core" as core;
76+
77+
import "dart:async";
78+
79+
class Class extends core::Object {
80+
synthetic constructor •() → self::Class
81+
: super core::Object::•()
82+
;
83+
method call<T extends core::Object? = dynamic>() → dynamic {}
84+
}
85+
class GetterCall extends core::Object {
86+
synthetic constructor •() → self::GetterCall
87+
: super core::Object::•()
88+
;
89+
get call() → <T extends core::Object? = dynamic>() → void
90+
return <T extends core::Object? = dynamic>() → void {};
91+
}
92+
extension Extension on core::int {
93+
method call = self::Extension|call;
94+
tearoff call = self::Extension|get#call;
95+
}
96+
extension ExtensionGetter on core::double {
97+
get call = self::ExtensionGetter|get#call;
98+
}
99+
extension ExtensionSetter on core::bool {
100+
set call = self::ExtensionSetter|set#call;
101+
}
102+
extension Ambiguous1 on core::String {
103+
method call = self::Ambiguous1|call;
104+
tearoff call = self::Ambiguous1|get#call;
105+
}
106+
extension Ambiguous2 on core::String {
107+
method call = self::Ambiguous2|call;
108+
tearoff call = self::Ambiguous2|get#call;
109+
}
110+
static method method<T extends self::Class, S extends core::int>(self::Class c, core::int i, self::method::T t, self::method::S s) → dynamic {
111+
c.{self::Class::call}{<T extends core::Object? = dynamic>() → dynamic}<core::int>;
112+
self::Extension|get#call(i)<core::int>;
113+
t.{self::Class::call}{<T extends core::Object? = dynamic>() → dynamic}<core::int>;
114+
self::Extension|get#call(s)<core::int>;
115+
}
116+
static method test<T extends self::Class?, S extends core::int>(self::Class? c1, self::GetterCall c2, core::int? i, self::test::T% t1, self::test::T? t2, self::test::S? s, <T extends core::Object? = dynamic>() →? void f1, Never n, dynamic d, core::String a, core::double b, core::bool c, FutureOr<self::Class>f2, core::Function f3) → dynamic {
117+
invalid-expression "pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart:29:5: Error: The static type of the explicit instantiation operand must be a generic function type but is 'Class?'.
118+
- 'Class' is from 'pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart'.
119+
Try changing the operand or remove the type arguments.
120+
c1<int>; // error
121+
^";
122+
invalid-expression "pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart:30:5: Error: The static type of the explicit instantiation operand must be a generic function type but is 'GetterCall'.
123+
- 'GetterCall' is from 'pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart'.
124+
Try changing the operand or remove the type arguments.
125+
c2<int>; // error
126+
^";
127+
invalid-expression "pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart:31:4: Error: The static type of the explicit instantiation operand must be a generic function type but is 'int?'.
128+
Try changing the operand or remove the type arguments.
129+
i<int>; // error
130+
^";
131+
invalid-expression "pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart:32:5: Error: The static type of the explicit instantiation operand must be a generic function type but is 'T'.
132+
Try changing the operand or remove the type arguments.
133+
t1<int>; // error
134+
^";
135+
invalid-expression "pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart:33:5: Error: The static type of the explicit instantiation operand must be a generic function type but is 'T?'.
136+
Try changing the operand or remove the type arguments.
137+
t2<int>; // error
138+
^";
139+
invalid-expression "pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart:34:4: Error: The static type of the explicit instantiation operand must be a generic function type but is 'S?'.
140+
Try changing the operand or remove the type arguments.
141+
s<int>; // error
142+
^";
143+
f1<core::int>;
144+
invalid-expression "pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart:36:4: Error: The static type of the explicit instantiation operand must be a generic function type but is 'Never'.
145+
Try changing the operand or remove the type arguments.
146+
n<int>; // error
147+
^";
148+
invalid-expression "pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart:37:4: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic'.
149+
Try changing the operand or remove the type arguments.
150+
d<int>; // error
151+
^";
152+
invalid-expression "pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart:38:4: Error: The static type of the explicit instantiation operand must be a generic function type but is 'String'.
153+
Try changing the operand or remove the type arguments.
154+
a<int>; // error
155+
^";
156+
invalid-expression "pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart:39:4: Error: The static type of the explicit instantiation operand must be a generic function type but is 'double'.
157+
Try changing the operand or remove the type arguments.
158+
b<int>; // error
159+
^";
160+
invalid-expression "pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart:40:4: Error: The static type of the explicit instantiation operand must be a generic function type but is 'bool'.
161+
Try changing the operand or remove the type arguments.
162+
c<int>; // error
163+
^";
164+
invalid-expression "pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart:41:5: Error: The static type of the explicit instantiation operand must be a generic function type but is 'FutureOr<Class>'.
165+
- 'Class' is from 'pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart'.
166+
Try changing the operand or remove the type arguments.
167+
f2<int>; // error
168+
^";
169+
invalid-expression "pkg/front_end/testcases/constructor_tearoffs/callable_instantiation.dart:42:5: Error: The static type of the explicit instantiation operand must be a generic function type but is 'Function'.
170+
- 'Function' is from 'dart:core'.
171+
Try changing the operand or remove the type arguments.
172+
f3<int>; // error
173+
^";
174+
}
175+
static method Extension|call<T extends core::Object? = dynamic>(lowered final core::int #this) → dynamic {}
176+
static method Extension|get#call(lowered final core::int #this) → <T extends core::Object? = dynamic>() → dynamic
177+
return <T extends core::Object? = dynamic>() → dynamic => self::Extension|call<T%>(#this);
178+
static method ExtensionGetter|get#call(lowered final core::double #this) → <T extends core::Object? = dynamic>() → void
179+
return <T extends core::Object? = dynamic>() → void {};
180+
static method ExtensionSetter|set#call(lowered final core::bool #this, <T extends core::Object? = dynamic>() → void value) → void {}
181+
static method Ambiguous1|call<T extends core::Object? = dynamic>(lowered final core::String #this) → dynamic {}
182+
static method Ambiguous1|get#call(lowered final core::String #this) → <T extends core::Object? = dynamic>() → dynamic
183+
return <T extends core::Object? = dynamic>() → dynamic => self::Ambiguous1|call<T%>(#this);
184+
static method Ambiguous2|call<T extends core::Object? = dynamic>(lowered final core::String #this) → dynamic {}
185+
static method Ambiguous2|get#call(lowered final core::String #this) → <T extends core::Object? = dynamic>() → dynamic
186+
return <T extends core::Object? = dynamic>() → dynamic => self::Ambiguous2|call<T%>(#this);
187+
static method main() → dynamic {
188+
self::method<self::Class, core::int>(new self::Class::•(), 0, new self::Class::•(), 0);
189+
}

0 commit comments

Comments
 (0)