mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[CodeCompletion][Sema] Add fix to treat empty or single-element array literals as dictionaries when used as such
In the single-element case, it is treated as the dictionary key.
func takesDict(_ x: [Int: String]) {}
takesDict([]) // diagnose with fixit to add missing ':'
takesDict([1]) // diagnose with fixit to add missing ': <#value#>'
takesDict([foo.<complete>]) // prioritise Int members in completion results -
// the user just hasn't written the value yet.
The above previously failed with a generic mismatch error in normal type
checking (due to the literal being parsed as an array literal) and code
completion could not pick up the expected type from the context.
This commit is contained in:
@@ -841,6 +841,27 @@ bool LabelingFailure::diagnoseAsNote() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ArrayLiteralToDictionaryConversionFailure::diagnoseAsError() {
|
||||
ArrayExpr *AE = getAsExpr<ArrayExpr>(getAnchor());
|
||||
assert(AE);
|
||||
|
||||
if (AE->getNumElements() == 0) {
|
||||
emitDiagnostic(diag::should_use_empty_dictionary_literal)
|
||||
.fixItInsertAfter(getLoc(), ":");
|
||||
return true;
|
||||
}
|
||||
|
||||
auto CTP = getConstraintSystem().getContextualTypePurpose(AE);
|
||||
emitDiagnostic(diag::should_use_dictionary_literal,
|
||||
getToType()->lookThroughAllOptionalTypes(),
|
||||
CTP == CTP_Initialization);
|
||||
|
||||
auto diagnostic = emitDiagnostic(diag::meant_dictionary_lit);
|
||||
if (AE->getNumElements() == 1)
|
||||
diagnostic.fixItInsertAfter(AE->getElement(0)->getEndLoc(), ": <#value#>");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NoEscapeFuncToTypeConversionFailure::diagnoseAsError() {
|
||||
if (diagnoseParameterUse())
|
||||
return true;
|
||||
@@ -5129,16 +5150,27 @@ bool CollectionElementContextualFailure::diagnoseAsError() {
|
||||
auto eltType = getFromType();
|
||||
auto contextualType = getToType();
|
||||
|
||||
Optional<InFlightDiagnostic> diagnostic;
|
||||
if (isExpr<ArrayExpr>(anchor)) {
|
||||
if (diagnoseMergedLiteralElements())
|
||||
return true;
|
||||
auto isFixedToDictionary = [&](ArrayExpr *anchor) {
|
||||
return llvm::any_of(getSolution().Fixes, [&](ConstraintFix *fix) {
|
||||
auto *fixAnchor = getAsExpr<ArrayExpr>(fix->getAnchor());
|
||||
return fixAnchor && fixAnchor == anchor &&
|
||||
fix->getKind() == FixKind::TreatArrayLiteralAsDictionary;
|
||||
});
|
||||
};
|
||||
|
||||
diagnostic.emplace(emitDiagnostic(diag::cannot_convert_array_element,
|
||||
eltType, contextualType));
|
||||
bool treatAsDictionary = false;
|
||||
Optional<InFlightDiagnostic> diagnostic;
|
||||
if (auto *AE = getAsExpr<ArrayExpr>(anchor)) {
|
||||
if (!(treatAsDictionary = isFixedToDictionary(AE))) {
|
||||
if (diagnoseMergedLiteralElements())
|
||||
return true;
|
||||
|
||||
diagnostic.emplace(emitDiagnostic(diag::cannot_convert_array_element,
|
||||
eltType, contextualType));
|
||||
}
|
||||
}
|
||||
|
||||
if (isExpr<DictionaryExpr>(anchor)) {
|
||||
if (treatAsDictionary || isExpr<DictionaryExpr>(anchor)) {
|
||||
auto eltLoc = locator->castLastElementTo<LocatorPathElt::TupleElement>();
|
||||
switch (eltLoc.getIndex()) {
|
||||
case 0: // key
|
||||
|
||||
Reference in New Issue
Block a user