Skip to content

Commit 2a9903d

Browse files
committed
[Diagnostics] Check whether missing conformance could be fixed by using .rawValue
A lot of operators (and most likely regular functions a well) have overloads that accept i.e. a generic parameter that conforms to `StringProtocol`, so the best fix in situations when argument is a raw representable type would be to check whether `.rawValue` conforms to the expected protocol and use it if so. Resolves rdar://problem/75367157
1 parent d608cb5 commit 2a9903d

File tree

5 files changed

+53
-4
lines changed

5 files changed

+53
-4
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6841,6 +6841,8 @@ AbstractRawRepresentableFailure::getDiagnostic() const {
68416841
return diag::cannot_convert_assign;
68426842
} else if (locator->isLastElement<LocatorPathElt::ApplyArgToParam>()) {
68436843
return diag::cannot_convert_argument_value;
6844+
} else if (locator->isLastElement<LocatorPathElt::AnyRequirement>()) {
6845+
return diag::cannot_convert_initializer_value_protocol;
68446846
}
68456847

68466848
return None;

lib/Sema/CSSimplify.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6013,6 +6013,14 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
60136013
}
60146014
}
60156015

6016+
if (auto rawValue = isRawRepresentable(*this, type)) {
6017+
if (!rawValue->isTypeVariableOrMember() &&
6018+
TypeChecker::conformsToProtocol(rawValue, protocol, DC)) {
6019+
auto *fix = UseRawValue::create(*this, type, protocolTy, loc);
6020+
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
6021+
}
6022+
}
6023+
60166024
auto anchor = locator.getAnchor();
60176025

60186026
if (isExpr<UnresolvedMemberExpr>(anchor) &&
@@ -10751,7 +10759,6 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1075110759
case FixKind::AddPropertyWrapperAttribute:
1075210760
case FixKind::ExpandArrayIntoVarargs:
1075310761
case FixKind::UseRawValue:
10754-
case FixKind::ExplicitlyConstructRawRepresentable:
1075510762
case FixKind::SpecifyBaseTypeForContextualMember:
1075610763
case FixKind::CoerceToCheckedCast:
1075710764
case FixKind::SpecifyObjectLiteralTypeImport:
@@ -10772,6 +10779,17 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1077210779
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
1077310780
}
1077410781

10782+
case FixKind::ExplicitlyConstructRawRepresentable: {
10783+
// Let's increase impact of this fix for binary operators because
10784+
// it's possible to get both `.rawValue` and construction fixes for
10785+
// different overloads of a binary operator and `.rawValue` is a
10786+
// better fix because raw representable has a failable constructor.
10787+
return recordFix(fix,
10788+
/*impact=*/isExpr<BinaryExpr>(locator.getAnchor()) ? 2 : 1)
10789+
? SolutionKind::Error
10790+
: SolutionKind::Solved;
10791+
}
10792+
1077510793
case FixKind::TreatRValueAsLValue: {
1077610794
unsigned impact = 1;
1077710795
// If this is an attempt to use result of a function/subscript call as

test/ClangImporter/newtype_conformance.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,11 @@ func acceptHashable<T: Hashable>(_: T) {}
1616
// expected-note@-1 {{where 'T' = 'WrappedRef'}}
1717
// expected-note@-2 {{where 'T' = 'WrappedValue'}}
1818
func acceptComparable<T: Comparable>(_: T) {}
19-
// expected-note@-1 {{where 'T' = 'NSNotification.Name'}}
2019

2120
func testNewTypeWrapper(x: NSNotification.Name, y: NSNotification.Name) {
2221
acceptEquatable(x)
2322
acceptHashable(x)
24-
acceptComparable(x) // expected-error {{global function 'acceptComparable' requires that 'NSNotification.Name' conform to 'Comparable'}}
23+
acceptComparable(x) // expected-error {{value of type 'NSNotification.Name' does not conform to specified type 'Comparable'}} {{19-19=.rawValue}}
2524

2625
_ = x == y
2726
_ = x != y

test/Constraints/fixes.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,5 +359,5 @@ func testKeyPathSubscriptArgFixes(_ fn: @escaping () -> Int) {
359359

360360
func sr12426(a: Any, _ str: String?) {
361361
a == str // expected-error {{binary operator '==' cannot be applied to operands of type 'Any' and 'String?'}}
362-
// expected-note@-1 {{overloads for '==' exist with these partially matching parameter lists: (CodingUserInfoKey, CodingUserInfoKey), (String, String)}}
362+
// expected-note@-1 {{overloads for '==' exist with these partially matching parameter lists: (String, String)}}
363363
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %target-typecheck-verify-swift -target x86_64-apple-macosx10.15 -swift-version 5
2+
// REQUIRES: objc_interop
3+
// REQUIRES: OS=macosx
4+
5+
import SwiftUI
6+
7+
enum E : String {
8+
case a
9+
case b
10+
11+
var description: String { get { "" } }
12+
}
13+
14+
struct S : View {
15+
var test: E = .a
16+
17+
func check(_: String) -> Bool {}
18+
19+
var body: some View {
20+
List {
21+
if test != E.b.description { // expected-error {{cannot convert value of type 'E' to expected argument type 'String'}} {{14-14=.rawValue}}
22+
EmptyView()
23+
}
24+
25+
if (check(self.test)) { // expected-error {{cannot convert value of type 'E' to expected argument type 'String'}} {{26-26=.rawValue}}
26+
Spacer()
27+
}
28+
}
29+
}
30+
}

0 commit comments

Comments
 (0)