Skip to content

Commit 31c4602

Browse files
authored
Merge pull request #73042 from ahoppen/6.0/parameter-pack-pattern-crash
[CodeCompletion] Fix a crash when completing the call pattern of a function that takes a parameter pack
2 parents 03c948d + 99f914f commit 31c4602

11 files changed

+68
-64
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -908,7 +908,7 @@ class FunctionArgApplyInfo {
908908
bool lookThroughAutoclosure) const {
909909
auto param = fnTy->getParams()[ParamIdx];
910910
auto paramTy = param.getPlainType();
911-
if (lookThroughAutoclosure && param.isAutoClosure())
911+
if (lookThroughAutoclosure && param.isAutoClosure() && paramTy->is<FunctionType>())
912912
paramTy = paramTy->castTo<FunctionType>()->getResult();
913913
return paramTy;
914914
}

lib/IDE/ArgumentCompletion.cpp

Lines changed: 14 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -89,43 +89,6 @@ bool ArgumentTypeCheckCompletionCallback::addPossibleParams(
8989
return ShowGlobalCompletions;
9090
}
9191

92-
/// Applies heuristic to determine whether the result type of \p E is
93-
/// unconstrained, that is if the constraint system is satisfiable for any
94-
/// result type of \p E.
95-
static bool isExpressionResultTypeUnconstrained(const Solution &S, Expr *E) {
96-
ConstraintSystem &CS = S.getConstraintSystem();
97-
if (auto ParentExpr = CS.getParentExpr(E)) {
98-
if (auto Assign = dyn_cast<AssignExpr>(ParentExpr)) {
99-
if (isa<DiscardAssignmentExpr>(Assign->getDest())) {
100-
// _ = <expr> is unconstrained
101-
return true;
102-
}
103-
} else if (isa<RebindSelfInConstructorExpr>(ParentExpr)) {
104-
// super.init() is unconstrained (it always produces the correct result
105-
// by definition)
106-
return true;
107-
}
108-
}
109-
auto target = S.getTargetFor(E);
110-
if (!target)
111-
return false;
112-
113-
assert(target->kind == SyntacticElementTarget::Kind::expression);
114-
switch (target->getExprContextualTypePurpose()) {
115-
case CTP_Unused:
116-
// If we aren't using the contextual type, its unconstrained by definition.
117-
return true;
118-
case CTP_Initialization: {
119-
// let x = <expr> is unconstrained
120-
auto contextualType = target->getExprContextualType();
121-
return !contextualType || contextualType->is<UnresolvedType>();
122-
}
123-
default:
124-
// Assume that it's constrained by default.
125-
return false;
126-
}
127-
}
128-
12992
/// Returns whether `E` has a parent expression with arguments.
13093
static bool hasParentCallLikeExpr(Expr *E, ConstraintSystem &CS) {
13194
E = CS.getParentExpr(E);
@@ -172,10 +135,21 @@ void ArgumentTypeCheckCompletionCallback::sawSolutionImpl(const Solution &S) {
172135
auto ArgIdx = ArgInfo->completionIdx;
173136

174137
Type ExpectedCallType;
175-
if (!isExpressionResultTypeUnconstrained(S, ParentCall)) {
176-
ExpectedCallType = getTypeForCompletion(S, ParentCall);
138+
if (auto ArgLoc = S.getConstraintSystem().getArgumentLocator(ParentCall)) {
139+
if (auto FuncArgApplyInfo = S.getFunctionArgApplyInfo(ArgLoc)) {
140+
Type ParamType = FuncArgApplyInfo->getParamInterfaceType();
141+
ExpectedCallType = S.simplifyTypeForCodeCompletion(ParamType);
142+
}
177143
}
178-
144+
if (!ExpectedCallType) {
145+
if (auto ContextualType = S.getContextualType(ParentCall)) {
146+
ExpectedCallType = ContextualType;
147+
}
148+
}
149+
if (ExpectedCallType && ExpectedCallType->hasUnresolvedType()) {
150+
ExpectedCallType = Type();
151+
}
152+
179153
auto *CallLocator = CS.getConstraintLocator(ParentCall);
180154
auto *CalleeLocator = S.getCalleeLocator(CallLocator);
181155

lib/Sema/CSApply.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,15 @@ Solution::computeSubstitutions(NullablePtr<ValueDecl> decl,
9898
TypeSubstitutionMap subs;
9999
for (const auto &opened : openedTypes->second) {
100100
auto type = getFixedType(opened.second);
101-
if (opened.first->isParameterPack() && !type->is<PackType>())
102-
type = PackType::getSingletonPackExpansion(type);
101+
if (opened.first->isParameterPack()) {
102+
if (type->is<PlaceholderType>()) {
103+
auto &ctx = type->getASTContext();
104+
type =
105+
PackType::get(ctx, {PackExpansionType::get(ctx.TheUnresolvedType,
106+
ctx.TheUnresolvedType)});
107+
} else if (!type->is<PackType>())
108+
type = PackType::getSingletonPackExpansion(type);
109+
}
103110
subs[opened.first] = type;
104111
}
105112

test/IDE/complete_call_arg.swift

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -576,17 +576,17 @@ func testStaticMemberCall() {
576576
func testImplicitMember() {
577577
let _: TestStaticMemberCall = .create1(#^IMPLICIT_MEMBER_AFTERPAREN_1^#)
578578
// IMPLICIT_MEMBER_AFTERPAREN_1: Begin completions, 1 items
579-
// IMPLICIT_MEMBER_AFTERPAREN_1: Decl[StaticMethod]/CurrNominal/Flair[ArgLabels]/TypeRelation[Convertible]: ['(']{#arg1: Int#}[')'][#TestStaticMemberCall#]; name=arg1:
579+
// IMPLICIT_MEMBER_AFTERPAREN_1: Decl[StaticMethod]/CurrNominal/Flair[ArgLabels]: ['(']{#arg1: Int#}[')'][#TestStaticMemberCall#]; name=arg1:
580580

581581
let _: TestStaticMemberCall = .create2(#^IMPLICIT_MEMBER_AFTERPAREN_2^#)
582-
// IMPLICIT_MEMBER_AFTERPAREN_2-DAG: Decl[StaticMethod]/CurrNominal/Flair[ArgLabels]/TypeRelation[Convertible]: ['(']{#(arg1): Int#}[')'][#TestStaticMemberCall#];
583-
// IMPLICIT_MEMBER_AFTERPAREN_2-DAG: Decl[StaticMethod]/CurrNominal/Flair[ArgLabels]/TypeRelation[Convertible]: ['(']{#(arg1): Int#}, {#arg2: Int#}, {#arg3: Int#}, {#arg4: Int#}[')'][#TestStaticMemberCall#];
582+
// IMPLICIT_MEMBER_AFTERPAREN_2-DAG: Decl[StaticMethod]/CurrNominal/Flair[ArgLabels]: ['(']{#(arg1): Int#}[')'][#TestStaticMemberCall#];
583+
// IMPLICIT_MEMBER_AFTERPAREN_2-DAG: Decl[StaticMethod]/CurrNominal/Flair[ArgLabels]: ['(']{#(arg1): Int#}, {#arg2: Int#}, {#arg3: Int#}, {#arg4: Int#}[')'][#TestStaticMemberCall#];
584584
// IMPLICIT_MEMBER_AFTERPAREN_2-DAG: Decl[Struct]/OtherModule[Swift]/IsSystem/TypeRelation[Convertible]: Int[#Int#];
585585
// IMPLICIT_MEMBER_AFTERPAREN_2-DAG: Literal[Integer]/None/TypeRelation[Convertible]: 0[#Int#];
586586

587587
let _: TestStaticMemberCall? = .create1(#^IMPLICIT_MEMBER_AFTERPAREN_3^#)
588588
// IMPLICIT_MEMBER_AFTERPAREN_3: Begin completions, 1 items
589-
// IMPLICIT_MEMBER_AFTERPAREN_3: Decl[StaticMethod]/CurrNominal/Flair[ArgLabels]/TypeRelation[Convertible]: ['(']{#arg1: Int#}[')'][#TestStaticMemberCall#]; name=arg1:
589+
// IMPLICIT_MEMBER_AFTERPAREN_3: Decl[StaticMethod]/CurrNominal/Flair[ArgLabels]: ['(']{#arg1: Int#}[')'][#TestStaticMemberCall#]; name=arg1:
590590

591591
let _: TestStaticMemberCall = .create2(1, #^IMPLICIT_MEMBER_SECOND^#)
592592
// IMPLICIT_MEMBER_SECOND: Begin completions, 3 items
@@ -600,7 +600,7 @@ func testImplicitMember() {
600600

601601
let _: TestStaticMemberCall = .createOverloaded(#^IMPLICIT_MEMBER_OVERLOADED^#)
602602
// IMPLICIT_MEMBER_OVERLOADED: Begin completions, 1 item
603-
// IMPLICIT_MEMBER_OVERLOADED: Decl[StaticMethod]/CurrNominal/Flair[ArgLabels]/TypeRelation[Convertible]: ['(']{#arg1: Int#}[')'][#TestStaticMemberCall#]; name=arg1:
603+
// IMPLICIT_MEMBER_OVERLOADED: Decl[StaticMethod]/CurrNominal/Flair[ArgLabels]: ['(']{#arg1: Int#}[')'][#TestStaticMemberCall#]; name=arg1:
604604
}
605605
func testImplicitMemberInArrayLiteral() {
606606
struct Receiver {
@@ -1325,8 +1325,8 @@ func testSubscriptWithExistingRhs(someString: String) {
13251325

13261326
// SUBSCRIPT_WITH_EXISTING_RHS: Begin completions
13271327
// SUBSCRIPT_WITH_EXISTING_RHS-DAG: Pattern/CurrNominal/Flair[ArgLabels]: ['[']{#keyPath: KeyPath<[String : Any], Value>#}[']'][#Value#];
1328-
// SUBSCRIPT_WITH_EXISTING_RHS-DAG: Decl[Subscript]/CurrNominal/Flair[ArgLabels]/IsSystem/TypeRelation[Convertible]: ['[']{#(key): String#}[']'][#@lvalue Any?#];
1329-
// SUBSCRIPT_WITH_EXISTING_RHS-DAG: Decl[Subscript]/CurrNominal/Flair[ArgLabels]/IsSystem/TypeRelation[Convertible]: ['[']{#(key): String#}, {#default: Any#}[']'][#@lvalue Any#];
1328+
// SUBSCRIPT_WITH_EXISTING_RHS-DAG: Decl[Subscript]/CurrNominal/Flair[ArgLabels]/IsSystem: ['[']{#(key): String#}[']'][#@lvalue Any?#];
1329+
// SUBSCRIPT_WITH_EXISTING_RHS-DAG: Decl[Subscript]/CurrNominal/Flair[ArgLabels]/IsSystem: ['[']{#(key): String#}, {#default: Any#}[']'][#@lvalue Any#];
13301330
// SUBSCRIPT_WITH_EXISTING_RHS-DAG: Decl[LocalVar]/Local/TypeRelation[Convertible]: someString[#String#];
13311331
// SUBSCRIPT_WITH_EXISTING_RHS: End completions
13321332
}
@@ -1348,8 +1348,8 @@ func testOptionalConversionInSrcOfAssignment(myArray: [Int]) {
13481348
var optInt: Int?
13491349
optInt = myArray[#^OPTIONAL_CONVERSION_IN_ASSIGNMENT^#]
13501350
// OPTIONAL_CONVERSION_IN_ASSIGNMENT: Begin completions
1351-
// OPTIONAL_CONVERSION_IN_ASSIGNMENT-DAG: Pattern/CurrNominal/Flair[ArgLabels]/TypeRelation[Convertible]: ['[']{#keyPath: KeyPath<[Int], Value>#}[']'][#Value#]; name=keyPath:
1352-
// OPTIONAL_CONVERSION_IN_ASSIGNMENT-DAG: Decl[Subscript]/CurrNominal/Flair[ArgLabels]/IsSystem/TypeRelation[Convertible]: ['[']{#(index): Int#}[']'][#Int#]; name=:
1351+
// OPTIONAL_CONVERSION_IN_ASSIGNMENT-DAG: Pattern/CurrNominal/Flair[ArgLabels]: ['[']{#keyPath: KeyPath<[Int], Value>#}[']'][#Value#]; name=keyPath:
1352+
// OPTIONAL_CONVERSION_IN_ASSIGNMENT-DAG: Decl[Subscript]/CurrNominal/Flair[ArgLabels]/IsSystem: ['[']{#(index): Int#}[']'][#Int#]; name=:
13531353
// OPTIONAL_CONVERSION_IN_ASSIGNMENT-DAG: Literal[Integer]/None/TypeRelation[Convertible]: 0[#Int#]; name=0
13541354
// OPTIONAL_CONVERSION_IN_ASSIGNMENT: End completions
13551355
}
@@ -1359,7 +1359,7 @@ func testAnyConversionInDestOfAssignment(_ message: String) {
13591359
userInfo[#^ANY_CONVERSION_IN_ASSIGNMENT^#] = message
13601360
// ANY_CONVERSION_IN_ASSIGNMENT: Begin completions
13611361
// ANY_CONVERSION_IN_ASSIGNMENT-DAG: Pattern/CurrNominal/Flair[ArgLabels]: ['[']{#keyPath: KeyPath<[String : Any], Value>#}[']'][#Value#]; name=keyPath:
1362-
// ANY_CONVERSION_IN_ASSIGNMENT-DAG: Decl[Subscript]/CurrNominal/Flair[ArgLabels]/IsSystem/TypeRelation[Convertible]: ['[']{#(key): String#}, {#default: Any#}[']'][#@lvalue Any#]; name=:default:
1362+
// ANY_CONVERSION_IN_ASSIGNMENT-DAG: Decl[Subscript]/CurrNominal/Flair[ArgLabels]/IsSystem: ['[']{#(key): String#}, {#default: Any#}[']'][#@lvalue Any#]; name=:default:
13631363
// ANY_CONVERSION_IN_ASSIGNMENT-DAG: Decl[LocalVar]/Local: userInfo[#[String : Any]#]; name=userInfo
13641364
// ANY_CONVERSION_IN_ASSIGNMENT-DAG: Decl[LocalVar]/Local/TypeRelation[Convertible]: message[#String#]; name=message
13651365
// ANY_CONVERSION_IN_ASSIGNMENT: End completions
@@ -1427,18 +1427,19 @@ struct NestedCallsWithoutClosingParen {
14271427
func testInDictionaryLiteral() {
14281428
let a = 1
14291429
let b = 2
1430-
_ = [a: foo(#^IN_DICTIONARY_LITERAL?check=NESTED_CALL_AT_START^#, b: 1]
1430+
_ = [a: foo(#^IN_DICTIONARY_LITERAL?check=NESTED_CALL_WITHOUT_TYPE_RELATION^#, b: 1]
1431+
// NESTED_CALL_WITHOUT_TYPE_RELATION-DAG: Decl[InstanceMethod]/CurrNominal/Flair[ArgLabels]: ['(']{#arg: Int#}, {#arg2: Int#}[')'][#Int#];
14311432
}
14321433

14331434
func testInArrayLiteral() {
1434-
_ = [foo(#^IN_ARRAY_LITERAL?check=NESTED_CALL_AT_START^#, 1]
1435+
_ = [foo(#^IN_ARRAY_LITERAL?check=NESTED_CALL_WITHOUT_TYPE_RELATION^#, 1]
14351436
}
14361437

14371438
func testInParen() {
1438-
_ = (foo(#^IN_PAREN?check=NESTED_CALL_AT_START^#)
1439+
_ = (foo(#^IN_PAREN?check=NESTED_CALL_WITHOUT_TYPE_RELATION^#)
14391440
}
14401441

14411442
func testInTuple() {
1442-
_ = (foo(#^IN_TUPLE?check=NESTED_CALL_AT_START^#, 1)
1443+
_ = (foo(#^IN_TUPLE?check=NESTED_CALL_WITHOUT_TYPE_RELATION^#, 1)
14431444
}
14441445
}

test/IDE/complete_dont_filter_overloads_with_cc_token.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ func test(text: String) {
1818
}
1919

2020
// COMPLETE: Begin completions
21-
// COMPLETE-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]/TypeRelation[Convertible]: ['(']{#verbatim: String#}[')'][#MyText#];
22-
// COMPLETE-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]/TypeRelation[Convertible]: ['(']{#(content): StringProtocol#}[')'][#MyText#];
21+
// COMPLETE-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['(']{#verbatim: String#}[')'][#MyText#];
22+
// COMPLETE-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['(']{#(content): StringProtocol#}[')'][#MyText#];
2323
// COMPLETE-DAG: Decl[LocalVar]/Local/TypeRelation[Convertible]: text[#String#];
2424
// COMPLETE: End completions

test/IDE/complete_enum_unresolved_dot_argument_labels.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ func testInit() {
1010
var state = DragState.inactive
1111
state = .dragging(#^SIGNATURE^#)
1212
// SIGNATURE: Begin completions, 1 item
13-
// SIGNATURE: Pattern/CurrNominal/Flair[ArgLabels]/TypeRelation[Convertible]: ['(']{#translationX: Int#}, {#translationY: Int#}[')'][#DragState#];
13+
// SIGNATURE: Pattern/CurrNominal/Flair[ArgLabels]: ['(']{#translationX: Int#}, {#translationY: Int#}[')'][#DragState#];
1414

1515
state = .dragging(translationX: 2, #^ARGUMENT^#)
1616
// ARGUMENT: Begin completions, 1 item
1717
// ARGUMENT: Pattern/Local/Flair[ArgLabels]: {#translationY: Int#}[#Int#];
1818

1919
state = .defaulted(#^DEFAULTED^#)
2020
// DEFAULTED: Begin completions, 1 items
21-
// DEFAULTED: Pattern/CurrNominal/Flair[ArgLabels]/TypeRelation[Convertible]: ['(']{#x: Int#}, {#y: Int#}, {#z: Int#}, {#extra: Int#}[')'][#DragState#];
21+
// DEFAULTED: Pattern/CurrNominal/Flair[ArgLabels]: ['(']{#x: Int#}, {#y: Int#}, {#z: Int#}, {#extra: Int#}[')'][#DragState#];
2222

2323
state = .defaulted(x: 1, #^DEFAULTEDARG^#)
2424
state = .defaulted(x: "Wrong type", #^ERRORTYPE?check=DEFAULTEDARG^#)

test/IDE/complete_in_result_builder.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ func testCompleteFunctionArgumentLabels() {
134134
@TupleBuilder<String> var x1 {
135135
StringFactory.makeString(#^FUNCTION_ARGUMENT_LABEL^#)
136136
// FUNCTION_ARGUMENT_LABEL: Begin completions, 1 item
137-
// FUNCTION_ARGUMENT_LABEL: Decl[StaticMethod]/CurrNominal/Flair[ArgLabels]/TypeRelation[Convertible]: ['(']{#x: String#}[')'][#String#];
137+
// FUNCTION_ARGUMENT_LABEL: Decl[StaticMethod]/CurrNominal/Flair[ArgLabels]: ['(']{#x: String#}[')'][#String#];
138138
}
139139
}
140140
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// RUN: %batch-code-completion
2+
3+
struct Mixer<each Source: Signal>: Signal {}
4+
5+
print(Mixer(#^COMPLETE^#))
6+
7+
// COMPLETE: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['('][')'][#Mixer<repeat each Source>#];

test/IDE/complete_subscript.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,5 +150,5 @@ func testSettableSub(x: inout HasSettableSub) {
150150
x[#^SETTABLE_SUBSCRIPT^#] = 32
151151
}
152152
// SETTABLE_SUBSCRIPT-DAG: Pattern/CurrNominal/Flair[ArgLabels]: ['[']{#keyPath: KeyPath<HasSettableSub, Value>#}[']'][#Value#];
153-
// SETTABLE_SUBSCRIPT-DAG: Decl[Subscript]/CurrNominal/Flair[ArgLabels]/TypeRelation[Convertible]: ['[']{#(a): String#}[']'][#@lvalue Int#];
153+
// SETTABLE_SUBSCRIPT-DAG: Decl[Subscript]/CurrNominal/Flair[ArgLabels]: ['[']{#(a): String#}[']'][#@lvalue Int#];
154154
// SETTABLE_SUBSCRIPT-DAG: Decl[LocalVar]/Local/TypeRelation[Convertible]: local[#String#]; name=local
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: %batch-code-completion
2+
3+
func foo(_ x: Int) {}
4+
5+
struct Bar {
6+
func bar(withString: String) -> String {}
7+
func bar(withInt: Int) -> Int {}
8+
}
9+
10+
func test() {
11+
foo(Bar().bar(#^COMPLETE^#))
12+
}
13+
// Ensure that we don't report the call pattern for `bar` as `Convertible`
14+
// COMPLETE-DAG: Decl[InstanceMethod]/CurrNominal/Flair[ArgLabels]: ['(']{#withString: String#}[')'][#String#]; name=withString:
15+
// COMPLETE-DAG: Decl[InstanceMethod]/CurrNominal/Flair[ArgLabels]/TypeRelation[Convertible]: ['(']{#withInt: Int#}[')'][#Int#]; name=withInt:

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,4 @@ struct ContentView: View {
2727
}
2828
}
2929

30-
// COMPLETE: Decl[InstanceMethod]/Super/Flair[ArgLabels]/TypeRelation[Convertible]: ['(']{#foo: Int#}[')'][#Never#]; name=foo:
30+
// COMPLETE: Decl[InstanceMethod]/Super/Flair[ArgLabels]: ['(']{#foo: Int#}[')'][#Never#]; name=foo:

0 commit comments

Comments
 (0)