Skip to content

Commit a3b5684

Browse files
authored
Merge pull request #17714 from jrose-apple/raw-deal (#17724)
Prefer RawRepresentable fix-its that don't require an extra conversion https://bugs.swift.org/browse/SR-8150 (cherry picked from commit 9116f95)
1 parent b831c12 commit a3b5684

File tree

2 files changed

+84
-27
lines changed

2 files changed

+84
-27
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 59 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4426,27 +4426,42 @@ diagnoseSingleCandidateFailures(CalleeCandidateInfo &CCI, Expr *fnExpr,
44264426
.diagnose();
44274427
}
44284428

4429-
static bool isRawRepresentableMismatch(Type fromType, Type toType,
4430-
KnownProtocolKind kind,
4431-
const ConstraintSystem &CS) {
4429+
namespace {
4430+
enum class RawRepresentableMismatch {
4431+
NotApplicable,
4432+
Convertible,
4433+
ExactMatch
4434+
};
4435+
}
4436+
4437+
static RawRepresentableMismatch
4438+
checkRawRepresentableMismatch(Type fromType, Type toType,
4439+
KnownProtocolKind kind,
4440+
const ConstraintSystem &CS) {
44324441
toType = toType->lookThroughAllOptionalTypes();
44334442
fromType = fromType->lookThroughAllOptionalTypes();
44344443

44354444
// First check if this is an attempt to convert from something to
44364445
// raw representable.
44374446
if (conformsToKnownProtocol(fromType, kind, CS)) {
4438-
if (isRawRepresentable(toType, kind, CS))
4439-
return true;
4447+
if (auto rawType = isRawRepresentable(toType, kind, CS)) {
4448+
if (rawType->isEqual(fromType))
4449+
return RawRepresentableMismatch::ExactMatch;
4450+
return RawRepresentableMismatch::Convertible;
4451+
}
44404452
}
44414453

44424454
// Otherwise, it might be an attempt to convert from raw representable
44434455
// to its raw value.
4444-
if (isRawRepresentable(fromType, kind, CS)) {
4445-
if (conformsToKnownProtocol(toType, kind, CS))
4446-
return true;
4456+
if (auto rawType = isRawRepresentable(fromType, kind, CS)) {
4457+
if (conformsToKnownProtocol(toType, kind, CS)) {
4458+
if (rawType->isEqual(toType))
4459+
return RawRepresentableMismatch::ExactMatch;
4460+
return RawRepresentableMismatch::Convertible;
4461+
}
44474462
}
44484463

4449-
return false;
4464+
return RawRepresentableMismatch::NotApplicable;
44504465
}
44514466

44524467
static bool diagnoseRawRepresentableMismatch(CalleeCandidateInfo &CCI,
@@ -4471,13 +4486,17 @@ static bool diagnoseRawRepresentableMismatch(CalleeCandidateInfo &CCI,
44714486
if (!argType || argType->hasTypeVariable() || argType->hasUnresolvedType())
44724487
return false;
44734488

4474-
ArrayRef<KnownProtocolKind> rawRepresentableProtocols = {
4489+
KnownProtocolKind rawRepresentableProtocols[] = {
44754490
KnownProtocolKind::ExpressibleByStringLiteral,
44764491
KnownProtocolKind::ExpressibleByIntegerLiteral};
44774492

44784493
const auto &CS = CCI.CS;
44794494
auto arguments = decomposeArgType(argType, argLabels);
4480-
auto *tupleArgs = dyn_cast<TupleExpr>(argExpr);
4495+
4496+
auto bestMatchKind = RawRepresentableMismatch::NotApplicable;
4497+
const UncurriedCandidate *bestMatchCandidate = nullptr;
4498+
KnownProtocolKind bestMatchProtocol;
4499+
size_t bestMatchIndex;
44814500

44824501
for (auto &candidate : CCI.candidates) {
44834502
auto *decl = candidate.getDecl();
@@ -4489,6 +4508,7 @@ static bool diagnoseRawRepresentableMismatch(CalleeCandidateInfo &CCI,
44894508
computeDefaultMap(candidate.getArgumentType(), decl,
44904509
candidate.level, defaultMap);
44914510

4511+
// FIXME: Default arguments?
44924512
if (parameters.size() != arguments.size())
44934513
continue;
44944514

@@ -4499,24 +4519,38 @@ static bool diagnoseRawRepresentableMismatch(CalleeCandidateInfo &CCI,
44994519
for (auto kind : rawRepresentableProtocols) {
45004520
// If trying to convert from raw type to raw representable,
45014521
// or vice versa from raw representable (e.g. enum) to raw type.
4502-
if (!isRawRepresentableMismatch(argType, paramType, kind, CS))
4503-
continue;
4504-
4505-
auto *expr = argExpr;
4506-
if (tupleArgs)
4507-
expr = tupleArgs->getElement(i);
4508-
4509-
auto diag =
4510-
CS.TC.diagnose(expr->getLoc(), diag::cannot_convert_argument_value,
4511-
argType, paramType);
4512-
4513-
tryRawRepresentableFixIts(diag, CS, argType, paramType, kind, expr);
4514-
return true;
4522+
auto matchKind = checkRawRepresentableMismatch(argType, paramType, kind,
4523+
CS);
4524+
if (matchKind > bestMatchKind) {
4525+
bestMatchKind = matchKind;
4526+
bestMatchProtocol = kind;
4527+
bestMatchCandidate = &candidate;
4528+
bestMatchIndex = i;
4529+
}
45154530
}
45164531
}
45174532
}
45184533

4519-
return false;
4534+
if (bestMatchKind == RawRepresentableMismatch::NotApplicable)
4535+
return false;
4536+
4537+
const Expr *expr = argExpr;
4538+
if (auto *tupleArgs = dyn_cast<TupleExpr>(argExpr))
4539+
expr = tupleArgs->getElement(bestMatchIndex);
4540+
expr = expr->getValueProvidingExpr();
4541+
4542+
auto parameters = bestMatchCandidate->getUncurriedFunctionType()->getParams();
4543+
auto paramType = parameters[bestMatchIndex].getType();
4544+
auto singleArgType = arguments[bestMatchIndex].getType();
4545+
4546+
auto diag = CS.TC.diagnose(expr->getLoc(),
4547+
diag::cannot_convert_argument_value,
4548+
singleArgType, paramType);
4549+
4550+
tryRawRepresentableFixIts(diag, CS, singleArgType, paramType,
4551+
bestMatchProtocol, expr);
4552+
return true;
4553+
45204554
}
45214555

45224556
// Extract expression for failed argument number

test/Sema/enum_raw_representable.swift

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ rdar32431165_1(.baz)
120120
// expected-error@-1 {{reference to member 'baz' cannot be resolved without a contextual type}}
121121

122122
rdar32431165_1("")
123-
// expected-error@-1 {{cannot convert value of type 'String' to expected argument type 'E_32431165'}} {{15-15=E_32431165(rawValue: }} {{19-19=)}}
123+
// expected-error@-1 {{cannot convert value of type 'String' to expected argument type 'E_32431165'}} {{16-16=E_32431165(rawValue: }} {{18-18=)}}
124124
rdar32431165_1(42, "")
125125
// expected-error@-1 {{cannot convert value of type 'String' to expected argument type 'E_32431165'}} {{20-20=E_32431165(rawValue: }} {{22-22=)}}
126126

@@ -129,7 +129,7 @@ func rdar32431165_2(_: Int) {}
129129
func rdar32431165_2(_: Int, _: String) {}
130130

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

@@ -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)