mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[Diagnostics] Diagnose an attempt to init/use dictionary with array literal in CSGen
It's much easier to detect that contextual type is a dictionary but expression is an array literal while generating constraints.
This commit is contained in:
@@ -1891,9 +1891,6 @@ bool ContextualFailure::diagnoseAsError() {
|
||||
if (diagnoseMissingFunctionCall())
|
||||
return true;
|
||||
|
||||
if (diagnoseConversionToDictionary())
|
||||
return true;
|
||||
|
||||
// Special case of some common conversions involving Swift.String
|
||||
// indexes, catching cases where people attempt to index them with an integer.
|
||||
if (isIntegerToStringIndexConversion()) {
|
||||
@@ -2403,61 +2400,6 @@ bool ContextualFailure::diagnoseConversionToBool() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ContextualFailure::isInvalidDictionaryConversion(
|
||||
ConstraintSystem &cs, Expr *anchor, Type contextualType) {
|
||||
auto *arrayExpr = dyn_cast<ArrayExpr>(anchor);
|
||||
if (!arrayExpr)
|
||||
return false;
|
||||
|
||||
auto type = contextualType->lookThroughAllOptionalTypes();
|
||||
if (!conformsToKnownProtocol(
|
||||
cs, type, KnownProtocolKind::ExpressibleByDictionaryLiteral))
|
||||
return false;
|
||||
|
||||
return (arrayExpr->getNumElements() & 1) == 0;
|
||||
}
|
||||
|
||||
bool ContextualFailure::diagnoseConversionToDictionary() const {
|
||||
auto &cs = getConstraintSystem();
|
||||
auto toType = getToType()->lookThroughAllOptionalTypes();
|
||||
|
||||
if (!isInvalidDictionaryConversion(cs, getAnchor(), toType))
|
||||
return false;
|
||||
|
||||
auto *arrayExpr = cast<ArrayExpr>(getAnchor());
|
||||
|
||||
// If the contextual type conforms to ExpressibleByDictionaryLiteral and
|
||||
// this is an empty array, then they meant "[:]".
|
||||
auto numElements = arrayExpr->getNumElements();
|
||||
if (numElements == 0) {
|
||||
emitDiagnostic(arrayExpr->getStartLoc(),
|
||||
diag::should_use_empty_dictionary_literal)
|
||||
.fixItInsert(arrayExpr->getEndLoc(), ":");
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the contextual type conforms to ExpressibleByDictionaryLiteral, then
|
||||
// they wrote "x = [1,2]" but probably meant "x = [1:2]".
|
||||
bool isIniting = getContextualTypePurpose() == CTP_Initialization;
|
||||
emitDiagnostic(arrayExpr->getStartLoc(), diag::should_use_dictionary_literal,
|
||||
toType, isIniting);
|
||||
|
||||
auto diagnostic =
|
||||
emitDiagnostic(arrayExpr->getStartLoc(), diag::meant_dictionary_lit);
|
||||
|
||||
// Change every other comma into a colon, only if the number
|
||||
// of commas present matches the number of elements, because
|
||||
// otherwise it might a structural problem with the expression
|
||||
// e.g. ["a""b": 1].
|
||||
const auto commaLocs = arrayExpr->getCommaLocs();
|
||||
if (commaLocs.size() == numElements - 1) {
|
||||
for (unsigned i = 0, e = numElements / 2; i != e; ++i)
|
||||
diagnostic.fixItReplace(commaLocs[i * 2], ":");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContextualFailure::diagnoseThrowsTypeMismatch() const {
|
||||
// If this is conversion failure due to a return statement with an argument
|
||||
// that cannot be coerced to the result type of the function, emit a
|
||||
@@ -4857,24 +4799,6 @@ bool CollectionElementContextualFailure::diagnoseAsError() {
|
||||
auto *anchor = getAnchor();
|
||||
auto *locator = getLocator();
|
||||
|
||||
// Check whether this is situation like `let _: [String: Int] = ["A", 0]`
|
||||
// which attempts to convert an array into a dictionary. We have a tailored
|
||||
// contextual diagnostic for that, so no need to diagnose element mismatches
|
||||
// as well.
|
||||
auto &cs = getConstraintSystem();
|
||||
auto *rawAnchor = getRawAnchor();
|
||||
if (llvm::any_of(cs.getFixes(), [&](const ConstraintFix *fix) -> bool {
|
||||
auto *locator = fix->getLocator();
|
||||
if (!(fix->getKind() == FixKind::ContextualMismatch &&
|
||||
locator->getAnchor() == rawAnchor))
|
||||
return false;
|
||||
|
||||
auto *mismatch = static_cast<const ContextualMismatch *>(fix);
|
||||
return isInvalidDictionaryConversion(cs, rawAnchor,
|
||||
mismatch->getToType());
|
||||
}))
|
||||
return false;
|
||||
|
||||
auto eltType = getFromType();
|
||||
auto contextualType = getToType();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user