Skip to content

Commit 1dd914a

Browse files
authored
Merge pull request #36445 from xedin/rdar-75367157
[Diagnostics] Check whether missing conformance could be fixed by using `.rawValue`
2 parents 15b83e1 + 45c73b3 commit 1dd914a

File tree

7 files changed

+84
-5
lines changed

7 files changed

+84
-5
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6951,6 +6951,26 @@ void MissingRawRepresentableInitFailure::fixIt(
69516951
}
69526952
}
69536953

6954+
bool MissingRawValueFailure::diagnoseAsError() {
6955+
auto *locator = getLocator();
6956+
6957+
if (locator->isLastElement<LocatorPathElt::AnyRequirement>()) {
6958+
MissingConformanceFailure failure(getSolution(), locator,
6959+
{RawReprType, ExpectedType});
6960+
6961+
auto diagnosed = failure.diagnoseAsError();
6962+
if (!diagnosed)
6963+
return false;
6964+
6965+
auto note = emitDiagnostic(diag::note_remapped_type, ".rawValue");
6966+
fixIt(note);
6967+
6968+
return true;
6969+
}
6970+
6971+
return AbstractRawRepresentableFailure::diagnoseAsError();
6972+
}
6973+
69546974
void MissingRawValueFailure::fixIt(InFlightDiagnostic &diagnostic) const {
69556975
auto *E = getAsExpr(getAnchor());
69566976
if (!E)

lib/Sema/CSDiagnostics.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2284,6 +2284,8 @@ class MissingRawValueFailure final : public AbstractRawRepresentableFailure {
22842284
Type getFromType() const override { return RawReprType; }
22852285
Type getToType() const override { return ExpectedType; }
22862286

2287+
bool diagnoseAsError() override;
2288+
22872289
private:
22882290
void fixIt(InFlightDiagnostic &diagnostic) const override;
22892291
};

lib/Sema/CSSimplify.cpp

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3261,7 +3261,14 @@ repairViaOptionalUnwrap(ConstraintSystem &cs, Type fromType, Type toType,
32613261
// behind itself which we can use to better understand
32623262
// how many levels of optionality have to be unwrapped.
32633263
if (auto *OEE = dyn_cast<OptionalEvaluationExpr>(anchor)) {
3264-
auto type = cs.getType(OEE->getSubExpr());
3264+
auto *subExpr = OEE->getSubExpr();
3265+
3266+
// First, let's check whether it has been determined that
3267+
// it was incorrect to use `?` in this position.
3268+
if (cs.hasFixFor(cs.getConstraintLocator(subExpr), FixKind::RemoveUnwrap))
3269+
return true;
3270+
3271+
auto type = cs.getType(subExpr);
32653272
// If the type of sub-expression is optional, type of the
32663273
// `OptionalEvaluationExpr` could be safely ignored because
32673274
// it doesn't add any type information.
@@ -6031,6 +6038,14 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
60316038
}
60326039
}
60336040

6041+
if (auto rawValue = isRawRepresentable(*this, type)) {
6042+
if (!rawValue->isTypeVariableOrMember() &&
6043+
TypeChecker::conformsToProtocol(rawValue, protocol, DC)) {
6044+
auto *fix = UseRawValue::create(*this, type, protocolTy, loc);
6045+
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
6046+
}
6047+
}
6048+
60346049
auto anchor = locator.getAnchor();
60356050

60366051
if (isExpr<UnresolvedMemberExpr>(anchor) &&
@@ -10769,7 +10784,6 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1076910784
case FixKind::AddPropertyWrapperAttribute:
1077010785
case FixKind::ExpandArrayIntoVarargs:
1077110786
case FixKind::UseRawValue:
10772-
case FixKind::ExplicitlyConstructRawRepresentable:
1077310787
case FixKind::SpecifyBaseTypeForContextualMember:
1077410788
case FixKind::CoerceToCheckedCast:
1077510789
case FixKind::SpecifyObjectLiteralTypeImport:
@@ -10790,6 +10804,17 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1079010804
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
1079110805
}
1079210806

10807+
case FixKind::ExplicitlyConstructRawRepresentable: {
10808+
// Let's increase impact of this fix for binary operators because
10809+
// it's possible to get both `.rawValue` and construction fixes for
10810+
// different overloads of a binary operator and `.rawValue` is a
10811+
// better fix because raw representable has a failable constructor.
10812+
return recordFix(fix,
10813+
/*impact=*/isExpr<BinaryExpr>(locator.getAnchor()) ? 2 : 1)
10814+
? SolutionKind::Error
10815+
: SolutionKind::Solved;
10816+
}
10817+
1079310818
case FixKind::TreatRValueAsLValue: {
1079410819
unsigned impact = 1;
1079510820
// If this is an attempt to use result of a function/subscript call as

test/ClangImporter/newtype_conformance.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ func testNewTypeWrapper(x: NSNotification.Name, y: NSNotification.Name) {
2222
acceptEquatable(x)
2323
acceptHashable(x)
2424
acceptComparable(x) // expected-error {{global function 'acceptComparable' requires that 'NSNotification.Name' conform to 'Comparable'}}
25+
// expected-note@-1 {{did you mean to use '.rawValue'?}} {{19-19=.rawValue}}
2526

2627
_ = x == y
2728
_ = 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
}

test/Constraints/optional.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -425,8 +425,9 @@ func test_force_unwrap_not_being_too_eager() {
425425

426426
// rdar://problem/57097401
427427
func invalidOptionalChaining(a: Any) {
428-
a == "="? // expected-error {{binary operator '==' cannot be applied to operands of type 'Any' and 'String?'}}
429-
// expected-note@-1 {{overloads for '==' exist with these partially matching parameter lists: (CodingUserInfoKey, CodingUserInfoKey), (FloatingPointSign, FloatingPointSign), (String, String), (Unicode.CanonicalCombiningClass, Unicode.CanonicalCombiningClass)}}
428+
a == "="? // expected-error {{cannot use optional chaining on non-optional value of type 'String'}}
429+
// expected-error@-1 {{protocol 'Any' as a type cannot conform to 'Equatable'}}
430+
// expected-note@-2 {{requirement from conditional conformance of 'Any?' to 'Equatable'}} expected-note@-2 {{only concrete types such as structs, enums and classes can conform to protocols}}
430431
}
431432

432433
// SR-12309 - Force unwrapping 'nil' compiles without warning
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)