Skip to content

Commit b318ab1

Browse files
committed
Prefer RawRepresentable fix-its that don't require an extra conversion
That is, if a type has a raw value of Int, and the function being called has overloads for both Int and UInt, we always want to offer a fix-it that leads to the 'Int' overload, not insert a conversion to UInt that might be incorrect. More https://bugs.swift.org/browse/SR-8150.
1 parent cc82ae0 commit b318ab1

File tree

2 files changed

+82
-26
lines changed

2 files changed

+82
-26
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 59 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4500,27 +4500,42 @@ diagnoseSingleCandidateFailures(CalleeCandidateInfo &CCI, Expr *fnExpr,
45004500
.diagnose();
45014501
}
45024502

4503-
static bool isRawRepresentableMismatch(Type fromType, Type toType,
4504-
KnownProtocolKind kind,
4505-
const ConstraintSystem &CS) {
4503+
namespace {
4504+
enum class RawRepresentableMismatch {
4505+
NotApplicable,
4506+
Convertible,
4507+
ExactMatch
4508+
};
4509+
}
4510+
4511+
static RawRepresentableMismatch
4512+
checkRawRepresentableMismatch(Type fromType, Type toType,
4513+
KnownProtocolKind kind,
4514+
const ConstraintSystem &CS) {
45064515
toType = toType->lookThroughAllOptionalTypes();
45074516
fromType = fromType->lookThroughAllOptionalTypes();
45084517

45094518
// First check if this is an attempt to convert from something to
45104519
// raw representable.
45114520
if (conformsToKnownProtocol(fromType, kind, CS)) {
4512-
if (isRawRepresentable(toType, kind, CS))
4513-
return true;
4521+
if (auto rawType = isRawRepresentable(toType, kind, CS)) {
4522+
if (rawType->isEqual(fromType))
4523+
return RawRepresentableMismatch::ExactMatch;
4524+
return RawRepresentableMismatch::Convertible;
4525+
}
45144526
}
45154527

45164528
// Otherwise, it might be an attempt to convert from raw representable
45174529
// to its raw value.
4518-
if (isRawRepresentable(fromType, kind, CS)) {
4519-
if (conformsToKnownProtocol(toType, kind, CS))
4520-
return true;
4530+
if (auto rawType = isRawRepresentable(fromType, kind, CS)) {
4531+
if (conformsToKnownProtocol(toType, kind, CS)) {
4532+
if (rawType->isEqual(toType))
4533+
return RawRepresentableMismatch::ExactMatch;
4534+
return RawRepresentableMismatch::Convertible;
4535+
}
45214536
}
45224537

4523-
return false;
4538+
return RawRepresentableMismatch::NotApplicable;
45244539
}
45254540

45264541
static bool diagnoseRawRepresentableMismatch(CalleeCandidateInfo &CCI,
@@ -4545,13 +4560,17 @@ static bool diagnoseRawRepresentableMismatch(CalleeCandidateInfo &CCI,
45454560
if (!argType || argType->hasTypeVariable() || argType->hasUnresolvedType())
45464561
return false;
45474562

4548-
ArrayRef<KnownProtocolKind> rawRepresentableProtocols = {
4563+
KnownProtocolKind rawRepresentableProtocols[] = {
45494564
KnownProtocolKind::ExpressibleByStringLiteral,
45504565
KnownProtocolKind::ExpressibleByIntegerLiteral};
45514566

45524567
const auto &CS = CCI.CS;
45534568
auto arguments = decomposeArgType(argType, argLabels);
4554-
auto *tupleArgs = dyn_cast<TupleExpr>(argExpr);
4569+
4570+
auto bestMatchKind = RawRepresentableMismatch::NotApplicable;
4571+
const UncurriedCandidate *bestMatchCandidate = nullptr;
4572+
KnownProtocolKind bestMatchProtocol;
4573+
size_t bestMatchIndex;
45554574

45564575
for (auto &candidate : CCI.candidates) {
45574576
auto *decl = candidate.getDecl();
@@ -4562,6 +4581,7 @@ static bool diagnoseRawRepresentableMismatch(CalleeCandidateInfo &CCI,
45624581
continue;
45634582

45644583
auto parameters = candidate.getParameters();
4584+
// FIXME: Default arguments?
45654585
if (parameters.size() != arguments.size())
45664586
continue;
45674587

@@ -4572,25 +4592,38 @@ static bool diagnoseRawRepresentableMismatch(CalleeCandidateInfo &CCI,
45724592
for (auto kind : rawRepresentableProtocols) {
45734593
// If trying to convert from raw type to raw representable,
45744594
// or vice versa from raw representable (e.g. enum) to raw type.
4575-
if (!isRawRepresentableMismatch(argType, paramType, kind, CS))
4576-
continue;
4577-
4578-
const Expr *expr = argExpr;
4579-
if (tupleArgs)
4580-
expr = tupleArgs->getElement(i);
4581-
expr = expr->getValueProvidingExpr();
4582-
4583-
auto diag =
4584-
CS.TC.diagnose(expr->getLoc(), diag::cannot_convert_argument_value,
4585-
argType, paramType);
4586-
4587-
tryRawRepresentableFixIts(diag, CS, argType, paramType, kind, expr);
4588-
return true;
4595+
auto matchKind = checkRawRepresentableMismatch(argType, paramType, kind,
4596+
CS);
4597+
if (matchKind > bestMatchKind) {
4598+
bestMatchKind = matchKind;
4599+
bestMatchProtocol = kind;
4600+
bestMatchCandidate = &candidate;
4601+
bestMatchIndex = i;
4602+
}
45894603
}
45904604
}
45914605
}
45924606

4593-
return false;
4607+
if (bestMatchKind == RawRepresentableMismatch::NotApplicable)
4608+
return false;
4609+
4610+
const Expr *expr = argExpr;
4611+
if (auto *tupleArgs = dyn_cast<TupleExpr>(argExpr))
4612+
expr = tupleArgs->getElement(bestMatchIndex);
4613+
expr = expr->getValueProvidingExpr();
4614+
4615+
auto parameters = bestMatchCandidate->getParameters();
4616+
auto paramType = parameters[bestMatchIndex].getType();
4617+
auto singleArgType = arguments[bestMatchIndex].getType();
4618+
4619+
auto diag = CS.TC.diagnose(expr->getLoc(),
4620+
diag::cannot_convert_argument_value,
4621+
singleArgType, paramType);
4622+
4623+
tryRawRepresentableFixIts(diag, CS, singleArgType, paramType,
4624+
bestMatchProtocol, expr);
4625+
return true;
4626+
45944627
}
45954628

45964629
// Extract expression for failed argument number

test/Sema/enum_raw_representable.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,29 @@ func rdar32432253(_ condition: Bool = false) {
145145
// expected-error@-1 {{cannot convert value of type 'E_32431165' to expected argument type 'String'}} {{11-11=}} {{17-17=.rawValue}}
146146
}
147147

148+
func sr8150_helper1(_: Int) {}
149+
func sr8150_helper1(_: Double) {}
150+
151+
func sr8150_helper2(_: Double) {}
152+
func sr8150_helper2(_: Int) {}
153+
154+
func sr8150_helper3(_: Foo) {}
155+
func sr8150_helper3(_: Bar) {}
156+
157+
func sr8150_helper4(_: Bar) {}
158+
func sr8150_helper4(_: Foo) {}
159+
160+
func sr8150(bar: Bar) {
161+
sr8150_helper1(bar)
162+
// expected-error@-1 {{cannot convert value of type 'Bar' to expected argument type 'Double'}} {{18-18=}} {{21-21=.rawValue}}
163+
sr8150_helper2(bar)
164+
// expected-error@-1 {{cannot convert value of type 'Bar' to expected argument type 'Double'}} {{18-18=}} {{21-21=.rawValue}}
165+
sr8150_helper3(0.0)
166+
// expected-error@-1 {{cannot convert value of type 'Double' to expected argument type 'Bar'}} {{18-18=Bar(rawValue: }} {{21-21=)}}
167+
sr8150_helper4(0.0)
168+
// expected-error@-1 {{cannot convert value of type 'Double' to expected argument type 'Bar'}} {{18-18=Bar(rawValue: }} {{21-21=)}}
169+
}
170+
148171

149172
struct NotEquatable { }
150173

0 commit comments

Comments
 (0)