Skip to content

[Diagnostics] Extend the AllowInOutConversion fix to cover inout attribute mismatches in function types. #27043

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions lib/Sema/CSDiagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4264,6 +4264,30 @@ bool ThrowingFunctionConversionFailure::diagnoseAsError() {

bool InOutConversionFailure::diagnoseAsError() {
auto *anchor = getAnchor();
auto *locator = getLocator();
auto path = locator->getPath();

if (!path.empty() &&
path.back().getKind() == ConstraintLocator::FunctionArgument) {
if (auto argApplyInfo = getFunctionArgApplyInfo(locator)) {
emitDiagnostic(anchor->getLoc(), diag::cannot_convert_argument_value,
argApplyInfo->getArgType(), argApplyInfo->getParamType());
} else {
assert(locator->findLast<LocatorPathElt::ContextualType>());
auto contextualType = getConstraintSystem().getContextualType();
auto purpose = getContextualTypePurpose();
auto diagnostic = getDiagnosticFor(purpose, /*forProtocol=*/false);

if (!diagnostic)
return false;

emitDiagnostic(anchor->getLoc(), *diagnostic, getType(anchor),
contextualType);
}

return true;
}

emitDiagnostic(anchor->getLoc(), diag::cannot_pass_rvalue_inout_converted,
getFromType(), getToType());
fixItChangeArgumentType();
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/CSFix.h
Original file line number Diff line number Diff line change
Expand Up @@ -1289,7 +1289,7 @@ class IgnoreContextualType : public ContextualMismatch {
};

/// If this is an argument-to-parameter conversion which is associated with
/// `inout` parameter, subtyping is now permitted, types have to
/// `inout` parameter, subtyping is not permitted, types have to
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! :)

/// be identical.
class AllowInOutConversion final : public ContextualMismatch {
AllowInOutConversion(ConstraintSystem &cs, Type argType, Type paramType,
Expand Down
18 changes: 18 additions & 0 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2603,6 +2603,24 @@ bool ConstraintSystem::repairFailures(
*this, fnType, {FunctionType::Param(*arg)},
getConstraintLocator(anchor, path)));
}

if ((lhs->is<InOutType>() && !rhs->is<InOutType>()) ||
(!lhs->is<InOutType>() && rhs->is<InOutType>())) {
// We want to call matchTypes with the default decomposition options
// in case there are type variables that we couldn't bind due to the
// inout attribute mismatch.
auto result = matchTypes(lhs->getInOutObjectType(),
rhs->getInOutObjectType(), matchKind,
getDefaultDecompositionOptions(TMF_ApplyingFix),
locator);

if (result.isSuccess()) {
conversionsOrFixes.push_back(AllowInOutConversion::create(*this, lhs,
rhs, getConstraintLocator(locator)));
break;
}
}

break;
}

Expand Down
14 changes: 7 additions & 7 deletions test/Constraints/closures.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,18 @@ func inoutToSharedConversions() {
fooOW({ (x : Int) in return Int(5) }) // defaut-to-'__owned' allowed
fooOW({ (x : __owned Int) in return Int(5) }) // '__owned'-to-'__owned' allowed
fooOW({ (x : __shared Int) in return Int(5) }) // '__shared'-to-'__owned' allowed
fooOW({ (x : inout Int) in return Int(5) }) // expected-error {{cannot convert value of type '(inout Int) -> Int' to expected argument type '(__owned _) -> _'}}
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'}}

func fooIO<T, U>(_ f : (inout T) -> U) {}
fooIO({ (x : inout Int) in return Int(5) }) // 'inout'-to-'inout' allowed
fooIO({ (x : Int) in return Int(5) }) // expected-error {{cannot convert value of type '(inout Int) -> Int' to expected argument type '(inout _) -> _'}}
fooIO({ (x : __shared Int) in return Int(5) }) // expected-error {{cannot convert value of type '(__shared Int) -> Int' to expected argument type '(inout _) -> _'}}
fooIO({ (x : __owned Int) in return Int(5) }) // expected-error {{cannot convert value of type '(__owned Int) -> Int' to expected argument type '(inout _) -> _'}}
fooIO({ (x : Int) in return Int(5) }) // expected-error {{cannot convert value of type '(Int) -> Int' to expected argument type '(inout Int) -> Int'}}
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'}}
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'}}

func fooSH<T, U>(_ f : (__shared T) -> U) {}
fooSH({ (x : __shared Int) in return Int(5) }) // '__shared'-to-'__shared' allowed
fooSH({ (x : __owned Int) in return Int(5) }) // '__owned'-to-'__shared' allowed
fooSH({ (x : inout Int) in return Int(5) }) // expected-error {{cannot convert value of type '(inout Int) -> Int' to expected argument type '(__shared _) -> _'}}
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'}}
fooSH({ (x : Int) in return Int(5) }) // default-to-'__shared' allowed
}

Expand Down Expand Up @@ -862,8 +862,8 @@ func rdar45771997() {
struct rdar30347997 {
func withUnsafeMutableBufferPointer(body : (inout Int) -> ()) {}
func foo() {
withUnsafeMutableBufferPointer {
(b : Int) in // expected-error {{'Int' is not convertible to 'inout Int'}}
withUnsafeMutableBufferPointer { // expected-error {{cannot convert value of type '(Int) -> ()' to expected argument type '(inout Int) -> ()'}}
(b : Int) in
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions test/Generics/materializable_restrictions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ func test20807269() {
func test15921530() {
struct X {}

func makef<T>() -> (T) -> () { // expected-note {{in call to function 'makef()'}}
func makef<T>() -> (T) -> () {
return {
x in ()
}
}
var _: (inout X) -> () = makef() // expected-error{{generic parameter 'T' could not be inferred}}
var _: (inout X) -> () = makef() // expected-error{{cannot convert value of type '(X) -> ()' to specified type '(inout X) -> ()'}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Much better!

}