Skip to content

Commit 4ca67f6

Browse files
committed
[ConstraintSystem] Teach getFunctionArgApplyInfo about inout expressions
Currently `getFunctionArgApplyInfo` expects a locator with `ApplyArgToParam` element to identify location of the argument. `InOutExpr` could only be used in argument positions but it doesn't have the same locator format as non-inout arguments, so `getFunctionArgApplyInfo` needs to do some digging in the AST to retrieve that information. Resolves: rdar://75146811
1 parent d608cb5 commit 4ca67f6

File tree

3 files changed

+84
-1
lines changed

3 files changed

+84
-1
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3449,6 +3449,13 @@ static bool repairOutOfOrderArgumentsInBinaryFunction(
34493449

34503450
bool isOperatorRef = overload->choice.getDecl()->isOperator();
34513451

3452+
// If one of the parameters is `inout`, we can't flip the arguments.
3453+
{
3454+
auto params = fnType->getParams();
3455+
if (params[0].isInOut() != params[1].isInOut())
3456+
return false;
3457+
}
3458+
34523459
auto matchArgToParam = [&](Type argType, Type paramType, ASTNode anchor) {
34533460
auto *loc = cs.getConstraintLocator(anchor);
34543461
// If argument (and/or parameter) is a generic type let's not even try this

lib/Sema/ConstraintSystem.cpp

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4542,6 +4542,59 @@ Type Solution::resolveInterfaceType(Type type) const {
45424542

45434543
Optional<FunctionArgApplyInfo>
45444544
Solution::getFunctionArgApplyInfo(ConstraintLocator *locator) const {
4545+
auto &cs = getConstraintSystem();
4546+
4547+
// It's only valid to use `&` in argument positions, but we need
4548+
// to figure out exactly where it was used.
4549+
if (auto *argExpr = getAsExpr<InOutExpr>(locator->getAnchor())) {
4550+
auto *argList = cs.getParentExpr(argExpr);
4551+
assert(argList);
4552+
4553+
// `inout` expression might be wrapped in a number of
4554+
// parens e.g. `test(((&x)))`.
4555+
if (isa<ParenExpr>(argList)) {
4556+
for (;;) {
4557+
auto nextParent = cs.getParentExpr(argList);
4558+
assert(nextParent && "Incorrect use of `inout` expression");
4559+
4560+
// e.g. `test((&x), x: ...)`
4561+
if (isa<TupleExpr>(nextParent)) {
4562+
argList = nextParent;
4563+
break;
4564+
}
4565+
4566+
// e.g. `test(((&x)))`
4567+
if (isa<ParenExpr>(nextParent)) {
4568+
argList = nextParent;
4569+
continue;
4570+
}
4571+
4572+
break;
4573+
}
4574+
}
4575+
4576+
unsigned argIdx = 0;
4577+
if (auto *tuple = dyn_cast<TupleExpr>(argList)) {
4578+
auto arguments = tuple->getElements();
4579+
4580+
for (auto idx : indices(arguments)) {
4581+
if (arguments[idx]->getSemanticsProvidingExpr() == argExpr) {
4582+
argIdx = idx;
4583+
break;
4584+
}
4585+
}
4586+
}
4587+
4588+
auto *call = cs.getParentExpr(argList);
4589+
assert(call);
4590+
4591+
ParameterTypeFlags flags;
4592+
locator = cs.getConstraintLocator(
4593+
call, {ConstraintLocator::ApplyArgument,
4594+
LocatorPathElt::ApplyArgToParam(argIdx, argIdx,
4595+
flags.withInOut(true))});
4596+
}
4597+
45454598
auto anchor = locator->getAnchor();
45464599
auto path = locator->getPath();
45474600

@@ -4635,7 +4688,6 @@ Solution::getFunctionArgApplyInfo(ConstraintLocator *locator) const {
46354688
auto argIdx = applyArgElt->getArgIdx();
46364689
auto paramIdx = applyArgElt->getParamIdx();
46374690

4638-
auto &cs = getConstraintSystem();
46394691
return FunctionArgApplyInfo(cs.getParentExpr(argExpr), argExpr, argIdx,
46404692
simplifyType(getType(argExpr)), paramIdx,
46414693
fnInterfaceType, fnType, callee);

test/Constraints/optional.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,3 +459,27 @@ func sr_12309() {
459459
return (((nil))) // Ok
460460
}
461461
}
462+
463+
// rdar://75146811 - crash due to incrrect inout type
464+
func rdar75146811() {
465+
func test(_: UnsafeMutablePointer<Double>) {}
466+
func test_tuple(_: UnsafeMutablePointer<Double>, x: Int) {}
467+
func test_named(x: UnsafeMutablePointer<Double>) {}
468+
469+
var arr: [Double]! = []
470+
471+
test(&arr) // expected-error {{cannot convert value of type '[Double]?' to expected argument type 'Double'}}
472+
test((&arr)) // expected-error {{use of extraneous '&'}}
473+
// expected-error@-1 {{cannot convert value of type '[Double]?' to expected argument type 'Double'}}
474+
test(&(arr)) // expected-error {{cannot convert value of type '[Double]?' to expected argument type 'Double'}}
475+
476+
test_tuple(&arr, x: 0) // expected-error {{cannot convert value of type '[Double]?' to expected argument type 'Double'}}
477+
test_tuple((&arr), x: 0) // expected-error {{use of extraneous '&'}}
478+
// expected-error@-1 {{cannot convert value of type '[Double]?' to expected argument type 'Double'}}
479+
test_tuple(&(arr), x: 0) // expected-error {{cannot convert value of type '[Double]?' to expected argument type 'Double'}}
480+
481+
test_named(x: &arr) // expected-error {{cannot convert value of type '[Double]?' to expected argument type 'Double'}}
482+
test_named(x: (&arr)) // expected-error {{use of extraneous '&'}}
483+
// expected-error@-1 {{cannot convert value of type '[Double]?' to expected argument type 'Double'}}
484+
test_named(x: &(arr)) // expected-error {{cannot convert value of type '[Double]?' to expected argument type 'Double'}}
485+
}

0 commit comments

Comments
 (0)