Skip to content

[SR-12242] Apply to Arg involving ConstraintLocator::GenericArgument diagnostics improvement #30814

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
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
29 changes: 22 additions & 7 deletions lib/Sema/CSDiagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -667,20 +667,17 @@ bool GenericArgumentsMismatchFailure::diagnoseAsError() {
}

case ConstraintLocator::GenericArgument: {
// In cases like `[[Int]]` vs. `[[String]]`
if (auto *assignExpr = dyn_cast<AssignExpr>(anchor)) {
diagnostic = getDiagnosticFor(CTP_AssignSource);
fromType = getType(assignExpr->getSrc());
toType = getType(assignExpr->getDest());
}
break;
}

case ConstraintLocator::OptionalPayload: {
// If we have an inout expression, this comes from an
// InoutToPointer argument mismatch failure.
if (isa<InOutExpr>(anchor)) {
diagnostic = diag::cannot_convert_argument_value;
auto applyInfo = getFunctionArgApplyInfo(getLocator());
if (applyInfo)
toType = applyInfo->getParamType();
}
break;
}
Expand All @@ -703,6 +700,24 @@ bool GenericArgumentsMismatchFailure::diagnoseAsError() {
}
}

if (!diagnostic) {
// Handle all mismatches involving an `AssignExpr`
if (auto *assignExpr = dyn_cast<AssignExpr>(anchor)) {
diagnostic = getDiagnosticFor(CTP_AssignSource);
fromType = getType(assignExpr->getSrc());
toType = getType(assignExpr->getDest());
} else {
// If we couldn't find a specific diagnostic let's fallback to
// attempt to handle cases where we have an apply arg to param.
auto applyInfo = getFunctionArgApplyInfo(getLocator());
if (applyInfo) {
diagnostic = diag::cannot_convert_argument_value;
fromType = applyInfo->getArgType();
toType = applyInfo->getParamType();
}
}
}

if (!diagnostic)
return false;

Expand Down
55 changes: 55 additions & 0 deletions test/Constraints/diagnostics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1415,3 +1415,58 @@ f11(3, f4) // expected-error {{global function 'f11' requires that 'Int' conform
let f12: (Int) -> Void = { _ in }
func f12<T : P2>(_ n: T, _ f: @escaping (T) -> T) {}
f12(3, f4)// expected-error {{extra argument in call}}

// SR-12242
struct SR_12242_R<Value> {}
struct SR_12242_T {}

protocol SR_12242_P {}

func fSR_12242() -> SR_12242_R<[SR_12242_T]> {}

func genericFunc<SR_12242_T: SR_12242_P>(_ completion: @escaping (SR_12242_R<[SR_12242_T]>) -> Void) {
let t = fSR_12242()
completion(t) // expected-error {{cannot convert value of type 'diagnostics.SR_12242_R<[diagnostics.SR_12242_T]>' to expected argument type 'diagnostics.SR_12242_R<[SR_12242_T]>'}}
// expected-note@-1 {{arguments to generic parameter 'Element' ('diagnostics.SR_12242_T' and 'SR_12242_T') are expected to be equal}}
}

func assignGenericMismatch() {
var a: [Int]?
var b: [String]

a = b // expected-error {{cannot assign value of type '[String]' to type '[Int]?'}}
// expected-note@-1 {{arguments to generic parameter 'Element' ('String' and 'Int') are expected to be equal}}

b = a // expected-error {{cannot assign value of type '[Int]' to type '[String]'}}
// expected-note@-1 {{arguments to generic parameter 'Element' ('Int' and 'String') are expected to be equal}}
// expected-error@-2 {{value of optional type '[Int]?' must be unwrapped to a value of type '[Int]'}}
// expected-note@-3 {{coalesce using '??' to provide a default when the optional value contains 'nil'}}
// expected-note@-4 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}}
}

// [Int] to [String]? argument to param conversion
let value: [Int] = []
func gericArgToParamOptional(_ param: [String]?) {}

gericArgToParamOptional(value) // expected-error {{convert value of type '[Int]' to expected argument type '[String]?'}}
// expected-note@-1 {{arguments to generic parameter 'Element' ('Int' and 'String') are expected to be equal}}

// Inout Expr conversions
func gericArgToParamInout1(_ x: inout [[Int]]) {}
func gericArgToParamInout2(_ x: inout [[String]]) {
gericArgToParamInout1(&x) // expected-error {{cannot convert value of type '[[String]]' to expected argument type '[[Int]]'}}
// expected-note@-1 {{arguments to generic parameter 'Element' ('String' and 'Int') are expected to be equal}}
}

func gericArgToParamInoutOptional(_ x: inout [[String]]?) {
gericArgToParamInout1(&x) // expected-error {{cannot convert value of type '[[String]]?' to expected argument type '[[Int]]'}}
// expected-note@-1 {{arguments to generic parameter 'Element' ('String' and 'Int') are expected to be equal}}
// expected-error@-2 {{value of optional type '[[String]]?' must be unwrapped to a value of type '[[String]]'}}
// expected-note@-3 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}}
}

func gericArgToParamInout(_ x: inout [[Int]]) { // expected-note {{change variable type to '[[String]]?' if it doesn't need to be declared as '[[Int]]'}}
gericArgToParamInoutOptional(&x) // expected-error {{cannot convert value of type '[[Int]]' to expected argument type '[[String]]?'}}
// expected-note@-1 {{arguments to generic parameter 'Element' ('Int' and 'String') are expected to be equal}}
// expected-error@-2 {{inout argument could be set to a value with a type other than '[[Int]]'; use a value declared as type '[[String]]?' instead}}
}
4 changes: 2 additions & 2 deletions test/Constraints/valid_pointer_conversions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ func givesPtr(_ str: String) {
takesDoubleOptionalPtr(i) // expected-error {{cannot convert value of type 'Int' to expected argument type 'UnsafeRawPointer??'}}
takesMutableDoubleOptionalPtr(arr) // expected-error {{cannot convert value of type '[Int]' to expected argument type 'UnsafeMutableRawPointer??'}}

takesMutableDoubleOptionalTypedPtr(&i) // expected-error {{cannot convert value of type 'UnsafeMutablePointer<Int>' to expected argument type 'UnsafeMutablePointer<Double>'}}
takesMutableDoubleOptionalTypedPtr(&i) // expected-error {{cannot convert value of type 'UnsafeMutablePointer<Int>' to expected argument type 'UnsafeMutablePointer<Double>??'}}
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('Int' and 'Double') are expected to be equal}}
}

// SR12382
func SR12382(_ x: UnsafeMutablePointer<Double>??) {}

var i = 0
SR12382(&i) // expected-error {{cannot convert value of type 'UnsafeMutablePointer<Int>' to expected argument type 'UnsafeMutablePointer<Double>'}}
SR12382(&i) // expected-error {{cannot convert value of type 'UnsafeMutablePointer<Int>' to expected argument type 'UnsafeMutablePointer<Double>??'}}
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('Int' and 'Double') are expected to be equal}}