Skip to content

Commit 0cccac3

Browse files
committed
[CodeCompletion] Fix ASAN failure when completing in parameter packs
Whe completing in parameter packs, we were calling `getParameterAt` with `Res.FuncDeclRef`. But the substitution map in `Res.FuncDeclRef` contained type variables that were allocated in the constraint system’s arena. And that arena had been freed when we call this from `deliverResults`. The fix is to compute the optional parameters in advance in `sawSolutionImpl` rdar://109093909
1 parent 5cd2b98 commit 0cccac3

File tree

2 files changed

+51
-40
lines changed

2 files changed

+51
-40
lines changed

include/swift/IDE/ArgumentCompletion.h

Lines changed: 9 additions & 5 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 reference to the FuncDecl or SubscriptDecl associated with the call.
33-
ConcreteDeclRef FuncDeclRef;
32+
/// The FuncDecl or SubscriptDecl associated with the call.
33+
ValueDecl *FuncD;
3434
/// The type of the function being called.
3535
AnyFunctionType *FuncTy;
3636
/// The index of the argument containing the completion location
@@ -50,14 +50,18 @@ class ArgumentTypeCheckCompletionCallback : public TypeCheckCompletionCallback {
5050
/// Whether the surrounding context is async and thus calling async
5151
/// functions is supported.
5252
bool IsInAsyncContext;
53+
/// A bitfield to mark whether the parameter at a given index is optional.
54+
/// Parameters can be optional if they have a default argument or belong to
55+
/// a parameter pack.
56+
/// Indicies are based on the parameters in \c FuncTy. Note that the number
57+
/// of parameters in \c FuncTy and \c FuncD is different when a parameter
58+
/// pack has been exploded.
59+
std::vector<bool> DeclParamIsOptional;
5360

5461
/// Types of variables that were determined in the solution that produced
5562
/// this result. This in particular includes parameters of closures that
5663
/// were type-checked with the code completion expression.
5764
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(); }
6165
};
6266

6367
CodeCompletionExpr *CompletionExpr;

lib/IDE/ArgumentCompletion.cpp

