[CS] Diagnose misuse of CheckedCastExpr with ~=

Using an unwrap operator with 'as' or the wrong keyword (i.e. `is`)
when already checking a cast via ~= results in error:
'pattern variable binding cannot appear in an expression'.
Add a diagnostic that provides more guidance and a fix-it
for the removal of ?/! or replacement of 'is' with 'as'.
This commit is contained in:
James Brown
2024-09-19 14:51:14 -04:00
parent 6b57a9f208
commit f0eef0f583
4 changed files with 73 additions and 3 deletions

View File

@@ -8699,10 +8699,47 @@ bool InvalidPatternInExprFailure::diagnoseAsError() {
E = parent;
}
}
emitDiagnostic(diag::pattern_in_expr, P->getDescriptiveKind());
if (!diagnoseInvalidCheckedCast()) {
emitDiagnostic(diag::pattern_in_expr, P->getDescriptiveKind());
}
return true;
}
bool InvalidPatternInExprFailure::diagnoseInvalidCheckedCast() const {
auto *E = findParentExpr(castToExpr(getAnchor()));
// Make sure we have a CheckedCastExpr and are in an argument of `~=`.
while (E && !isa<CheckedCastExpr>(E))
E = findParentExpr(E);
auto *castExpr = cast_or_null<CheckedCastExpr>(E);
if (!castExpr)
return false;
auto *parent = findParentExpr(castExpr);
while (parent && !isa<BinaryExpr>(parent))
parent = findParentExpr(parent);
auto *BE = cast_or_null<BinaryExpr>(parent);
if (!BE || !isPatternMatchingOperator(BE->getFn()))
return false;
// Emit the appropriate diagnostic based on the cast kind.
if (auto *forced = dyn_cast<ForcedCheckedCastExpr>(castExpr)) {
emitDiagnosticAt(castExpr->getLoc(),
diag::force_cast_in_type_casting_pattern)
.fixItRemove(forced->getExclaimLoc());
return true;
}
if (auto *conditional = dyn_cast<ConditionalCheckedCastExpr>(castExpr)) {
emitDiagnosticAt(castExpr->getLoc(),
diag::conditional_cast_in_type_casting_pattern)
.fixItRemove(conditional->getQuestionLoc());
return true;
}
if (auto *isExpr = dyn_cast<IsExpr>(castExpr)) {
emitDiagnosticAt(castExpr->getLoc(), diag::cannot_bind_value_with_is)
.fixItReplace(isExpr->getAsLoc(), "as");
return true;
}
return false;
}
bool MissingContextualTypeForNil::diagnoseAsError() {
auto *expr = castToExpr<NilLiteralExpr>(getAnchor());