Skip to content

Commit cb0a21d

Browse files
authored
Merge pull request #83170 from hamishknight/fix-assert
[IDE] Fix assertion failure in `PostfixCompletionCallback::Result::tryMerge`
2 parents bed6408 + 62f1303 commit cb0a21d

File tree

6 files changed

+61
-25
lines changed

6 files changed

+61
-25
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6093,6 +6093,7 @@ bool isAutoClosureArgument(Expr *argExpr);
60936093
/// parameter being applied, meaning that it's dropped from the type of the
60946094
/// reference.
60956095
bool hasAppliedSelf(ConstraintSystem &cs, const OverloadChoice &choice);
6096+
bool hasAppliedSelf(const Solution &S, const OverloadChoice &choice);
60966097
bool hasAppliedSelf(const OverloadChoice &choice,
60976098
llvm::function_ref<Type(Type)> getFixedType);
60986099

lib/IDE/PostfixCompletion.cpp

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ bool PostfixCompletionCallback::Result::tryMerge(const Result &Other,
2727
if (BaseDecl != Other.BaseDecl)
2828
return false;
2929

30-
// These properties should match if we are talking about the same BaseDecl.
31-
assert(IsBaseDeclUnapplied == Other.IsBaseDeclUnapplied);
30+
// This should match if we are talking about the same BaseDecl.
3231
assert(BaseIsStaticMetaType == Other.BaseIsStaticMetaType);
3332

3433
auto baseTy = tryMergeBaseTypeForCompletionLookup(BaseTy, Other.BaseTy, DC);
@@ -56,6 +55,12 @@ bool PostfixCompletionCallback::Result::tryMerge(const Result &Other,
5655
ExpectsNonVoid &= Other.ExpectsNonVoid;
5756
IsImpliedResult |= Other.IsImpliedResult;
5857
IsInAsyncContext |= Other.IsInAsyncContext;
58+
59+
// Note this may differ if we pre-check multiple times since pre-checking
60+
// changes the recorded apply level.
61+
// FIXME: We ought to fix completion to not pre-check multiple times.
62+
IsBaseDeclUnapplied |= Other.IsBaseDeclUnapplied;
63+
5964
return true;
6065
}
6166

@@ -119,25 +124,26 @@ getClosureActorIsolation(const Solution &S, AbstractClosureExpr *ACE) {
119124
getClosureActorIsolationThunk);
120125
}
121126

