Skip to content

Commit 9805b0a

Browse files
committed
[ConstraintSystem] Do more checking before suggesting to use of .rawValue
Introduce `repairByUsingRawValueOfRawRepresentableType` which is used for assignment, argument-to-parameter conversions and contextual mismatches. It checks whether `from` side is a raw representable type and tries to match `to` side to its `rawValue`. Also extract logic common for `repairByUsingRawValueOfRawRepresentableType` and `repairByExplicitRawRepresentativeUse` into `isValueOfRawRepresentable`.
1 parent 80c4aa6 commit 9805b0a

File tree

3 files changed

+61
-28
lines changed

3 files changed

+61
-28
lines changed

lib/Sema/CSFix.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1139,8 +1139,8 @@ ExplicitlyConstructRawRepresentable::create(ConstraintSystem &cs,
11391139

11401140
bool UseValueTypeOfRawRepresentative::diagnose(const Solution &solution,
11411141
bool asNote) const {
1142-
ArgumentMismatchFailure failure(solution, RawReprType, ExpectedType,
1143-
getLocator());
1142+
UseOfRawRepresentableInsteadOfItsRawValueFailure failure(
1143+
solution, RawReprType, ExpectedType, getLocator());
11441144
return failure.diagnose(asNote);
11451145
}
11461146

lib/Sema/CSSimplify.cpp

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3135,36 +3135,57 @@ bool ConstraintSystem::repairFailures(
31353135
return false;
31363136
};
31373137

3138-
// Check whether given `rawReprType` does indeed conform to `RawRepresentable`
3139-
// and if so check that given `valueType` matches its `RawValue` type. If that
3140-
// condition holds add a tailored fix which is going to suggest to explicitly
3141-
// construct a raw representable type from a given value type.
3142-
auto repairByExplicitRawRepresentativeUse =
3143-
[&](Type origValueType, Type origRawReprType) -> bool {
3144-
auto rawReprType = origRawReprType;
3145-
// Let's unwrap a single level of optionality since
3138+
// Check whether given `value` type matches a `RawValue` type of
3139+
// a given raw representable type.
3140+
auto isValueOfRawRepresentable = [&](Type valueType,
3141+
Type rawReprType) -> bool {
31463142
// diagnostic is going to suggest failable initializer anyway.
31473143
if (auto objType = rawReprType->getOptionalObjectType())
31483144
rawReprType = objType;
31493145

3150-
auto valueType = origValueType;
31513146
// If value is optional diagnostic would suggest using `Optional.map` in
31523147
// combination with `<Type>(rawValue: ...)` initializer.
31533148
if (auto objType = valueType->getOptionalObjectType())
31543149
valueType = objType;
31553150

3151+
if (rawReprType->isTypeVariableOrMember())
3152+
return false;
3153+
31563154
auto rawValue = isRawRepresentable(*this, rawReprType);
31573155
if (!rawValue)
31583156
return false;
31593157

31603158
auto result = matchTypes(valueType, rawValue, ConstraintKind::Conversion,
31613159
TMF_ApplyingFix, locator);
3160+
return !result.isFailure();
3161+
};
31623162

3163-
if (result.isFailure())
3163+
// Check whether given `rawReprType` does indeed conform to `RawRepresentable`
3164+
// and if so check that given `expectedType` matches its `RawValue` type. If
3165+
// that condition holds add a tailored fix which is going to suggest to
3166+
// explicitly construct a raw representable type from a given value type.
3167+
auto repairByExplicitRawRepresentativeUse = [&](Type expectedType,
3168+
Type rawReprType) -> bool {
3169+
if (!isValueOfRawRepresentable(expectedType, rawReprType))
31643170
return false;
31653171

31663172
conversionsOrFixes.push_back(ExplicitlyConstructRawRepresentable::create(
3167-
*this, origRawReprType, origValueType, getConstraintLocator(locator)));
3173+
*this, rawReprType, expectedType, getConstraintLocator(locator)));
3174+
return true;
3175+
};
3176+
3177+
// Check whether given `rawReprType` does indeed conform to `RawRepresentable`
3178+
// and if so check that given `expectedType` matches its `RawValue` type. If
3179+
// that condition holds add a tailored fix which is going to suggest to
3180+
// use `.rawValue` associated with given raw representable type to match
3181+
// given expected type.
3182+
auto repairByUsingRawValueOfRawRepresentableType =
3183+
[&](Type rawReprType, Type expectedType) -> bool {
3184+
if (!isValueOfRawRepresentable(expectedType, rawReprType))
3185+
return false;
3186+
3187+
conversionsOrFixes.push_back(UseValueTypeOfRawRepresentative::create(
3188+
*this, rawReprType, expectedType, getConstraintLocator(locator)));
31683189
return true;
31693190
};
31703191

