Skip to content

Commit 651503b

Browse files
authored
Merge pull request swiftlang#32128 from xedin/adjust-raw-representable-diag
[Diagnostics] Refactor diagnostics related to raw representable types
2 parents 492ba85 + b938f96 commit 651503b

File tree

7 files changed

+374
-245
lines changed

7 files changed

+374
-245
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 133 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -166,12 +166,6 @@ bool FailureDiagnostic::conformsToKnownProtocol(
166166
return constraints::conformsToKnownProtocol(cs, type, protocol);
167167
}
168168

169-
Type FailureDiagnostic::isRawRepresentable(Type type,
170-
KnownProtocolKind protocol) const {
171-
auto &cs = getConstraintSystem();
172-
return constraints::isRawRepresentable(cs, type, protocol);
173-
}
174-
175169
Type RequirementFailure::getOwnerType() const {
176170
auto anchor = getRawAnchor();
177171

@@ -2297,12 +2291,6 @@ void ContextualFailure::tryFixIts(InFlightDiagnostic &diagnostic) const {
22972291
if (trySequenceSubsequenceFixIts(diagnostic))
22982292
return;
22992293

2300-
if (tryRawRepresentableFixIts(
2301-
diagnostic, KnownProtocolKind::ExpressibleByIntegerLiteral) ||
2302-
tryRawRepresentableFixIts(diagnostic,
2303-
KnownProtocolKind::ExpressibleByStringLiteral))
2304-
return;
2305-
23062294
if (tryIntegerCastFixIts(diagnostic))
23072295
return;
23082296

@@ -2532,130 +2520,6 @@ bool ContextualFailure::diagnoseYieldByReferenceMismatch() const {
25322520
return true;
25332521
}
25342522

2535-
bool ContextualFailure::tryRawRepresentableFixIts(
2536-
InFlightDiagnostic &diagnostic,
2537-
KnownProtocolKind rawRepresentableProtocol) const {
2538-
auto anchor = getAnchor();
2539-
auto fromType = getFromType();
2540-
auto toType = getToType();
2541-
2542-
// The following fixes apply for optional destination types as well.
2543-
bool toTypeIsOptional = !toType->getOptionalObjectType().isNull();
2544-
toType = toType->lookThroughAllOptionalTypes();
2545-
2546-
Type fromTypeUnwrapped = fromType->getOptionalObjectType();
2547-
bool fromTypeIsOptional = !fromTypeUnwrapped.isNull();
2548-
if (fromTypeIsOptional)
2549-
fromType = fromTypeUnwrapped;
2550-
2551-
auto fixIt = [&](StringRef convWrapBefore, StringRef convWrapAfter,
2552-
const Expr *expr) {
2553-
SourceRange exprRange = expr->getSourceRange();
2554-
if (fromTypeIsOptional && toTypeIsOptional) {
2555-
// Use optional's map function to convert conditionally, like so:
2556-
// expr.map{ T(rawValue: $0) }
2557-
bool needsParens = !expr->canAppendPostfixExpression();
2558-
std::string mapCodeFix;
2559-
if (needsParens) {
2560-
diagnostic.fixItInsert(exprRange.Start, "(");
2561-
mapCodeFix += ")";
2562-
}
2563-
mapCodeFix += ".map { ";
2564-
mapCodeFix += convWrapBefore;
2565-
mapCodeFix += "$0";
2566-
mapCodeFix += convWrapAfter;
2567-
mapCodeFix += " }";
2568-
diagnostic.fixItInsertAfter(exprRange.End, mapCodeFix);
2569-
} else if (!fromTypeIsOptional) {
2570-
diagnostic.fixItInsert(exprRange.Start, convWrapBefore);
2571-
diagnostic.fixItInsertAfter(exprRange.End, convWrapAfter);
2572-
} else {
2573-
SmallString<16> fixItBefore(convWrapBefore);
2574-
SmallString<16> fixItAfter;
2575-
2576-
if (!expr->canAppendPostfixExpression(true)) {
2577-
fixItBefore += "(";
2578-
fixItAfter = ")";
2579-
}
2580-
2581-
fixItAfter += "!" + convWrapAfter.str();
2582-
2583-
diagnostic.flush();
2584-
emitDiagnostic(diag::construct_raw_representable_from_unwrapped_value,
2585-
toType, fromType)
2586-
.highlight(exprRange)
2587-
.fixItInsert(exprRange.Start, fixItBefore)
2588-
.fixItInsertAfter(exprRange.End, fixItAfter);
2589-
}
2590-
};
2591-
2592-
if (conformsToKnownProtocol(fromType, rawRepresentableProtocol)) {
2593-
if (conformsToKnownProtocol(fromType, KnownProtocolKind::OptionSet) &&
2594-
isExpr<IntegerLiteralExpr>(anchor) &&
2595-
castToExpr<IntegerLiteralExpr>(anchor)->getDigitsText() == "0") {
2596-
diagnostic.fixItReplace(::getSourceRange(anchor), "[]");
2597-
return true;
2598-
}
2599-
if (auto rawTy = isRawRepresentable(toType, rawRepresentableProtocol)) {
2600-
// Produce before/after strings like 'Result(rawValue: RawType(<expr>))'
2601-
// or just 'Result(rawValue: <expr>)'.
2602-
std::string convWrapBefore = toType.getString();
2603-
convWrapBefore += "(rawValue: ";
2604-
std::string convWrapAfter = ")";
2605-
if (!isExpr<LiteralExpr>(anchor) &&
2606-
!TypeChecker::isConvertibleTo(fromType, rawTy, getDC())) {
2607-
// Only try to insert a converting construction if the protocol is a
2608-
// literal protocol and not some other known protocol.
2609-
switch (rawRepresentableProtocol) {
2610-
#define EXPRESSIBLE_BY_LITERAL_PROTOCOL_WITH_NAME(name, _, __, ___) \
2611-
case KnownProtocolKind::name: \
2612-
break;
2613-
#define PROTOCOL_WITH_NAME(name, _) \
2614-
case KnownProtocolKind::name: \
2615-
return false;
2616-
#include "swift/AST/KnownProtocols.def"
2617-
}
2618-
convWrapBefore += rawTy->getString();
2619-
convWrapBefore += "(";
2620-
convWrapAfter += ")";
2621-
}
2622-
2623-
if (auto *E = getAsExpr(anchor))
2624-
fixIt(convWrapBefore, convWrapAfter, E);
2625-
return true;
2626-
}
2627-
}
2628-
2629-
if (auto rawTy = isRawRepresentable(fromType, rawRepresentableProtocol)) {
2630-
if (conformsToKnownProtocol(toType, rawRepresentableProtocol)) {
2631-
std::string convWrapBefore;
2632-
std::string convWrapAfter = ".rawValue";
2633-
if (!TypeChecker::isConvertibleTo(rawTy, toType, getDC())) {
2634-
// Only try to insert a converting construction if the protocol is a
2635-
// literal protocol and not some other known protocol.
2636-
switch (rawRepresentableProtocol) {
2637-
#define EXPRESSIBLE_BY_LITERAL_PROTOCOL_WITH_NAME(name, _, __, ___) \
2638-
case KnownProtocolKind::name: \
2639-
break;
2640-
#define PROTOCOL_WITH_NAME(name, _) \
2641-
case KnownProtocolKind::name: \
2642-
return false;
2643-
#include "swift/AST/KnownProtocols.def"
2644-
}
2645-
convWrapBefore += toType->getString();
2646-
convWrapBefore += "(";
2647-
convWrapAfter += ")";
2648-
}
2649-
2650-
if (auto *E = getAsExpr(anchor))
2651-
fixIt(convWrapBefore, convWrapAfter, E);
2652-
return true;
2653-
}
2654-
}
2655-
2656-
return false;
2657-
}
2658-
26592523
bool ContextualFailure::tryIntegerCastFixIts(
26602524
InFlightDiagnostic &diagnostic) const {
26612525
auto fromType = getFromType();
@@ -6389,3 +6253,136 @@ bool UnableToInferKeyPathRootFailure::diagnoseAsError() {
63896253
.fixItInsertAfter(keyPathExpr->getStartLoc(), "<#Root#>");
63906254
return true;
63916255
}
6256+
6257+
Optional<Diag<Type, Type>>
6258+
AbstractRawRepresentableFailure::getDiagnostic() const {
6259+
auto *locator = getLocator();
6260+
6261+
if (locator->isForContextualType()) {
6262+
return diag::cannot_convert_initializer_value;
6263+
} else if (locator->isForAssignment()) {
6264+
return diag::cannot_convert_assign;
6265+
} else if (locator->isLastElement<LocatorPathElt::ApplyArgToParam>()) {
6266+
return diag::cannot_convert_argument_value;
6267+
}
6268+
6269+
return None;
6270+
}
6271+
6272+
bool AbstractRawRepresentableFailure::diagnoseAsError() {
6273+
auto message = getDiagnostic();
6274+
if (!message)
6275+
return false;
6276+
6277+
auto diagnostic = emitDiagnostic(*message, getFromType(), getToType());
6278+
fixIt(diagnostic);
6279+
return true;
6280+
}
6281+
6282+
bool AbstractRawRepresentableFailure::diagnoseAsNote() {
6283+
auto *locator = getLocator();
6284+
6285+
Optional<InFlightDiagnostic> diagnostic;
6286+
if (locator->isForContextualType()) {
6287+
auto overload = getCalleeOverloadChoiceIfAvailable(locator);
6288+
if (!overload)
6289+
return false;
6290+
6291+
if (auto *decl = overload->choice.getDeclOrNull()) {
6292+
diagnostic.emplace(emitDiagnosticAt(
6293+
decl, diag::cannot_convert_candidate_result_to_contextual_type,
6294+
decl->getName(), ExpectedType, RawReprType));
6295+
}
6296+
} else if (auto argConv =
6297+
locator->getLastElementAs<LocatorPathElt::ApplyArgToParam>()) {
6298+
diagnostic.emplace(
6299+
emitDiagnostic(diag::candidate_has_invalid_argument_at_position,
6300+
RawReprType, argConv->getParamIdx(), /*inOut=*/false));
6301+
}
6302+
6303+
if (diagnostic) {
6304+
fixIt(*diagnostic);
6305+
return true;
6306+
}
6307+
6308+
return false;
6309+
}
6310+
6311+
void MissingRawRepresentableInitFailure::fixIt(
6312+
InFlightDiagnostic &diagnostic) const {
6313+
if (auto *E = getAsExpr(getAnchor())) {
6314+
auto range = E->getSourceRange();
6315+
auto rawReprObjType = RawReprType->getOptionalObjectType();
6316+
auto valueObjType = ExpectedType->getOptionalObjectType();
6317+
6318+
if (rawReprObjType && valueObjType) {
6319+
std::string mapCodeFix;
6320+
6321+
// Check whether expression has been be wrapped in parens first.
6322+
if (!E->canAppendPostfixExpression()) {
6323+
diagnostic.fixItInsert(range.Start, "(");
6324+
mapCodeFix += ")";
6325+
}
6326+
6327+
mapCodeFix += ".map { ";
6328+
mapCodeFix += rawReprObjType->getString();
6329+
mapCodeFix += "(rawValue: $0) }";
6330+
6331+
diagnostic.fixItInsertAfter(range.End, mapCodeFix);
6332+
} else if (rawReprObjType) {
6333+
diagnostic
6334+
.fixItInsert(range.Start, rawReprObjType->getString() + "(rawValue: ")
6335+
.fixItInsertAfter(range.End, ")");
6336+
} else if (valueObjType) {
6337+
diagnostic.flush();
6338+
6339+
std::string fixItBefore = RawReprType->getString() + "(rawValue: ";
6340+
std::string fixItAfter;
6341+
6342+
if (!E->canAppendPostfixExpression(true)) {
6343+
fixItBefore += "(";
6344+
fixItAfter += ")";
6345+
}
6346+
6347+
fixItAfter += "!) ?? <#default value#>";
6348+
6349+
emitDiagnostic(diag::construct_raw_representable_from_unwrapped_value,
6350+
RawReprType, valueObjType)
6351+
.highlight(range)
6352+
.fixItInsert(range.Start, fixItBefore)
6353+
.fixItInsertAfter(range.End, fixItAfter);
6354+
} else {
6355+
diagnostic
6356+
.fixItInsert(range.Start, RawReprType->getString() + "(rawValue: ")
6357+
.fixItInsertAfter(range.End, ") ?? <#default value#>");
6358+
}
6359+
}
6360+
}
6361+
6362+
void MissingRawValueFailure::fixIt(InFlightDiagnostic &diagnostic) const {
6363+
auto *E = getAsExpr(getAnchor());
6364+
if (!E)
6365+
return;
6366+
6367+
std::string fix;
6368+
6369+
auto range = E->getSourceRange();
6370+
if (!E->canAppendPostfixExpression()) {
6371+
diagnostic.fixItInsert(range.Start, "(");
6372+
fix += ")";
6373+
}
6374+
6375+
// If raw representable is an optional we need to map its raw value out
6376+
// out first and then, if destination is not optional, allow to specify
6377+
// default value.
6378+
if (RawReprType->getOptionalObjectType()) {
6379+
fix += "?.rawValue";
6380+
6381+
if (!ExpectedType->getOptionalObjectType())
6382+
fix += " ?? <#default value#>";
6383+
} else {
6384+
fix += ".rawValue";
6385+
}
6386+
6387+
diagnostic.fixItInsertAfter(range.End, fix);
6388+
}

0 commit comments

Comments
 (0)