122-
/// Returns \c true if \p Choice refers to a function that hasn't been called
123-
/// yet.
124-
static bool isUnappliedFunctionRef(const OverloadChoice &Choice) {
125-
if (!Choice.isDecl()) {
127+
/// Returns \c true if \p Choice refers to a function that has been fully
128+
/// applied, including the curried self if present.
129+
static bool isFullyAppliedFunctionRef(const Solution &S,
130+
const OverloadChoice &Choice) {
131+
auto *D = Choice.getDeclOrNull();
132+
if (!D)
126133
return false;
127-
}
128-
auto fnRefKind = Choice.getFunctionRefInfo();
129134

130-
if (fnRefKind.isUnapplied())
135+
switch (Choice.getFunctionRefInfo().getApplyLevel()) {
136+
case FunctionRefInfo::ApplyLevel::Unapplied:
137+
// No argument lists have been applied.
138+
return false;
139+
case FunctionRefInfo::ApplyLevel::SingleApply:
140+
// The arguments have been applied, check to see if the curried self has
141+
// been applied if present.
142+
return !D->hasCurriedSelf() || hasAppliedSelf(S, Choice);
143+
case FunctionRefInfo::ApplyLevel::DoubleApply:
144+
// All argument lists have been applied.
131145
return true;
132-
133-
// We consider curried member calls as unapplied. E.g.
134-
// MyStruct.someInstanceFunc(theInstance)#^COMPLETE^#
135-
// is unapplied.
136-
if (fnRefKind.isSingleApply()) {
137-
if (auto BaseTy = Choice.getBaseType())
138-
return BaseTy->is<MetatypeType>() && !Choice.getDeclOrNull()->isStatic();
139146
}
140-
return false;
141147
}
142148

143149
void PostfixCompletionCallback::sawSolutionImpl(
@@ -166,7 +172,8 @@ void PostfixCompletionCallback::sawSolutionImpl(
166172
bool IsBaseDeclUnapplied = false;
167173
if (auto SelectedOverload = S.getOverloadChoiceIfAvailable(CalleeLocator)) {
168174
ReferencedDecl = SelectedOverload->choice.getDeclOrNull();
169-
IsBaseDeclUnapplied = isUnappliedFunctionRef(SelectedOverload->choice);
175+
IsBaseDeclUnapplied = ReferencedDecl && !isFullyAppliedFunctionRef(
176+
S, SelectedOverload->choice);
170177
}
171178

172179
bool BaseIsStaticMetaType = S.isStaticallyDerivedMetatype(ParsedExpr);

lib/Sema/CSDiagnostics.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2831,10 +2831,7 @@ bool ContextualFailure::diagnoseAsError() {
28312831
auto params = fnType->getParams();
28322832

28332833
ParameterListInfo info(
2834-
params, choice,
2835-
hasAppliedSelf(overload->choice, [&solution](Type type) {
2836-
return solution.simplifyType(type);
2837-
}));
2834+
params, choice, hasAppliedSelf(solution, overload->choice));
28382835
auto numMissingArgs = llvm::count_if(
28392836
indices(params), [&info](const unsigned paramIdx) -> bool {
28402837
return !info.hasDefaultArgument(paramIdx);

lib/Sema/ConstraintSystem.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3891,6 +3891,13 @@ bool constraints::hasAppliedSelf(ConstraintSystem &cs,
38913891
});
38923892
}
38933893

3894+
bool constraints::hasAppliedSelf(const Solution &S,
3895+
const OverloadChoice &choice) {
3896+
return hasAppliedSelf(choice, [&](Type type) -> Type {
3897+
return S.simplifyType(type);
3898+
});
3899+
}
3900+
38943901
bool constraints::hasAppliedSelf(const OverloadChoice &choice,
38953902
llvm::function_ref<Type(Type)> getFixedType) {
38963903
auto *decl = choice.getDeclOrNull();
@@ -4206,8 +4213,7 @@ Solution::getFunctionArgApplyInfo(ConstraintLocator *locator) const {
42064213
fnInterfaceType = callee->getInterfaceType();
42074214

42084215
// Strip off the curried self parameter if necessary.
4209-
if (hasAppliedSelf(
4210-
*choice, [this](Type type) -> Type { return simplifyType(type); }))
4216+
if (hasAppliedSelf(*this, *choice))
42114217
fnInterfaceType = fnInterfaceType->castTo<AnyFunctionType>()->getResult();
42124218

42134219
#ifndef NDEBUG
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
// {"kind":"complete","signature":"swift::ide::PostfixCompletionCallback::Result::tryMerge(swift::ide::PostfixCompletionCallback::Result const&, swift::DeclContext*)"}
2-
// RUN: not --crash %target-swift-ide-test -code-completion --code-completion-token=COMPLETE -code-completion-diagnostics -source-filename %s
2+
// RUN: %target-swift-ide-test -code-completion --code-completion-token=COMPLETE -code-completion-diagnostics -source-filename %s
33
Int { switch { case Optional.some()#^COMPLETE^#

validation-test/IDE/issues_fixed/issue-75845.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,28 @@ struct Foo {
1515
// B: Begin completions
1616
// C: Decl[LocalVar]/Local: error[#any Error#]; name=error
1717
// D: Begin completions
18+
19+
enum E {
20+
case e(Error)
21+
22+
func foo() {
23+
var x = self
24+
do {
25+
} catch {
26+
x = .e(error)#^E^#
27+
// E: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: .foo()[#Void#]; name=foo()
28+
}
29+
}
30+
31+
static func bar() {
32+
do {
33+
} catch {
34+
_ = foo(.e(error))#^F^#
35+
// F: Decl[InstanceMethod]/CurrNominal/Flair[ArgLabels]: ()[#Void#]; name=()
36+
37+
_ = foo(.e(error))()#^G^#
38+
// G: Begin completions, 1 items
39+
// G: Keyword[self]/CurrNominal: .self[#Void#]; name=self
40+
}
41+
}
42+
}

0 commit comments

Comments
 (0)