@@ -3388,6 +3409,9 @@ bool ConstraintSystem::repairFailures(
33883409
if (repairByExplicitRawRepresentativeUse(lhs, rhs))
33893410
return true;
33903411

3412+
if (repairByUsingRawValueOfRawRepresentableType(lhs, rhs))
3413+
return true;
3414+
33913415
// Let's try to match source and destination types one more
33923416
// time to see whether they line up, if they do - the problem is
33933417
// related to immutability, otherwise it's a type mismatch.
@@ -3620,12 +3644,6 @@ bool ConstraintSystem::repairFailures(
36203644
break;
36213645
}
36223646

3623-
if (auto *fix = UseValueTypeOfRawRepresentative::attempt(*this, lhs, rhs,
3624-
locator)) {
3625-
conversionsOrFixes.push_back(fix);
3626-
break;
3627-
}
3628-
36293647
// If parameter is a collection but argument is not, let's try
36303648
// to try and match collection element type to the argument to
36313649
// produce better diagnostics e.g.:
@@ -3659,6 +3677,9 @@ bool ConstraintSystem::repairFailures(
36593677
if (repairByExplicitRawRepresentativeUse(lhs, rhs))
36603678
break;
36613679

3680+
if (repairByUsingRawValueOfRawRepresentableType(lhs, rhs))
3681+
break;
3682+
36623683
if (repairViaOptionalUnwrap(*this, lhs, rhs, matchKind, conversionsOrFixes,
36633684
locator))
36643685
break;
@@ -3877,6 +3898,9 @@ bool ConstraintSystem::repairFailures(
38773898
break;
38783899
}
38793900

3901+
if (repairByUsingRawValueOfRawRepresentableType(lhs, rhs))
3902+
break;
3903+
38803904
if (repairViaOptionalUnwrap(*this, lhs, rhs, matchKind, conversionsOrFixes,
38813905
locator))
38823906
break;

test/Sema/enum_raw_representable.swift

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -131,15 +131,15 @@ func rdar32431165_2(_: Int) {}
131131
func rdar32431165_2(_: Int, _: String) {}
132132

133133
rdar32431165_2(E_32431165.bar)
134-
// expected-error@-1 {{cannot convert value of type 'E_32431165' to expected argument type 'String'}} {{16-16=}} {{30-30=.rawValue}}
134+
// expected-error@-1 {{cannot convert value of type 'E_32431165' to expected argument type 'String'}} {{30-30=.rawValue}}
135135
rdar32431165_2(42, E_32431165.bar)
136-
// expected-error@-1 {{cannot convert value of type 'E_32431165' to expected argument type 'String'}} {{20-20=}} {{34-34=.rawValue}}
136+
// expected-error@-1 {{cannot convert value of type 'E_32431165' to expected argument type 'String'}} {{34-34=.rawValue}}
137137

138138
E_32431165.bar == "bar"
139-
// expected-error@-1 {{cannot convert value of type 'E_32431165' to expected argument type 'String}} {{1-1=}} {{15-15=.rawValue}}
139+
// expected-error@-1 {{cannot convert value of type 'E_32431165' to expected argument type 'String}} {{15-15=.rawValue}}
140140

141141
"bar" == E_32431165.bar
142-
// expected-error@-1 {{cannot convert value of type 'E_32431165' to expected argument type 'String}} {{10-10=}} {{24-24=.rawValue}}
142+
// expected-error@-1 {{cannot convert value of type 'E_32431165' to expected argument type 'String}} {{24-24=.rawValue}}
143143

144144
func rdar32431165_overloaded() -> Int { 42 } // expected-note {{found candidate with type 'Int'}}
145145
func rdar32431165_overloaded() -> String { "A" } // expected-note {{'rdar32431165_overloaded()' produces 'String', not the expected contextual result type 'E_32431165'}}
@@ -154,7 +154,7 @@ func test_candidate_diagnostic() {
154154
func rdar32432253(_ condition: Bool = false) {
155155
let choice: E_32431165 = condition ? .foo : .bar
156156
let _ = choice == "bar"
157-
// expected-error@-1 {{cannot convert value of type 'E_32431165' to expected argument type 'String'}} {{11-11=}} {{17-17=.rawValue}}
157+
// expected-error@-1 {{cannot convert value of type 'E_32431165' to expected argument type 'String'}} {{17-17=.rawValue}}
158158
}
159159

160160
func sr8150_helper1(_: Int) {}
@@ -171,9 +171,9 @@ func sr8150_helper4(_: Foo) {}
171171

172172
func sr8150(bar: Bar) {
173173
sr8150_helper1(bar)
174-
// expected-error@-1 {{cannot convert value of type 'Bar' to expected argument type 'Double'}} {{18-18=}} {{21-21=.rawValue}}
174+
// expected-error@-1 {{cannot convert value of type 'Bar' to expected argument type 'Double'}} {{21-21=.rawValue}}
175175
sr8150_helper2(bar)
176-
// expected-error@-1 {{cannot convert value of type 'Bar' to expected argument type 'Double'}} {{18-18=}} {{21-21=.rawValue}}
176+
// expected-error@-1 {{cannot convert value of type 'Bar' to expected argument type 'Double'}} {{21-21=.rawValue}}
177177
sr8150_helper3(0.0)
178178
// expected-error@-1 {{cannot convert value of type 'Double' to expected argument type 'Bar'}} {{18-18=Bar(rawValue: }} {{21-21=) ?? <#default value#>}}
179179
sr8150_helper4(0.0)
@@ -187,11 +187,20 @@ class SR8150Box {
187187
// Bonus problem with mutable values being passed.
188188
func sr8150_mutable(obj: SR8150Box) {
189189
sr8150_helper1(obj.bar)
190-
// expected-error@-1 {{cannot convert value of type 'Bar' to expected argument type 'Double'}} {{18-18=}} {{25-25=.rawValue}}
190+
// expected-error@-1 {{cannot convert value of type 'Bar' to expected argument type 'Double'}} {{25-25=.rawValue}}
191191

192192
var bar = obj.bar
193193
sr8150_helper1(bar)
194-
// expected-error@-1 {{cannot convert value of type 'Bar' to expected argument type 'Double'}} {{18-18=}} {{21-21=.rawValue}}
194+
// expected-error@-1 {{cannot convert value of type 'Bar' to expected argument type 'Double'}} {{21-21=.rawValue}}
195+
196+
func test(_ opt: Bar?) {
197+
sr8150_helper1(opt)
198+
// expected-error@-1 {{cannot convert value of type 'Bar?' to expected argument type 'Double'}} {{23-23=.map { $0.rawValue } ?? <#default value#>}}
199+
sr8150_helper1(opt ?? Bar.a)
200+
// expected-error@-1 {{cannot convert value of type 'Bar' to expected argument type 'Double'}} {{20-20=(}} {{32-32=).rawValue}}
201+
let _: Double? = opt
202+
// expected-error@-1 {{cannot convert value of type 'Bar?' to specified type 'Double?'}} {{25-25=.map { $0.rawValue }}}
203+
}
195204
}
196205

197206
struct NotEquatable { }

0 commit comments

Comments
 (0)