Skip to content

Commit cc50b46

Browse files
committed
[Diagnostics] Preserve raw from/to types in contextual mismatch diagnostic
This is useful in some situations where access to type variable(s) helps to diagnose the problem properly e.g. if it's a conversion to generic parameter.
1 parent f259286 commit cc50b46

File tree

2 files changed

+43
-33
lines changed

2 files changed

+43
-33
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2032,6 +2032,9 @@ bool ContextualFailure::diagnoseAsError() {
20322032
return true;
20332033
}
20342034

2035+
auto fromType = getFromType();
2036+
auto toType = getToType();
2037+
20352038
Diag<Type, Type> diagnostic;
20362039
switch (path.back().getKind()) {
20372040
case ConstraintLocator::ClosureResult: {
@@ -2040,9 +2043,8 @@ bool ContextualFailure::diagnoseAsError() {
20402043
closure->getExplicitResultTypeLoc().getTypeRepr()) {
20412044
auto resultRepr = closure->getExplicitResultTypeLoc().getTypeRepr();
20422045
emitDiagnostic(resultRepr->getStartLoc(),
2043-
diag::incorrect_explicit_closure_result, getFromType(),
2044-
getToType())
2045-
.fixItReplace(resultRepr->getSourceRange(), getToType().getString());
2046+
diag::incorrect_explicit_closure_result, fromType, toType)
2047+
.fixItReplace(resultRepr->getSourceRange(), toType.getString());
20462048
return true;
20472049
}
20482050

@@ -2071,22 +2073,21 @@ bool ContextualFailure::diagnoseAsError() {
20712073
return true;
20722074

20732075
if (CTP == CTP_ForEachStmt) {
2074-
if (FromType->isAnyExistentialType()) {
2076+
if (fromType->isAnyExistentialType()) {
20752077
emitDiagnostic(anchor->getLoc(), diag::type_cannot_conform,
2076-
/*isExistentialType=*/true, FromType, ToType);
2078+
/*isExistentialType=*/true, fromType, toType);
20772079
return true;
20782080
}
20792081

20802082
emitDiagnostic(
20812083
anchor->getLoc(),
20822084
diag::foreach_sequence_does_not_conform_to_expected_protocol,
2083-
FromType, ToType, bool(FromType->getOptionalObjectType()))
2085+
fromType, toType, bool(fromType->getOptionalObjectType()))
20842086
.highlight(anchor->getSourceRange());
20852087
return true;
20862088
}
20872089

2088-
auto contextualType = getToType();
2089-
if (auto msg = getDiagnosticFor(CTP, contextualType->isExistentialType())) {
2090+
if (auto msg = getDiagnosticFor(CTP, toType->isExistentialType())) {
20902091
diagnostic = *msg;
20912092
break;
20922093
}
@@ -2102,11 +2103,11 @@ bool ContextualFailure::diagnoseAsError() {
21022103
return false;
21032104

21042105
auto *choice = overload->choice.getDecl();
2105-
auto fnType = FromType->getAs<FunctionType>();
2106+
auto fnType = fromType->getAs<FunctionType>();
21062107
if (!fnType) {
21072108
emitDiagnostic(anchor->getLoc(),
21082109
diag::expected_result_in_contextual_member,
2109-
choice->getFullName(), FromType, ToType);
2110+
choice->getFullName(), fromType, toType);
21102111
return true;
21112112
}
21122113

@@ -2151,7 +2152,8 @@ bool ContextualFailure::diagnoseAsError() {
21512152
return false;
21522153
}
21532154

2154-
auto diag = emitDiagnostic(anchor->getLoc(), diagnostic, FromType, ToType);
2155+
auto diag =
2156+
emitDiagnostic(anchor->getLoc(), diagnostic, fromType, toType);
21552157
diag.highlight(anchor->getSourceRange());
21562158

21572159
(void)tryFixIts(diag);
@@ -2357,12 +2359,13 @@ bool ContextualFailure::diagnoseMissingFunctionCall() const {
23572359
if (getLocator()->isLastElement<LocatorPathElt::RValueAdjustment>())
23582360
return false;
23592361

2360-
auto *srcFT = FromType->getAs<FunctionType>();
2362+
auto *srcFT = getFromType()->getAs<FunctionType>();
23612363
if (!srcFT || !srcFT->getParams().empty())
23622364
return false;
23632365

2364-
if (ToType->is<AnyFunctionType>() ||
2365-
!TypeChecker::isConvertibleTo(srcFT->getResult(), ToType, getDC()))
2366+
auto toType = getToType();
2367+
if (toType->is<AnyFunctionType>() ||
2368+
!TypeChecker::isConvertibleTo(srcFT->getResult(), toType, getDC()))
23662369
return false;
23672370

23682371
auto *anchor = getAnchor();
@@ -2663,7 +2666,10 @@ bool ContextualFailure::tryRawRepresentableFixIts(
26632666

26642667
bool ContextualFailure::tryIntegerCastFixIts(
26652668
InFlightDiagnostic &diagnostic) const {
2666-
if (!isIntegerType(FromType) || !isIntegerType(ToType))
2669+
auto fromType = getFromType();
2670+
auto toType = getToType();
2671+
2672+
if (!isIntegerType(fromType) || !isIntegerType(toType))
26672673
return false;
26682674

26692675
auto getInnerCastedExpr = [&](Expr *expr) -> Expr * {
@@ -2684,7 +2690,7 @@ bool ContextualFailure::tryIntegerCastFixIts(
26842690
auto *anchor = getAnchor();
26852691
if (Expr *innerE = getInnerCastedExpr(anchor)) {
26862692
Type innerTy = getType(innerE);
2687-
if (TypeChecker::isConvertibleTo(innerTy, ToType, getDC())) {
2693+
if (TypeChecker::isConvertibleTo(innerTy, toType, getDC())) {
26882694
// Remove the unnecessary cast.
26892695
diagnostic.fixItRemoveChars(anchor->getLoc(), innerE->getStartLoc())
26902696
.fixItRemove(anchor->getEndLoc());
@@ -2693,7 +2699,7 @@ bool ContextualFailure::tryIntegerCastFixIts(
26932699
}
26942700

26952701
// Add a wrapping integer cast.
2696-
std::string convWrapBefore = ToType.getString();
2702+
std::string convWrapBefore = toType.getString();
26972703
convWrapBefore += "(";
26982704
std::string convWrapAfter = ")";
26992705
SourceRange exprRange = anchor->getSourceRange();
@@ -2715,8 +2721,8 @@ bool ContextualFailure::trySequenceSubsequenceFixIts(
27152721

27162722
// Substring -> String conversion
27172723
// Wrap in String.init
2718-
if (FromType->isEqual(Substring)) {
2719-
if (ToType->isEqual(String)) {
2724+
if (getFromType()->isEqual(Substring)) {
2725+
if (getToType()->isEqual(String)) {
27202726
auto *anchor = getAnchor()->getSemanticsProvidingExpr();
27212727
auto range = anchor->getSourceRange();
27222728
diagnostic.fixItInsert(range.Start, "String(");
@@ -2775,10 +2781,11 @@ bool ContextualFailure::tryProtocolConformanceFixIt(
27752781
if (!nominal)
27762782
return false;
27772783

2784+
auto fromType = getFromType();
27782785
// We need to get rid of optionals and parens as it's not relevant when
27792786
// printing the diagnostic and the fix-it.
27802787
auto unwrappedToType =
2781-
ToType->lookThroughAllOptionalTypes()->getWithoutParens();
2788+
getToType()->lookThroughAllOptionalTypes()->getWithoutParens();
27822789

27832790
// If the protocol requires a class & we don't have one (maybe the context
27842791
// is a struct), then bail out instead of offering a broken fix-it later on.
@@ -2789,13 +2796,13 @@ bool ContextualFailure::tryProtocolConformanceFixIt(
27892796
requiresClass = layout.requiresClass();
27902797
}
27912798

2792-
if (requiresClass && !FromType->is<ClassType>()) {
2799+
if (requiresClass && !fromType->is<ClassType>()) {
27932800
return false;
27942801
}
27952802

27962803
// We can only offer a fix-it if we're assigning to a protocol type and
27972804
// the type we're assigning is the same as the innermost type context.
2798-
bool shouldOfferFixIt = nominal->getSelfTypeInContext()->isEqual(FromType) &&
2805+
bool shouldOfferFixIt = nominal->getSelfTypeInContext()->isEqual(fromType) &&
27992806
unwrappedToType->isExistentialType();
28002807
if (!shouldOfferFixIt)
28012808
return false;
@@ -2805,7 +2812,7 @@ bool ContextualFailure::tryProtocolConformanceFixIt(
28052812
// Let's build a list of protocols that the context does not conform to.
28062813
SmallVector<std::string, 8> missingProtoTypeStrings;
28072814
for (auto protocol : layout.getProtocols()) {
2808-
if (!TypeChecker::conformsToProtocol(FromType, protocol->getDecl(), getDC(),
2815+
if (!TypeChecker::conformsToProtocol(fromType, protocol->getDecl(), getDC(),
28092816
ConformanceCheckFlags::InExpression)) {
28102817
missingProtoTypeStrings.push_back(protocol->getString());
28112818
}
@@ -2833,7 +2840,7 @@ bool ContextualFailure::tryProtocolConformanceFixIt(
28332840
// TODO: Maybe also insert the requirement stubs?
28342841
auto conformanceDiag = emitDiagnostic(
28352842
getAnchor()->getLoc(), diag::assign_protocol_conformance_fix_it,
2836-
unwrappedToType, nominal->getDescriptiveKind(), FromType);
2843+
unwrappedToType, nominal->getDescriptiveKind(), fromType);
28372844
if (nominal->getInherited().size() > 0) {
28382845
auto lastInherited = nominal->getInherited().back().getLoc();
28392846
auto lastInheritedEndLoc =

lib/Sema/CSDiagnostics.h

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -694,23 +694,26 @@ class AssignmentFailure final : public FailureDiagnostic {
694694
/// e.g. argument/parameter, closure result, conversions etc.
695695
class ContextualFailure : public FailureDiagnostic {
696696
ContextualTypePurpose CTP;
697-
Type FromType, ToType;
697+
Type RawFromType, RawToType;
698698

699699
public:
700700
ContextualFailure(ConstraintSystem &cs, Type lhs, Type rhs,
701701
ConstraintLocator *locator)
702702
: ContextualFailure(cs, cs.getContextualTypePurpose(), lhs, rhs,
703703
locator) {}
704704

705-
ContextualFailure(ConstraintSystem &cs,
706-
ContextualTypePurpose purpose, Type lhs, Type rhs,
707-
ConstraintLocator *locator)
708-
: FailureDiagnostic(cs, locator), CTP(purpose),
709-
FromType(resolve(lhs)), ToType(resolve(rhs)) {}
705+
ContextualFailure(ConstraintSystem &cs, ContextualTypePurpose purpose,
706+
Type lhs, Type rhs, ConstraintLocator *locator)
707+
: FailureDiagnostic(cs, locator), CTP(purpose), RawFromType(lhs),
708+
RawToType(rhs) {}
709+
710+
Type getFromType() const { return resolve(RawFromType); }
711+
712+
Type getToType() const { return resolve(RawToType); }
710713

711-
Type getFromType() const { return FromType; }
714+
Type getRawFromType() const { return RawFromType; }
712715

713-
Type getToType() const { return ToType; }
716+
Type getRawToType() const { return RawToType; }
714717

715718
bool diagnoseAsError() override;
716719

@@ -791,7 +794,7 @@ class ContextualFailure : public FailureDiagnostic {
791794
Type contextualType);
792795

793796
private:
794-
Type resolve(Type rawType) {
797+
Type resolve(Type rawType) const {
795798
return resolveType(rawType)->getWithoutSpecifierType();
796799
}
797800

0 commit comments

Comments
 (0)