Skip to content

Commit 27639c2

Browse files
committed
[CodeCompletion] Lenient argument label checking if matching overload not found
If label-matching overload is not found, try to find a position with lenient label matching.
1 parent 8d63f29 commit 27639c2

File tree

2 files changed

+63
-26
lines changed

2 files changed

+63
-26
lines changed

lib/IDE/ExprContextAnalysis.cpp

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -771,22 +771,22 @@ static Expr *getArgAtPosition(Expr *Args, unsigned Position) {
771771
/// be different than the position in \p Args if there are defaulted arguments
772772
/// in \p Params which don't occur in \p Args.
773773
///
774-
/// \returns \c true if success, \c false if \p CCExpr is not a part of \p Args.
775-
static bool getPositionInParams(DeclContext &DC, Expr *Args, Expr *CCExpr,
776-
ArrayRef<AnyFunctionType::Param> Params,
777-
unsigned &PosInParams) {
774+
/// \returns the position index number on success, \c None if \p CCExpr is not
775+
/// a part of \p Args.
776+
static Optional<unsigned>
777+
getPositionInParams(DeclContext &DC, Expr *Args, Expr *CCExpr,
778+
ArrayRef<AnyFunctionType::Param> Params, bool Lenient) {
778779
if (isa<ParenExpr>(Args)) {
779-
PosInParams = 0;
780-
return true;
780+
return 0;
781781
}
782782

783783
auto *tuple = dyn_cast<TupleExpr>(Args);
784784
if (!tuple) {
785-
return false;
785+
return None;
786786
}
787787

788788
auto &SM = DC.getASTContext().SourceMgr;
789-
PosInParams = 0;
789+
unsigned PosInParams = 0;
790790
unsigned PosInArgs = 0;
791791
bool LastParamWasVariadic = false;
792792
// We advance PosInArgs until we find argument that is after the code
@@ -847,16 +847,22 @@ static bool getPositionInParams(DeclContext &DC, Expr *Args, Expr *CCExpr,
847847
}
848848

849849
if (!AdvancedPosInParams) {
850-
// If there is no matching argument label. These arguments can't be
851-
// applied to the params.
852-
return false;
850+
if (Lenient) {
851+
// We haven't performed any special advance logic. Assume the argument
852+
// and parameter match, so advance PosInParams by 1.
853+
PosInParams += 1;
854+
} else {
855+
// If there is no matching argument label. These arguments can't be
856+
// applied to the params.
857+
return None;
858+
}
853859
}
854860
}
855861
if (PosInArgs < tuple->getNumElements() && PosInParams < Params.size()) {
856862
// We didn't search until the end, so we found a position in Params. Success
857-
return true;
863+
return PosInParams;
858864
} else {
859-
return false;
865+
return None;
860866
}
861867
}
862868

@@ -947,21 +953,45 @@ class ExprContextAnalyzer {
947953
}
948954
SmallPtrSet<CanType, 4> seenTypes;
949955
llvm::SmallSet<std::pair<Identifier, CanType>, 4> seenArgs;
950-
for (auto &typeAndDecl : Candidates) {
951-
DeclContext *memberDC = nullptr;
952-
if (typeAndDecl.Decl)
953-
memberDC = typeAndDecl.Decl->getInnermostDeclContext();
956+
llvm::SmallVector<Optional<unsigned>, 2> posInParams;
957+
{
958+
bool found = false;
959+
for (auto &typeAndDecl : Candidates) {
960+
Optional<unsigned> pos = getPositionInParams(
961+
*DC, Args, ParsedExpr, typeAndDecl.Type->getParams(),
962+
/*lenient=*/false);
963+
posInParams.push_back(pos);
964+
found |= pos.hasValue();
965+
}
966+
if (!found) {
967+
// If applicable overload is not found, retry with considering
968+
// non-matching argument labels mis-typed.
969+
for (auto i : indices(Candidates)) {
970+
posInParams[i] = getPositionInParams(
971+
*DC, Args, ParsedExpr, Candidates[i].Type->getParams(),
972+
/*lenient=*/true);
973+
}
974+
}
975+
}
976+
assert(posInParams.size() == Candidates.size());
954977

955-
auto Params = typeAndDecl.Type->getParams();
956-
unsigned PositionInParams;
957-
if (!getPositionInParams(*DC, Args, ParsedExpr, Params,
958-
PositionInParams)) {
978+
for (auto i : indices(Candidates)) {
979+
if (!posInParams[i].hasValue()) {
959980
// If the argument doesn't have a matching position in the parameters,
960981
// indicate that with optional nullptr param.
961982
if (seenArgs.insert({Identifier(), CanType()}).second)
962983
recordPossibleParam(nullptr, /*isRequired=*/false);
963984
continue;
964985
}
986+
987+
auto &typeAndDecl = Candidates[i];
988+
DeclContext *memberDC = nullptr;
989+
if (typeAndDecl.Decl)
990+
memberDC = typeAndDecl.Decl->getInnermostDeclContext();
991+
992+
auto Params = typeAndDecl.Type->getParams();
993+
auto PositionInParams = *posInParams[i];
994+
965995
ParameterList *paramList = nullptr;
966996
if (auto VD = typeAndDecl.Decl) {
967997
paramList = getParameterList(VD);

test/IDE/complete_call_arg.swift

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -939,10 +939,17 @@ struct Rdar77867723 {
939939
enum Vertical { case up, down }
940940
func fn(aaa: Horizontal = .east, bbb: Vertical = .up) {}
941941
func fn(ccc: Vertical = .up, ddd: Horizontal = .west) {}
942-
func test {
943-
self.fn(ccc: .up, #^OVERLOAD_LABEL^#)
944-
// OVERLOAD_LABEL: Begin completions, 1 items
945-
// OVERLOAD_LABEL-DAG: Pattern/ExprSpecific: {#ddd: Horizontal#}[#Horizontal#];
946-
// OVERLOAD_LABEL: End completions
942+
func test1 {
943+
self.fn(ccc: .up, #^OVERLOAD_LABEL1^#)
944+
// OVERLOAD_LABEL1: Begin completions, 1 items
945+
// OVERLOAD_LABEL1-DAG: Pattern/ExprSpecific: {#ddd: Horizontal#}[#Horizontal#];
946+
// OVERLOAD_LABEL1: End completions
947+
}
948+
func test2 {
949+
self.fn(eee: .up, #^OVERLOAD_LABEL2^#)
950+
// OVERLOAD_LABEL2: Begin completions, 2 items
951+
// OVERLOAD_LABEL2-DAG: Pattern/ExprSpecific: {#bbb: Vertical#}[#Vertical#];
952+
// OVERLOAD_LABEL2-DAG: Pattern/ExprSpecific: {#ddd: Horizontal#}[#Horizontal#];
953+
// OVERLOAD_LABEL2: End completions
947954
}
948955
}

0 commit comments

Comments
 (0)