@@ -21,6 +21,64 @@ using namespace swift;
21
21
using namespace swift ::constraints;
22
22
using namespace swift ::ide;
23
23
24
+ bool PostfixCompletionCallback::Result::canBeMergedWith (const Result &Other,
25
+ DeclContext &DC) const {
26
+ if (BaseDecl != Other.BaseDecl ) {
27
+ return false ;
28
+ }
29
+ if (!BaseTy->isEqual (Other.BaseTy ) &&
30
+ !isConvertibleTo (BaseTy, Other.BaseTy , /* openArchetypes=*/ true , DC) &&
31
+ !isConvertibleTo (Other.BaseTy , BaseTy, /* openArchetypes=*/ true , DC)) {
32
+ return false ;
33
+ }
34
+ return true ;
35
+ }
36
+
37
+ void PostfixCompletionCallback::Result::merge (const Result &Other,
38
+ DeclContext &DC) {
39
+ assert (canBeMergedWith (Other, DC));
40
+ // These properties should match if we are talking about the same BaseDecl.
41
+ assert (BaseIsStaticMetaType == Other.BaseIsStaticMetaType );
42
+
43
+ if (!BaseTy->isEqual (Other.BaseTy ) &&
44
+ isConvertibleTo (Other.BaseTy , BaseTy, /* openArchetypes=*/ true , DC)) {
45
+ // Pick the more specific base type as it will produce more solutions.
46
+ BaseTy = Other.BaseTy ;
47
+ }
48
+
49
+ // There could be multiple results that have different actor isolations if the
50
+ // closure is an argument to a function that has multiple overloads with
51
+ // different isolations for the closure. Producing multiple results for these
52
+ // is usually not very enlightning. For now, we just pick the first actor
53
+ // isolation that we find. This is good enough in practice.
54
+ // What we should really do is probably merge these two actor isolations and
55
+ // pick the weakest isolation for each closure.
56
+
57
+ for (auto &OtherExpectedTy : Other.ExpectedTypes ) {
58
+ auto IsEqual = [&](Type Ty) { return Ty->isEqual (OtherExpectedTy); };
59
+ if (llvm::any_of (ExpectedTypes, IsEqual)) {
60
+ // We already know if this expected type
61
+ continue ;
62
+ }
63
+ ExpectedTypes.push_back (OtherExpectedTy);
64
+ }
65
+ ExpectsNonVoid &= Other.ExpectsNonVoid ;
66
+ IsImplicitSingleExpressionReturn |= Other.IsImplicitSingleExpressionReturn ;
67
+ IsInAsyncContext |= Other.IsInAsyncContext ;
68
+ }
69
+
70
+ void PostfixCompletionCallback::addResult (const Result &Res) {
71
+ auto ExistingRes =
72
+ llvm::find_if (Results, [&Res, DC = DC](const Result &ExistingResult) {
73
+ return ExistingResult.canBeMergedWith (Res, *DC);
74
+ });
75
+ if (ExistingRes != Results.end ()) {
76
+ ExistingRes->merge (Res, *DC);
77
+ } else {
78
+ Results.push_back (Res);
79
+ }
80
+ }
81
+
24
82
void PostfixCompletionCallback::fallbackTypeCheck (DeclContext *DC) {
25
83
assert (!gotCallback ());
26
84
@@ -101,39 +159,43 @@ void PostfixCompletionCallback::sawSolutionImpl(
101
159
}
102
160
}
103
161
104
- auto Key = std::make_pair (BaseTy, ReferencedDecl);
105
- auto Ret = BaseToSolutionIdx.insert ({Key, Results.size ()});
106
- if (Ret.second ) {
107
- bool ISDMT = S.isStaticallyDerivedMetatype (ParsedExpr);
108
- bool ImplicitReturn = isImplicitSingleExpressionReturn (CS, CompletionExpr);
109
- bool DisallowVoid = false ;
110
- DisallowVoid |= ExpectedTy && !ExpectedTy->isVoid ();
111
- DisallowVoid |= !ParentExpr &&
112
- CS.getContextualTypePurpose (CompletionExpr) != CTP_Unused;
113
- for (auto SAT : S.targets ) {
114
- if (DisallowVoid) {
115
- // DisallowVoid is already set. No need to iterate further.
116
- break ;
117
- }
118
- if (SAT.second .getAsExpr () == CompletionExpr) {
119
- DisallowVoid |= SAT.second .getExprContextualTypePurpose () != CTP_Unused;
120
- }
121
- }
162
+ bool BaseIsStaticMetaType = S.isStaticallyDerivedMetatype (ParsedExpr);
163
+
164
+ SmallVector<Type, 4 > ExpectedTypes;
165
+ if (ExpectedTy) {
166
+ ExpectedTypes.push_back (ExpectedTy);
167
+ }
122
168
123
- Results.push_back ({BaseTy, ReferencedDecl,
124
- /* ExpectedTypes=*/ {}, DisallowVoid, ISDMT,
125
- ImplicitReturn, IsAsync, ClosureActorIsolations});
126
- if (ExpectedTy) {
127
- Results.back ().ExpectedTypes .push_back (ExpectedTy);
169
+ bool ExpectsNonVoid = false ;
170
+ ExpectsNonVoid |= ExpectedTy && !ExpectedTy->isVoid ();
171
+ ExpectsNonVoid |=
172
+ !ParentExpr && CS.getContextualTypePurpose (CompletionExpr) != CTP_Unused;
173
+
174
+ for (auto SAT : S.targets ) {
175
+ if (ExpectsNonVoid) {
176
+ // ExpectsNonVoid is already set. No need to iterate further.
177
+ break ;
128
178
}
129
- } else if (ExpectedTy) {
130
- auto &ExistingResult = Results[Ret.first ->getSecond ()];
131
- ExistingResult.IsInAsyncContext |= IsAsync;
132
- auto IsEqual = [&](Type Ty) { return ExpectedTy->isEqual (Ty); };
133
- if (!llvm::any_of (ExistingResult.ExpectedTypes , IsEqual)) {
134
- ExistingResult.ExpectedTypes .push_back (ExpectedTy);
179
+ if (SAT.second .getAsExpr () == CompletionExpr) {
180
+ ExpectsNonVoid |= SAT.second .getExprContextualTypePurpose () != CTP_Unused;
135
181
}
136
182
}
183
+
184
+ bool IsImplicitSingleExpressionReturn =
185
+ isImplicitSingleExpressionReturn (CS, CompletionExpr);
186
+
187
+ Result Res = {
188
+ BaseTy,
189
+ ReferencedDecl,
190
+ BaseIsStaticMetaType,
191
+ ExpectedTypes,
192
+ ExpectsNonVoid,
193
+ IsImplicitSingleExpressionReturn,
194
+ IsAsync,
195
+ ClosureActorIsolations
196
+ };
197
+
198
+ addResult (Res);
137
199
}
138
200
139
201
void PostfixCompletionCallback::deliverResults (
0 commit comments