Skip to content

Commit b813976

Browse files
committed
[Diagnostics] Port diagnostic for CTP_YieldByReference
Last special case from `FailureDiagnosis::diagnoseContextualConversionError` has been ported to the new diagnostic framework.
1 parent fb9a864 commit b813976

File tree

5 files changed

+75
-22
lines changed

5 files changed

+75
-22
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1683,24 +1683,6 @@ bool FailureDiagnosis::diagnoseContextualConversionError(
16831683
if (isUnresolvedOrTypeVarType(exprType) || exprType->isEqual(contextualType))
16841684
return false;
16851685

1686-
if (CTP == CTP_YieldByReference) {
1687-
if (auto contextualLV = contextualType->getAs<LValueType>())
1688-
contextualType = contextualLV->getObjectType();
1689-
if (auto exprLV = exprType->getAs<LValueType>()) {
1690-
diagnose(expr->getLoc(), diag::cannot_yield_wrong_type_by_reference,
1691-
exprLV->getObjectType(), contextualType);
1692-
} else if (exprType->isEqual(contextualType)) {
1693-
diagnose(expr->getLoc(), diag::cannot_yield_rvalue_by_reference_same_type,
1694-
exprType);
1695-
} else {
1696-
diagnose(expr->getLoc(), diag::cannot_yield_rvalue_by_reference, exprType,
1697-
contextualType);
1698-
}
1699-
return true;
1700-
}
1701-
1702-
exprType = exprType->getRValueType();
1703-
17041686
// Don't attempt fixits if we have an unsolved type variable, since
17051687
// the recovery path's recursion into the type checker via typeCheckCast()
17061688
// will confuse matters.

lib/Sema/CSDiagnostics.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1885,6 +1885,9 @@ bool ContextualFailure::diagnoseAsError() {
18851885
if (diagnoseThrowsTypeMismatch())
18861886
return true;
18871887

1888+
if (diagnoseYieldByReferenceMismatch())
1889+
return true;
1890+
18881891
auto contextualType = getToType();
18891892
if (auto msg = getDiagnosticFor(CTP, contextualType->isExistentialType())) {
18901893
diagnostic = *msg;
@@ -2238,6 +2241,27 @@ bool ContextualFailure::diagnoseThrowsTypeMismatch() const {
22382241
return true;
22392242
}
22402243

2244+
bool ContextualFailure::diagnoseYieldByReferenceMismatch() const {
2245+
if (CTP != CTP_YieldByReference)
2246+
return false;
2247+
2248+
auto *anchor = getAnchor();
2249+
auto exprType = getType(anchor);
2250+
auto contextualType = getToType();
2251+
2252+
if (auto exprLV = exprType->getAs<LValueType>()) {
2253+
emitDiagnostic(anchor->getLoc(), diag::cannot_yield_wrong_type_by_reference,
2254+
exprLV->getObjectType(), contextualType);
2255+
} else if (exprType->isEqual(contextualType)) {
2256+
emitDiagnostic(anchor->getLoc(),
2257+
diag::cannot_yield_rvalue_by_reference_same_type, exprType);
2258+
} else {
2259+
emitDiagnostic(anchor->getLoc(), diag::cannot_yield_rvalue_by_reference,
2260+
exprType, contextualType);
2261+
}
2262+
return true;
2263+
}
2264+
22412265
bool ContextualFailure::tryRawRepresentableFixIts(
22422266
InFlightDiagnostic &diagnostic,
22432267
KnownProtocolKind rawRepresentableProtocol) const {

lib/Sema/CSDiagnostics.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,10 @@ class ContextualFailure : public FailureDiagnostic {
633633
/// something with doesn't conform to `Error`.
634634
bool diagnoseThrowsTypeMismatch() const;
635635

636+
/// Produce a specialized diagnostic if this is an attempt to `yield`
637+
/// something of incorrect type.
638+
bool diagnoseYieldByReferenceMismatch() const;
639+
636640
/// Attempt to attach any relevant fix-its to already produced diagnostic.
637641
void tryFixIts(InFlightDiagnostic &diagnostic) const;
638642

lib/Sema/CSSimplify.cpp

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2028,15 +2028,36 @@ ConstraintSystem::matchTypesBindTypeVar(
20282028
type = type->getRValueType();
20292029
}
20302030

2031+
// Attempt to fix situations where type variable can't be bound
2032+
// to a particular type e.g. `l-value` or `inout`.
2033+
auto fixReferenceMismatch = [&](TypeVariableType *typeVar,
2034+
Type type) -> bool {
2035+
if (auto last = locator.last()) {
2036+
if (last->is<LocatorPathElt::ContextualType>()) {
2037+
auto *fix = IgnoreContextualType::create(*this, typeVar, type,
2038+
getConstraintLocator(locator));
2039+
return !recordFix(fix);
2040+
}
2041+
}
2042+
2043+
return false;
2044+
};
2045+
20312046
// If the left-hand type variable cannot bind to an lvalue,
20322047
// but we still have an lvalue, fail.
20332048
if (!typeVar->getImpl().canBindToLValue() && type->hasLValueType()) {
2034-
return getTypeMatchFailure(locator);
2049+
if (shouldAttemptFixes() && fixReferenceMismatch(typeVar, type))
2050+
return getTypeMatchSuccess();
2051+
2052+
return getTypeMatchFailure(locator);
20352053
}
20362054

20372055
// If the left-hand type variable cannot bind to an inout,
20382056
// but we still have an inout, fail.
20392057
if (!typeVar->getImpl().canBindToInOut() && type->is<InOutType>()) {
2058+
if (shouldAttemptFixes() && fixReferenceMismatch(typeVar, type))
2059+
return getTypeMatchSuccess();
2060+
20402061
return getTypeMatchFailure(locator);
20412062
}
20422063

@@ -2399,9 +2420,31 @@ bool ConstraintSystem::repairFailures(
23992420
});
24002421
};
24012422

2402-
auto &elt = path.back();
2423+
auto elt = path.back();
24032424
switch (elt.getKind()) {
2404-
case ConstraintLocator::LValueConversion:
2425+
case ConstraintLocator::LValueConversion: {
2426+
auto CTP = getContextualTypePurpose();
2427+
// Special case for `CTP_CallArgument` set by CSDiag
2428+
// while type-checking each argument because we yet
2429+
// to cover argument-to-parameter conversions in the
2430+
// new framework.
2431+
if (CTP != CTP_CallArgument) {
2432+
// Ignore l-value conversion element since it has already
2433+
// played its role.
2434+
path.pop_back();
2435+
// If this is a contextual mismatch between l-value types e.g.
2436+
// `@lvalue String vs. @lvalue Int`, let's pretend that it's okay.
2437+
if (!path.empty() && path.back().is<LocatorPathElt::ContextualType>()) {
2438+
auto *locator = getConstraintLocator(anchor, path.back());
2439+
conversionsOrFixes.push_back(
2440+
IgnoreContextualType::create(*this, lhs, rhs, locator));
2441+
break;
2442+
}
2443+
}
2444+
2445+
LLVM_FALLTHROUGH;
2446+
}
2447+
24052448
case ConstraintLocator::ApplyArgToParam: {
24062449
auto loc = getConstraintLocator(locator);
24072450
if (repairByInsertingExplicitCall(lhs, rhs))

test/stmt/yield.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ struct YieldVariables {
2525
}
2626
_modify {
2727
var x = 0
28-
yield &x // expected-error {{cannot yield immutable value of type 'Int' as an inout yield of type 'String'}}
28+
yield &x // expected-error {{cannot yield reference to storage of type 'Int' as an inout yield of type 'String'}}
2929
}
3030
}
3131

0 commit comments

Comments
 (0)