Skip to content

Commit f55ce19

Browse files
committed
[Diagnostics] Strip off unrelated optionals from generic parameter diagnostics
In situations where left-hand side requires value-to-optional promotion which ends up in type mismatch let's not mention optionals in the diagnostic because they are unrelated e.g. ```swift func test(_: UnsafePointer<Int>??) {} var value: Float = 0 test(&value) ``` In this example `value` gets implicitly wrapped into a double optional before `UnsafePointer<Float>` could be matched against `UnsafePointer<Int>` associated with the parameter. Diagnostic is about generic argument mismatch `Float` vs. `Int` and shouldn't mention any optionals.
1 parent ca3aa67 commit f55ce19

File tree

3 files changed

+26
-17
lines changed

3 files changed

+26
-17
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -630,11 +630,32 @@ void GenericArgumentsMismatchFailure::emitNoteForMismatch(int position) {
630630

631631
bool GenericArgumentsMismatchFailure::diagnoseAsError() {
632632
auto anchor = getAnchor();
633-
auto path = getLocator()->getPath();
634633

635634
auto fromType = getFromType();
636635
auto toType = getToType();
637636

637+
// This is a situation where right-hand size type is wrapped
638+
// into a number of optionals and argument isn't e.g.
639+
//
640+
// func test(_: UnsafePointer<Int>??) {}
641+
//
642+
// var value: Float = 0
643+
// test(&value)
644+
//
645+
// `value` has to get implicitly wrapped into 2 optionals
646+
// before pointer types could be compared.
647+
auto path = getLocator()->getPath();
648+
unsigned toDrop = 0;
649+
for (const auto &elt : llvm::reverse(path)) {
650+
if (!elt.is<LocatorPathElt::OptionalPayload>())
651+
break;
652+
653+
// Disregard optional payload element to look at its source.
654+
toDrop++;
655+
}
656+
657+
path = path.drop_back(toDrop);
658+
638659
Optional<Diag<Type, Type>> diagnostic;
639660
if (path.empty()) {
640661
if (isExpr<AssignExpr>(anchor)) {
@@ -684,18 +705,6 @@ bool GenericArgumentsMismatchFailure::diagnoseAsError() {
684705
break;
685706
}
686707

687-
case ConstraintLocator::OptionalPayload: {
688-
// If we have an inout expression, this comes from an
689-
// InoutToPointer argument mismatch failure.
690-
if (isExpr<InOutExpr>(anchor)) {
691-
diagnostic = diag::cannot_convert_argument_value;
692-
auto applyInfo = getFunctionArgApplyInfo(getLocator());
693-
if (applyInfo)
694-
toType = applyInfo->getParamType();
695-
}
696-
break;
697-
}
698-
699708
case ConstraintLocator::TupleElement: {
700709
auto rawAnchor = getRawAnchor();
701710

test/Constraints/diagnostics.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1433,7 +1433,7 @@ func assignGenericMismatch() {
14331433
var a: [Int]?
14341434
var b: [String]
14351435

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

14391439
b = a // expected-error {{cannot assign value of type '[Int]' to type '[String]'}}
@@ -1447,7 +1447,7 @@ func assignGenericMismatch() {
14471447
let value: [Int] = []
14481448
func gericArgToParamOptional(_ param: [String]?) {}
14491449

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

14531453
// Inout Expr conversions

test/Constraints/valid_pointer_conversions.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@ func givesPtr(_ str: String) {
3131
takesDoubleOptionalPtr(i) // expected-error {{cannot convert value of type 'Int' to expected argument type 'UnsafeRawPointer??'}}
3232
takesMutableDoubleOptionalPtr(arr) // expected-error {{cannot convert value of type '[Int]' to expected argument type 'UnsafeMutableRawPointer??'}}
3333

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

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

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

0 commit comments

Comments
 (0)