Skip to content

Commit a139962

Browse files
authored
Merge pull request #65720 from ahoppen/ahoppen/complete-parameter-pack-arg
[CodeCompletion] Fix a crash when completing an argument to a function taking a parameter pack
2 parents 5ecf763 + 6d8b1f4 commit a139962

File tree

6 files changed

+65
-39
lines changed

6 files changed

+65
-39
lines changed

include/swift/IDE/ArgumentCompletion.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ class ArgumentTypeCheckCompletionCallback : public TypeCheckCompletionCallback {
2929
Type ExpectedCallType;
3030
/// True if this is a subscript rather than a function call.
3131
bool IsSubscript;
32-
/// The FuncDecl or SubscriptDecl associated with the call.
33-
ValueDecl *FuncD;
32+
/// The reference to the FuncDecl or SubscriptDecl associated with the call.
33+
ConcreteDeclRef FuncDeclRef;
3434
/// The type of the function being called.
3535
AnyFunctionType *FuncTy;
3636
/// The index of the argument containing the completion location
@@ -55,6 +55,9 @@ class ArgumentTypeCheckCompletionCallback : public TypeCheckCompletionCallback {
5555
/// this result. This in particular includes parameters of closures that
5656
/// were type-checked with the code completion expression.
5757
llvm::SmallDenseMap<const VarDecl *, Type> SolutionSpecificVarTypes;
58+
59+
/// Return the \c FuncDecl or \c SubscriptDecl associated with this call.
60+
ValueDecl *getFuncD() const { return FuncDeclRef.getDecl(); }
5861
};
5962

6063
CodeCompletionExpr *CompletionExpr;

include/swift/IDE/SelectedOverloadInfo.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,15 @@ using namespace swift::constraints;
2525
/// \c SelectedOverload.
2626
struct SelectedOverloadInfo {
2727
/// The function that is being called or the value that is being accessed.
28-
ValueDecl *Value = nullptr;
28+
ConcreteDeclRef ValueRef;
2929
/// For a function, type of the called function itself (not its result type),
3030
/// for an arbitrary value the type of that value.
3131
Type ValueTy;
3232
/// The type on which the overload is being accessed. \c null if it does not
3333
/// have a base type, e.g. for a free function.
3434
Type BaseTy;
35+
36+
ValueDecl *getValue() const { return ValueRef.getDecl(); }
3537
};
3638

3739
/// Extract additional information about the overload that is being called by

lib/IDE/ArgumentCompletion.cpp

Lines changed: 43 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,6 @@ bool ArgumentTypeCheckCompletionCallback::addPossibleParams(
3838

3939
ArrayRef<AnyFunctionType::Param> ParamsToPass = Res.FuncTy->getParams();
4040

41-
ParameterList *PL = nullptr;
42-
if (Res.FuncD) {
43-
PL = swift::getParameterList(Res.FuncD);
44-
}
45-
assert(!PL || PL->size() == ParamsToPass.size());
46-
4741
bool ShowGlobalCompletions = false;
4842
for (auto Idx : range(*Res.ParamIdx, ParamsToPass.size())) {
4943
bool IsCompletion = (Idx == Res.ParamIdx);
@@ -53,22 +47,35 @@ bool ArgumentTypeCheckCompletionCallback::addPossibleParams(
5347
break;
5448
}
5549

56-
const AnyFunctionType::Param *P = &ParamsToPass[Idx];
57-
bool Required =
58-
!(PL && PL->get(Idx)->isDefaultArgument()) && !P->isVariadic();
50+
// We work with the parameter from the function type and the declaration
51+
// because they contain different information that we need.
52+
//
53+
// Since not all function types are backed by declarations (e.g. closure
54+
// paramters), `DeclParam` might be `nullptr`.
55+
const AnyFunctionType::Param *TypeParam = &ParamsToPass[Idx];
56+
const ParamDecl *DeclParam = getParameterAt(Res.FuncDeclRef, Idx);
57+
58+
bool Required = true;
59+
if (DeclParam && DeclParam->isDefaultArgument()) {
60+
Required = false;
61+
} else if (DeclParam && DeclParam->getType()->is<PackExpansionType>()) {
62+
Required = false;
63+
} else if (TypeParam->isVariadic()) {
64+
Required = false;
65+
}
5966

60-
if (P->hasLabel() && !(IsCompletion && Res.IsNoninitialVariadic)) {
67+
if (TypeParam->hasLabel() && !(IsCompletion && Res.IsNoninitialVariadic)) {
6168
// Suggest parameter label if parameter has label, we are completing in it
6269
// and it is not a variadic parameter that already has arguments
63-
PossibleParamInfo PP(P, Required);
70+
PossibleParamInfo PP(TypeParam, Required);
6471
if (!llvm::is_contained(Params, PP)) {
6572
Params.push_back(std::move(PP));
6673
}
6774
} else {
6875
// We have a parameter that doesn't require a label. Suggest global
6976
// results for that type.
7077
ShowGlobalCompletions = true;
71-
Types.push_back(P->getPlainType());
78+
Types.push_back(TypeParam->getPlainType());
7279
}
7380
if (Required) {
7481
// The user should only be suggested the first required param. Stop.
@@ -157,7 +164,7 @@ void ArgumentTypeCheckCompletionCallback::sawSolutionImpl(const Solution &S) {
157164
auto *CalleeLocator = S.getCalleeLocator(CallLocator);
158165

159166
auto Info = getSelectedOverloadInfo(S, CalleeLocator);
160-
if (Info.Value && Info.Value->shouldHideFromEditor()) {
167+
if (Info.getValue() && Info.getValue()->shouldHideFromEditor()) {
161168
return;
162169
}
163170
// Disallow invalid initializer references
@@ -215,7 +222,7 @@ void ArgumentTypeCheckCompletionCallback::sawSolutionImpl(const Solution &S) {
215222

216223
// If this is a duplicate of any other result, ignore this solution.
217224
if (llvm::any_of(Results, [&](const Result &R) {
218-
return R.FuncD == Info.Value &&
225+
return R.FuncDeclRef == Info.ValueRef &&
219226
nullableTypesEqual(R.FuncTy, Info.ValueTy) &&
220227
nullableTypesEqual(R.BaseType, Info.BaseTy) &&
221228
R.ParamIdx == ParamIdx &&
@@ -232,9 +239,10 @@ void ArgumentTypeCheckCompletionCallback::sawSolutionImpl(const Solution &S) {
232239
FuncTy = Info.ValueTy->lookThroughAllOptionalTypes()->getAs<AnyFunctionType>();
233240
}
234241
Results.push_back({ExpectedTy, ExpectedCallType,
235-
isa<SubscriptExpr>(ParentCall), Info.Value, FuncTy, ArgIdx,
236-
ParamIdx, std::move(ClaimedParams), IsNoninitialVariadic,
237-
Info.BaseTy, HasLabel, IsAsync, SolutionSpecificVarTypes});
242+
isa<SubscriptExpr>(ParentCall), Info.ValueRef, FuncTy,
243+
ArgIdx, ParamIdx, std::move(ClaimedParams),
244+
IsNoninitialVariadic, Info.BaseTy, HasLabel, IsAsync,
245+
SolutionSpecificVarTypes});
238246
}
239247

240248
void ArgumentTypeCheckCompletionCallback::computeShadowedDecls(
@@ -243,24 +251,25 @@ void ArgumentTypeCheckCompletionCallback::computeShadowedDecls(
243251
auto &ResultA = Results[i];
244252
for (size_t j = i + 1; j < Results.size(); ++j) {
245253
auto &ResultB = Results[j];
246-
if (!ResultA.FuncD || !ResultB.FuncD || !ResultA.FuncTy || !ResultB.FuncTy) {
254+
if (!ResultA.getFuncD() || !ResultB.getFuncD() || !ResultA.FuncTy ||
255+
!ResultB.FuncTy) {
247256
continue;
248257
}
249-
if (ResultA.FuncD->getName() != ResultB.FuncD->getName()) {
258+
if (ResultA.getFuncD()->getName() != ResultB.getFuncD()->getName()) {
250259
continue;
251260
}
252261
if (!ResultA.FuncTy->isEqual(ResultB.FuncTy)) {
253262
continue;
254263
}
255264
ProtocolDecl *inProtocolExtensionA =
256-
ResultA.FuncD->getDeclContext()->getExtendedProtocolDecl();
265+
ResultA.getFuncD()->getDeclContext()->getExtendedProtocolDecl();
257266
ProtocolDecl *inProtocolExtensionB =
258-
ResultB.FuncD->getDeclContext()->getExtendedProtocolDecl();
267+
ResultB.getFuncD()->getDeclContext()->getExtendedProtocolDecl();
259268

260269
if (inProtocolExtensionA && !inProtocolExtensionB) {
261-
ShadowedDecls.insert(ResultA.FuncD);
270+
ShadowedDecls.insert(ResultA.getFuncD());
262271
} else if (!inProtocolExtensionA && inProtocolExtensionB) {
263-
ShadowedDecls.insert(ResultB.FuncD);
272+
ShadowedDecls.insert(ResultB.getFuncD());
264273
}
265274
}
266275
}
@@ -301,35 +310,37 @@ void ArgumentTypeCheckCompletionCallback::deliverResults(
301310
}
302311
if ((BaseNominal = BaseTy->getAnyNominal())) {
303312
SemanticContext = SemanticContextKind::CurrentNominal;
304-
if (Result.FuncD &&
305-
Result.FuncD->getDeclContext()->getSelfNominalTypeDecl() !=
313+
if (Result.getFuncD() &&
314+
Result.getFuncD()->getDeclContext()->getSelfNominalTypeDecl() !=
306315
BaseNominal) {
307316
SemanticContext = SemanticContextKind::Super;
308317
}
309318
} else if (BaseTy->is<TupleType>() || BaseTy->is<SubstitutableType>()) {
310319
SemanticContext = SemanticContextKind::CurrentNominal;
311320
}
312321
}
313-
if (SemanticContext == SemanticContextKind::None && Result.FuncD) {
314-
if (Result.FuncD->getDeclContext()->isTypeContext()) {
322+
if (SemanticContext == SemanticContextKind::None && Result.getFuncD()) {
323+
if (Result.getFuncD()->getDeclContext()->isTypeContext()) {
315324
SemanticContext = SemanticContextKind::CurrentNominal;
316-
} else if (Result.FuncD->getDeclContext()->isLocalContext()) {
325+
} else if (Result.getFuncD()->getDeclContext()->isLocalContext()) {
317326
SemanticContext = SemanticContextKind::Local;
318-
} else if (Result.FuncD->getModuleContext() == DC->getParentModule()) {
327+
} else if (Result.getFuncD()->getModuleContext() ==
328+
DC->getParentModule()) {
319329
SemanticContext = SemanticContextKind::CurrentModule;
320330
}
321331
}
322332
if (Result.FuncTy) {
323333
if (auto FuncTy = Result.FuncTy) {
324-
if (ShadowedDecls.count(Result.FuncD) == 0) {
334+
if (ShadowedDecls.count(Result.getFuncD()) == 0) {
325335
// Don't show call pattern completions if the function is
326336
// overridden.
327337
if (Result.IsSubscript) {
328338
assert(SemanticContext != SemanticContextKind::None);
329-
auto *SD = dyn_cast_or_null<SubscriptDecl>(Result.FuncD);
339+
auto *SD = dyn_cast_or_null<SubscriptDecl>(Result.getFuncD());
330340
Lookup.addSubscriptCallPattern(FuncTy, SD, SemanticContext);
331341
} else {
332-
auto *FD = dyn_cast_or_null<AbstractFunctionDecl>(Result.FuncD);
342+
auto *FD =
343+
dyn_cast_or_null<AbstractFunctionDecl>(Result.getFuncD());
333344
Lookup.addFunctionCallPattern(FuncTy, FD, SemanticContext);
334345
}
335346
}

lib/IDE/CursorInfo.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ class CursorInfoTypeCheckSolutionCallback : public TypeCheckCompletionCallback {
311311
auto Locator = CS.getConstraintLocator(ResolveExpr);
312312
auto CalleeLocator = S.getCalleeLocator(Locator);
313313
auto OverloadInfo = getSelectedOverloadInfo(S, CalleeLocator);
314-
if (!OverloadInfo.Value) {
314+
if (!OverloadInfo.ValueRef) {
315315
// We could not resolve the referenced declaration. Skip the solution.
316316
return;
317317
}
@@ -322,11 +322,12 @@ class CursorInfoTypeCheckSolutionCallback : public TypeCheckCompletionCallback {
322322
if (auto BaseExpr =
323323
simplifyLocatorToAnchor(BaseLocator).dyn_cast<Expr *>()) {
324324
IsDynamicRef =
325-
ide::isDynamicRef(BaseExpr, OverloadInfo.Value,
325+
ide::isDynamicRef(BaseExpr, OverloadInfo.getValue(),
326326
[&S](Expr *E) { return S.getResolvedType(E); });
327327
}
328328

329-
Results.push_back({OverloadInfo.BaseTy, IsDynamicRef, OverloadInfo.Value});
329+
Results.push_back(
330+
{OverloadInfo.BaseTy, IsDynamicRef, OverloadInfo.getValue()});
330331
}
331332

332333
public:

lib/IDE/SelectedOverloadInfo.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ swift::ide::getSelectedOverloadInfo(const Solution &S,
4040
Result.BaseTy = nullptr;
4141
}
4242

43-
Result.Value = SelectedOverload->choice.getDeclOrNull();
43+
if (auto ReferencedDecl = SelectedOverload->choice.getDeclOrNull()) {
44+
Result.ValueRef = S.resolveConcreteDeclRef(ReferencedDecl, CalleeLocator);
45+
}
4446
Result.ValueTy =
4547
S.simplifyTypeForCodeCompletion(SelectedOverload->adjustedOpenedType);
4648

test/IDE/complete_call_arg.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,3 +1303,10 @@ func testMacroArg() {
13031303
// MACRO_CALL_ARG-DAG: Literal[Boolean]/None: true[#Bool#]; name=true
13041304
// MACRO_CALL_ARG: End completions
13051305
}
1306+
1307+
func testParameterPack(intArray: [Int]) {
1308+
func myZip<each S>(_ sequence: repeat each S, otherParam: Int) where repeat each S: Sequence {}
1309+
myZip([1], #^PARAMETER_PACK_ARG^#)
1310+
// PARAMETER_PACK_ARG: Pattern/Local/Flair[ArgLabels]: {#otherParam: Int#}[#Int#]; name=otherParam:
1311+
// PARAMETER_PACK_ARG: Decl[LocalVar]/Local/TypeRelation[Convertible]: intArray[#[Int]#]; name=intArray
1312+
}

0 commit comments

Comments
 (0)