Skip to content

Commit 7277f4f

Browse files
committed
[Diagnostics] Extend the AllowInOutConversion fix to cover inout attribute
mismatches in function types. This improves the diagnostic in cases where we have argument-to-parameter conversion failures or contextual type mismatches due to inout attribute mismatches.
1 parent 2062ee8 commit 7277f4f

File tree

5 files changed

+52
-10
lines changed

5 files changed

+52
-10
lines changed

lib/Sema/CSDiagnostics.cpp

+24
Original file line numberDiff line numberDiff line change
@@ -4264,6 +4264,30 @@ bool ThrowingFunctionConversionFailure::diagnoseAsError() {
42644264

42654265
bool InOutConversionFailure::diagnoseAsError() {
42664266
auto *anchor = getAnchor();
4267+
auto *locator = getLocator();
4268+
auto path = locator->getPath();
4269+
4270+
if (!path.empty() &&
4271+
path.back().getKind() == ConstraintLocator::FunctionArgument) {
4272+
if (auto argApplyInfo = getFunctionArgApplyInfo(locator)) {
4273+
emitDiagnostic(anchor->getLoc(), diag::cannot_convert_argument_value,
4274+
argApplyInfo->getArgType(), argApplyInfo->getParamType());
4275+
} else {
4276+
assert(locator->findLast<LocatorPathElt::ContextualType>());
4277+
auto contextualType = getConstraintSystem().getContextualType();
4278+
auto purpose = getContextualTypePurpose();
4279+
auto diagnostic = getDiagnosticFor(purpose, /*forProtocol=*/false);
4280+
4281+
if (!diagnostic)
4282+
return false;
4283+
4284+
emitDiagnostic(anchor->getLoc(), *diagnostic, getType(anchor),
4285+
contextualType);
4286+
}
4287+
4288+
return true;
4289+
}
4290+
42674291
emitDiagnostic(anchor->getLoc(), diag::cannot_pass_rvalue_inout_converted,
42684292
getFromType(), getToType());
42694293
fixItChangeArgumentType();

lib/Sema/CSFix.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -1289,7 +1289,7 @@ class IgnoreContextualType : public ContextualMismatch {
12891289
};
12901290

12911291
/// If this is an argument-to-parameter conversion which is associated with
1292-
/// `inout` parameter, subtyping is now permitted, types have to
1292+
/// `inout` parameter, subtyping is not permitted, types have to
12931293
/// be identical.
12941294
class AllowInOutConversion final : public ContextualMismatch {
12951295
AllowInOutConversion(ConstraintSystem &cs, Type argType, Type paramType,

lib/Sema/CSSimplify.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -2603,6 +2603,24 @@ bool ConstraintSystem::repairFailures(
26032603
*this, fnType, {FunctionType::Param(*arg)},
26042604
getConstraintLocator(anchor, path)));
26052605
}
2606+
2607+
if ((lhs->is<InOutType>() && !rhs->is<InOutType>()) ||
2608+
(!lhs->is<InOutType>() && rhs->is<InOutType>())) {
2609+
// We want to call matchTypes with the default decomposition options
2610+
// in case there are type variables that we couldn't bind due to the
2611+
// inout attribute mismatch.
2612+
auto result = matchTypes(lhs->getInOutObjectType(),
2613+
rhs->getInOutObjectType(), matchKind,
2614+
getDefaultDecompositionOptions(TMF_ApplyingFix),
2615+
locator);
2616+
2617+
if (result.isSuccess()) {
2618+
conversionsOrFixes.push_back(AllowInOutConversion::create(*this, lhs,
2619+
rhs, getConstraintLocator(locator)));
2620+
break;
2621+
}
2622+
}
2623+
26062624
break;
26072625
}
26082626

test/Constraints/closures.swift

+7-7
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,18 @@ func inoutToSharedConversions() {
3737
fooOW({ (x : Int) in return Int(5) }) // defaut-to-'__owned' allowed
3838
fooOW({ (x : __owned Int) in return Int(5) }) // '__owned'-to-'__owned' allowed
3939
fooOW({ (x : __shared Int) in return Int(5) }) // '__shared'-to-'__owned' allowed
40-
fooOW({ (x : inout Int) in return Int(5) }) // expected-error {{cannot convert value of type '(inout Int) -> Int' to expected argument type '(__owned _) -> _'}}
40+
fooOW({ (x : inout Int) in return Int(5) }) // expected-error {{cannot convert value of type '(inout Int) -> Int' to expected argument type '(__owned Int) -> Int'}}
4141

4242
func fooIO<T, U>(_ f : (inout T) -> U) {}
4343
fooIO({ (x : inout Int) in return Int(5) }) // 'inout'-to-'inout' allowed
44-
fooIO({ (x : Int) in return Int(5) }) // expected-error {{cannot convert value of type '(inout Int) -> Int' to expected argument type '(inout _) -> _'}}
45-
fooIO({ (x : __shared Int) in return Int(5) }) // expected-error {{cannot convert value of type '(__shared Int) -> Int' to expected argument type '(inout _) -> _'}}
46-
fooIO({ (x : __owned Int) in return Int(5) }) // expected-error {{cannot convert value of type '(__owned Int) -> Int' to expected argument type '(inout _) -> _'}}
44+
fooIO({ (x : Int) in return Int(5) }) // expected-error {{cannot convert value of type '(Int) -> Int' to expected argument type '(inout Int) -> Int'}}
45+
fooIO({ (x : __shared Int) in return Int(5) }) // expected-error {{cannot convert value of type '(__shared Int) -> Int' to expected argument type '(inout Int) -> Int'}}
46+
fooIO({ (x : __owned Int) in return Int(5) }) // expected-error {{cannot convert value of type '(__owned Int) -> Int' to expected argument type '(inout Int) -> Int'}}
4747

4848
func fooSH<T, U>(_ f : (__shared T) -> U) {}
4949
fooSH({ (x : __shared Int) in return Int(5) }) // '__shared'-to-'__shared' allowed
5050
fooSH({ (x : __owned Int) in return Int(5) }) // '__owned'-to-'__shared' allowed
51-
fooSH({ (x : inout Int) in return Int(5) }) // expected-error {{cannot convert value of type '(inout Int) -> Int' to expected argument type '(__shared _) -> _'}}
51+
fooSH({ (x : inout Int) in return Int(5) }) // expected-error {{cannot convert value of type '(inout Int) -> Int' to expected argument type '(__shared Int) -> Int'}}
5252
fooSH({ (x : Int) in return Int(5) }) // default-to-'__shared' allowed
5353
}
5454

@@ -862,8 +862,8 @@ func rdar45771997() {
862862
struct rdar30347997 {
863863
func withUnsafeMutableBufferPointer(body : (inout Int) -> ()) {}
864864
func foo() {
865-
withUnsafeMutableBufferPointer {
866-
(b : Int) in // expected-error {{'Int' is not convertible to 'inout Int'}}
865+
withUnsafeMutableBufferPointer { // expected-error {{cannot convert value of type '(Int) -> ()' to expected argument type '(inout Int) -> ()'}}
866+
(b : Int) in
867867
}
868868
}
869869
}

test/Generics/materializable_restrictions.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ func test20807269() {
1515
func test15921530() {
1616
struct X {}
1717

18-
func makef<T>() -> (T) -> () { // expected-note {{in call to function 'makef()'}}
18+
func makef<T>() -> (T) -> () {
1919
return {
2020
x in ()
2121
}
2222
}
23-
var _: (inout X) -> () = makef() // expected-error{{generic parameter 'T' could not be inferred}}
23+
var _: (inout X) -> () = makef() // expected-error{{cannot convert value of type '(X) -> ()' to specified type '(inout X) -> ()'}}
2424
}

0 commit comments

Comments
 (0)