Lines changed: 42 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -47,22 +47,8 @@ bool ArgumentTypeCheckCompletionCallback::addPossibleParams(
4747
break;
4848
}
4949

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`.
5550
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-
}
51+
bool Required = !Res.DeclParamIsOptional[Idx];
6652

6753
if (TypeParam->hasLabel() && !(IsCompletion && Res.IsNoninitialVariadic)) {
6854
// Suggest parameter label if parameter has label, we are completing in it
@@ -222,7 +208,7 @@ void ArgumentTypeCheckCompletionCallback::sawSolutionImpl(const Solution &S) {
222208

223209
// If this is a duplicate of any other result, ignore this solution.
224210
if (llvm::any_of(Results, [&](const Result &R) {
225-
return R.FuncDeclRef == Info.ValueRef &&
211+
return R.FuncD == Info.getValue() &&
226212
nullableTypesEqual(R.FuncTy, Info.ValueTy) &&
227213
nullableTypesEqual(R.BaseType, Info.BaseTy) &&
228214
R.ParamIdx == ParamIdx &&
@@ -238,11 +224,34 @@ void ArgumentTypeCheckCompletionCallback::sawSolutionImpl(const Solution &S) {
238224
if (Info.ValueTy) {
239225
FuncTy = Info.ValueTy->lookThroughAllOptionalTypes()->getAs<AnyFunctionType>();
240226
}
227+
228+
// Determine which parameters is optional. We need to do this in
229+
// `sawSolutionImpl` because it accesses the substitution map in
230+
// `Info.ValueRef`. This substitution map might contain tyep variables that
231+
// are allocated in the constraint system's arena and are freed once we reach
232+
// `deliverResults`.
233+
std::vector<bool> DeclParamIsOptional;
234+
if (FuncTy) {
235+
ArrayRef<AnyFunctionType::Param> ParamsToPass = FuncTy->getParams();
236+
for (auto Idx : range(0, ParamsToPass.size())) {
237+
bool Optional = false;
238+
if (Info.ValueRef) {
239+
if (const ParamDecl *DeclParam = getParameterAt(Info.ValueRef, Idx)) {
240+
Optional |= DeclParam->isDefaultArgument();
241+
Optional |= DeclParam->getType()->is<PackExpansionType>();
242+
}
243+
}
244+
const AnyFunctionType::Param *TypeParam = &ParamsToPass[Idx];
245+
Optional |= TypeParam->isVariadic();
246+
DeclParamIsOptional.push_back(Optional);
247+
}
248+
}
249+
241250
Results.push_back({ExpectedTy, ExpectedCallType,
242-
isa<SubscriptExpr>(ParentCall), Info.ValueRef, FuncTy,
251+
isa<SubscriptExpr>(ParentCall), Info.getValue(), FuncTy,
243252
ArgIdx, ParamIdx, std::move(ClaimedParams),
244253
IsNoninitialVariadic, Info.BaseTy, HasLabel, IsAsync,
245-
SolutionSpecificVarTypes});
254+
DeclParamIsOptional, SolutionSpecificVarTypes});
246255
}
247256

248257
void ArgumentTypeCheckCompletionCallback::computeShadowedDecls(
@@ -251,25 +260,25 @@ void ArgumentTypeCheckCompletionCallback::computeShadowedDecls(
251260
auto &ResultA = Results[i];
252261
for (size_t j = i + 1; j < Results.size(); ++j) {
253262
auto &ResultB = Results[j];
254-
if (!ResultA.getFuncD() || !ResultB.getFuncD() || !ResultA.FuncTy ||
263+
if (!ResultA.FuncD || !ResultB.FuncD || !ResultA.FuncTy ||
255264
!ResultB.FuncTy) {
256265
continue;
257266
}
258-
if (ResultA.getFuncD()->getName() != ResultB.getFuncD()->getName()) {
267+
if (ResultA.FuncD->getName() != ResultB.FuncD->getName()) {
259268
continue;
260269
}
261270
if (!ResultA.FuncTy->isEqual(ResultB.FuncTy)) {
262271
continue;
263272
}
264273
ProtocolDecl *inProtocolExtensionA =
265-
ResultA.getFuncD()->getDeclContext()->getExtendedProtocolDecl();
274+
ResultA.FuncD->getDeclContext()->getExtendedProtocolDecl();
266275
ProtocolDecl *inProtocolExtensionB =
267-
ResultB.getFuncD()->getDeclContext()->getExtendedProtocolDecl();
276+
ResultB.FuncD->getDeclContext()->getExtendedProtocolDecl();
268277

269278
if (inProtocolExtensionA && !inProtocolExtensionB) {
270-
ShadowedDecls.insert(ResultA.getFuncD());
279+
ShadowedDecls.insert(ResultA.FuncD);
271280
} else if (!inProtocolExtensionA && inProtocolExtensionB) {
272-
ShadowedDecls.insert(ResultB.getFuncD());
281+
ShadowedDecls.insert(ResultB.FuncD);
273282
}
274283
}
275284
}
@@ -310,37 +319,35 @@ void ArgumentTypeCheckCompletionCallback::deliverResults(
310319
}
311320
if ((BaseNominal = BaseTy->getAnyNominal())) {
312321
SemanticContext = SemanticContextKind::CurrentNominal;
313-
if (Result.getFuncD() &&
314-
Result.getFuncD()->getDeclContext()->getSelfNominalTypeDecl() !=
322+
if (Result.FuncD &&
323+
Result.FuncD->getDeclContext()->getSelfNominalTypeDecl() !=
315324
BaseNominal) {
316325
SemanticContext = SemanticContextKind::Super;
317326
}
318327
} else if (BaseTy->is<TupleType>() || BaseTy->is<SubstitutableType>()) {
319328
SemanticContext = SemanticContextKind::CurrentNominal;
320329
}
321330
}
322-
if (SemanticContext == SemanticContextKind::None && Result.getFuncD()) {
323-
if (Result.getFuncD()->getDeclContext()->isTypeContext()) {
331+
if (SemanticContext == SemanticContextKind::None && Result.FuncD) {
332+
if (Result.FuncD->getDeclContext()->isTypeContext()) {
324333
SemanticContext = SemanticContextKind::CurrentNominal;
325-
} else if (Result.getFuncD()->getDeclContext()->isLocalContext()) {
334+
} else if (Result.FuncD->getDeclContext()->isLocalContext()) {
326335
SemanticContext = SemanticContextKind::Local;
327-
} else if (Result.getFuncD()->getModuleContext() ==
328-
DC->getParentModule()) {
336+
} else if (Result.FuncD->getModuleContext() == DC->getParentModule()) {
329337
SemanticContext = SemanticContextKind::CurrentModule;
330338
}
331339
}
332340
if (Result.FuncTy) {
333341
if (auto FuncTy = Result.FuncTy) {
334-
if (ShadowedDecls.count(Result.getFuncD()) == 0) {
342+
if (ShadowedDecls.count(Result.FuncD) == 0) {
335343
// Don't show call pattern completions if the function is
336344
// overridden.
337345
if (Result.IsSubscript) {
338346
assert(SemanticContext != SemanticContextKind::None);
339-
auto *SD = dyn_cast_or_null<SubscriptDecl>(Result.getFuncD());
347+
auto *SD = dyn_cast_or_null<SubscriptDecl>(Result.FuncD);
340348
Lookup.addSubscriptCallPattern(FuncTy, SD, SemanticContext);
341349
} else {
342-
auto *FD =
343-
dyn_cast_or_null<AbstractFunctionDecl>(Result.getFuncD());
350+
auto *FD = dyn_cast_or_null<AbstractFunctionDecl>(Result.FuncD);
344351
Lookup.addFunctionCallPattern(FuncTy, FD, SemanticContext);
345352
}
346353
}

0 commit comments

Comments
 (0)