Skip to content

Commit e7e3097

Browse files
authored
Merge pull request #37432 from rintaro/ide-completion-rdar77867723
[CodeCompletion] Don't suggest argument labels from unapplicable overload
2 parents 4d91f79 + 27639c2 commit e7e3097

File tree

3 files changed

+77
-27
lines changed

3 files changed

+77
-27
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-
// We haven't performed any special advance logic. Assume the argument
851-
// and parameter match, so advance PosInParams by 1.
852-
++PosInParams;
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: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -933,3 +933,23 @@ func testGenericConstructor() {
933933
// GENERIC_INITIALIZER-DAG: Pattern/ExprSpecific: {#text: String#}[#String#]
934934
// GENERIC_INITIALIZER: End completions
935935
}
936+
937+
struct Rdar77867723 {
938+
enum Horizontal { case east, west }
939+
enum Vertical { case up, down }
940+
func fn(aaa: Horizontal = .east, bbb: Vertical = .up) {}
941+
func fn(ccc: Vertical = .up, ddd: Horizontal = .west) {}
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
954+
}
955+
}

test/SourceKit/CodeComplete/complete_type_match.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,32 +14,32 @@ func takeIntOpt(x: Int, y: Int?)
1414
func takeString(x: Int, y: String)
1515
func takeAny(x: Int, y: Any)
1616

17-
takeInt(1, y: #^TOP_LEVEL_0^#)
17+
takeInt(x: 1, y: #^TOP_LEVEL_0^#)
1818
// TOP_LEVEL_0-NOT: nil
1919
// TOP_LEVEL_0: valueZ
2020
// TOP_LEVEL_0: Int
2121
// TOP_LEVEL_0: valueA
2222
// TOP_LEVEL_0: valueS
2323

24-
takeString(1, y: #^TOP_LEVEL_1^#)
24+
takeString(x: 1, y: #^TOP_LEVEL_1^#)
2525
// TOP_LEVEL_1: valueS
2626
// TOP_LEVEL_1: String
2727
// TOP_LEVEL_1: valueA
2828
// TOP_LEVEL_1: valueZ
2929

30-
takeAny(1, y: #^TOP_LEVEL_2^#)
30+
takeAny(x: 1, y: #^TOP_LEVEL_2^#)
3131
// TOP_LEVEL_2: valueA
3232
// TOP_LEVEL_2: valueS
3333
// TOP_LEVEL_2: valueZ
3434

35-
takeIntOpt(1, y: #^TOP_LEVEL_3^#)
35+
takeIntOpt(x: 1, y: #^TOP_LEVEL_3^#)
3636
// TOP_LEVEL_3: nil
3737
// TOP_LEVEL_3: valueZ
3838
// TOP_LEVEL_3: valueA
3939
// TOP_LEVEL_3: valueS
4040

4141
func testCrossContext(x: Int, y: String, z: Any) {
42-
takeInt(1, y: #^CROSS_CONTEXT_0^#)
42+
takeInt(x: 1, y: #^CROSS_CONTEXT_0^#)
4343
}
4444
// CROSS_CONTEXT_0: x
4545
// CROSS_CONTEXT_0: valueZ
@@ -56,7 +56,7 @@ struct FromMethod {
5656
}
5757

5858
func testFromMethod(x: FromMethod) {
59-
takeInt(1, y: x.#^FROM_METHOD_0^#)
59+
takeInt(x: 1, y: x.#^FROM_METHOD_0^#)
6060
}
6161
// FROM_METHOD_0: valueZ()
6262
// FROM_METHOD_0: valueA()

0 commit comments

Comments
 (0)