Skip to content

Commit b0ae4d7

Browse files
authored
Merge pull request #24988 from xedin/assignment-diagnostic-improvements-5.1
[5.1][Diagnostics] Assignment diagnostic improvements
2 parents e481a98 + 5ca9a20 commit b0ae4d7

28 files changed

+414
-146
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,13 @@ ERROR(cannot_convert_assign_protocol,none,
451451
ERROR(cannot_convert_assign_nil,none,
452452
"'nil' cannot be assigned to type %0", (Type))
453453

454+
// for ... in expression
455+
ERROR(cannot_convert_sequence_element_value,none,
456+
"cannot convert sequence element type %0 to expected type %1",
457+
(Type, Type))
458+
ERROR(cannot_convert_sequence_element_protocol,none,
459+
"sequence element type %0 does not conform to expected protocol %1",
460+
(Type, Type))
454461

455462
ERROR(throws_functiontype_mismatch,none,
456463
"invalid conversion from throwing function of type %0 to "

lib/Sema/CSDiag.cpp

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2128,7 +2128,6 @@ bool FailureDiagnosis::diagnoseContextualConversionError(
21282128
// system had a contextual type specified, we use it - it will have a purpose
21292129
// indicator which allows us to give a very "to the point" diagnostic.
21302130
Diag<Type, Type> diagID;
2131-
Diag<Type, Type> diagIDProtocol;
21322131
Diag<Type> nilDiag;
21332132
std::function<void(void)> nilFollowup;
21342133

@@ -2145,7 +2144,6 @@ bool FailureDiagnosis::diagnoseContextualConversionError(
21452144
"contextual type");
21462145
case CTP_Initialization:
21472146
diagID = diag::cannot_convert_initializer_value;
2148-
diagIDProtocol = diag::cannot_convert_initializer_value_protocol;
21492147
nilDiag = diag::cannot_convert_initializer_value_nil;
21502148
nilFollowup = [this] {
21512149
TypeRepr *patternTR = CS.getContextualTypeLoc().getTypeRepr();
@@ -2171,7 +2169,6 @@ bool FailureDiagnosis::diagnoseContextualConversionError(
21712169
}
21722170

21732171
diagID = diag::cannot_convert_to_return_type;
2174-
diagIDProtocol = diag::cannot_convert_to_return_type_protocol;
21752172
nilDiag = diag::cannot_convert_to_return_type_nil;
21762173
break;
21772174
case CTP_ThrowStmt: {
@@ -2219,12 +2216,10 @@ bool FailureDiagnosis::diagnoseContextualConversionError(
22192216

22202217
case CTP_EnumCaseRawValue:
22212218
diagID = diag::cannot_convert_raw_initializer_value;
2222-
diagIDProtocol = diag::cannot_convert_raw_initializer_value;
22232219
nilDiag = diag::cannot_convert_raw_initializer_value_nil;
22242220
break;
22252221
case CTP_DefaultParameter:
22262222
diagID = diag::cannot_convert_default_arg_value;
2227-
diagIDProtocol = diag::cannot_convert_default_arg_value_protocol;
22282223
nilDiag = diag::cannot_convert_default_arg_value_nil;
22292224
break;
22302225

@@ -2244,42 +2239,34 @@ bool FailureDiagnosis::diagnoseContextualConversionError(
22442239
return true;
22452240
case CTP_YieldByValue:
22462241
diagID = diag::cannot_convert_yield_value;
2247-
diagIDProtocol = diag::cannot_convert_yield_value_protocol;
22482242
nilDiag = diag::cannot_convert_yield_value_nil;
22492243
break;
22502244
case CTP_CallArgument:
22512245
diagID = diag::cannot_convert_argument_value;
2252-
diagIDProtocol = diag::cannot_convert_argument_value_protocol;
22532246
nilDiag = diag::cannot_convert_argument_value_nil;
22542247
break;
22552248
case CTP_ClosureResult:
22562249
diagID = diag::cannot_convert_closure_result;
2257-
diagIDProtocol = diag::cannot_convert_closure_result_protocol;
22582250
nilDiag = diag::cannot_convert_closure_result_nil;
22592251
break;
22602252
case CTP_ArrayElement:
22612253
diagID = diag::cannot_convert_array_element;
2262-
diagIDProtocol = diag::cannot_convert_array_element_protocol;
22632254
nilDiag = diag::cannot_convert_array_element_nil;
22642255
break;
22652256
case CTP_DictionaryKey:
22662257
diagID = diag::cannot_convert_dict_key;
2267-
diagIDProtocol = diag::cannot_convert_dict_key_protocol;
22682258
nilDiag = diag::cannot_convert_dict_key_nil;
22692259
break;
22702260
case CTP_DictionaryValue:
22712261
diagID = diag::cannot_convert_dict_value;
2272-
diagIDProtocol = diag::cannot_convert_dict_value_protocol;
22732262
nilDiag = diag::cannot_convert_dict_value_nil;
22742263
break;
22752264
case CTP_CoerceOperand:
22762265
diagID = diag::cannot_convert_coerce;
2277-
diagIDProtocol = diag::cannot_convert_coerce_protocol;
22782266
nilDiag = diag::cannot_convert_coerce_nil;
22792267
break;
22802268
case CTP_AssignSource:
22812269
diagID = diag::cannot_convert_assign;
2282-
diagIDProtocol = diag::cannot_convert_assign_protocol;
22832270
nilDiag = diag::cannot_convert_assign_nil;
22842271
break;
22852272
}
@@ -2391,10 +2378,13 @@ bool FailureDiagnosis::diagnoseContextualConversionError(
23912378

23922379
// When complaining about conversion to a protocol type, complain about
23932380
// conformance instead of "conversion".
2394-
if (contextualType->is<ProtocolType>() ||
2395-
contextualType->is<ProtocolCompositionType>())
2396-
diagID = diagIDProtocol;
2397-
2381+
if (contextualType->isExistentialType()) {
2382+
MissingContextualConformanceFailure failure(
2383+
expr, CS, CTP, exprType, contextualType,
2384+
CS.getConstraintLocator(expr, ConstraintLocator::ContextualType));
2385+
return failure.diagnoseAsError();
2386+
}
2387+
23982388
// Try to simplify irrelevant details of function types. For example, if
23992389
// someone passes a "() -> Float" function to a "() throws -> Int"
24002390
// parameter, then uttering the "throws" may confuse them into thinking that

lib/Sema/CSDiagnostics.cpp

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2763,3 +2763,140 @@ bool ExtraneousReturnFailure::diagnoseAsError() {
27632763
emitDiagnostic(anchor->getLoc(), diag::cannot_return_value_from_void_func);
27642764
return true;
27652765
}
2766+
2767+
bool CollectionElementContextualFailure::diagnoseAsError() {
2768+
auto *anchor = getAnchor();
2769+
auto *locator = getLocator();
2770+
2771+
auto eltType = getFromType();
2772+
auto contextualType = getToType();
2773+
2774+
Optional<InFlightDiagnostic> diagnostic;
2775+
if (isa<ArrayExpr>(getRawAnchor())) {
2776+
diagnostic.emplace(emitDiagnostic(anchor->getLoc(),
2777+
diag::cannot_convert_array_element,
2778+
eltType, contextualType));
2779+
}
2780+
2781+
if (isa<DictionaryExpr>(getRawAnchor())) {
2782+
const auto &eltLoc = locator->getPath().back();
2783+
2784+
switch (eltLoc.getValue()) {
2785+
case 0: // key
2786+
diagnostic.emplace(emitDiagnostic(anchor->getLoc(),
2787+
diag::cannot_convert_dict_key, eltType,
2788+
contextualType));
2789+
break;
2790+
2791+
case 1: // value
2792+
diagnostic.emplace(emitDiagnostic(anchor->getLoc(),
2793+
diag::cannot_convert_dict_value,
2794+
eltType, contextualType));
2795+
break;
2796+
2797+
default:
2798+
break;
2799+
}
2800+
}
2801+
2802+
if (locator->isForSequenceElementType()) {
2803+
diagnostic.emplace(
2804+
emitDiagnostic(anchor->getLoc(),
2805+
contextualType->isExistentialType()
2806+
? diag::cannot_convert_sequence_element_protocol
2807+
: diag::cannot_convert_sequence_element_value,
2808+
eltType, contextualType));
2809+
}
2810+
2811+
if (!diagnostic)
2812+
return false;
2813+
2814+
(void)trySequenceSubsequenceFixIts(*diagnostic, getConstraintSystem(),
2815+
eltType, contextualType, anchor);
2816+
return true;
2817+
}
2818+
2819+
bool MissingContextualConformanceFailure::diagnoseAsError() {
2820+
auto *anchor = getAnchor();
2821+
auto path = getLocator()->getPath();
2822+
2823+
Optional<Diag<Type, Type>> diagnostic;
2824+
if (path.empty()) {
2825+
assert(isa<AssignExpr>(anchor));
2826+
diagnostic = getDiagnosticFor(CTP_AssignSource);
2827+
} else {
2828+
const auto &last = path.back();
2829+
switch (last.getKind()) {
2830+
case ConstraintLocator::ContextualType:
2831+
assert(Context != CTP_Unused);
2832+
diagnostic = getDiagnosticFor(Context);
2833+
break;
2834+
2835+
case ConstraintLocator::SequenceElementType: {
2836+
diagnostic = diag::cannot_convert_sequence_element_protocol;
2837+
break;
2838+
}
2839+
2840+
default:
2841+
break;
2842+
}
2843+
}
2844+
2845+
if (!diagnostic)
2846+
return false;
2847+
2848+
auto srcType = getFromType();
2849+
auto dstType = getToType();
2850+
2851+
emitDiagnostic(anchor->getLoc(), *diagnostic, srcType, dstType);
2852+
2853+
if (isa<InOutExpr>(anchor))
2854+
return true;
2855+
2856+
if (srcType->isAny() && dstType->isAnyObject()) {
2857+
emitDiagnostic(anchor->getLoc(), diag::any_as_anyobject_fixit)
2858+
.fixItInsertAfter(anchor->getEndLoc(), " as AnyObject");
2859+
}
2860+
2861+
return true;
2862+
}
2863+
2864+
Optional<Diag<Type, Type>>
2865+
MissingContextualConformanceFailure::getDiagnosticFor(
2866+
ContextualTypePurpose context) {
2867+
switch (context) {
2868+
case CTP_Initialization:
2869+
return diag::cannot_convert_initializer_value_protocol;
2870+
case CTP_ReturnStmt:
2871+
case CTP_ReturnSingleExpr:
2872+
return diag::cannot_convert_to_return_type_protocol;
2873+
case CTP_EnumCaseRawValue:
2874+
return diag::cannot_convert_raw_initializer_value;
2875+
case CTP_DefaultParameter:
2876+
return diag::cannot_convert_default_arg_value_protocol;
2877+
case CTP_YieldByValue:
2878+
return diag::cannot_convert_yield_value_protocol;
2879+
case CTP_CallArgument:
2880+
return diag::cannot_convert_argument_value_protocol;
2881+
case CTP_ClosureResult:
2882+
return diag::cannot_convert_closure_result_protocol;
2883+
case CTP_ArrayElement:
2884+
return diag::cannot_convert_array_element_protocol;
2885+
case CTP_DictionaryKey:
2886+
return diag::cannot_convert_dict_key_protocol;
2887+
case CTP_DictionaryValue:
2888+
return diag::cannot_convert_dict_value_protocol;
2889+
case CTP_CoerceOperand:
2890+
return diag::cannot_convert_coerce_protocol;
2891+
case CTP_AssignSource:
2892+
return diag::cannot_convert_assign_protocol;
2893+
2894+
case CTP_ThrowStmt:
2895+
case CTP_Unused:
2896+
case CTP_CannotFail:
2897+
case CTP_YieldByReference:
2898+
case CTP_CalleeResult:
2899+
break;
2900+
}
2901+
return None;
2902+
}

lib/Sema/CSDiagnostics.h

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -324,14 +324,15 @@ class RequirementFailure : public FailureDiagnostic {
324324
/// ```
325325
class MissingConformanceFailure final : public RequirementFailure {
326326
Type NonConformingType;
327-
ProtocolDecl *Protocol;
327+
Type ProtocolType;
328328

329329
public:
330330
MissingConformanceFailure(Expr *expr, ConstraintSystem &cs,
331331
ConstraintLocator *locator,
332-
std::pair<Type, ProtocolDecl *> conformance)
332+
std::pair<Type, Type> conformance)
333333
: RequirementFailure(cs, expr, RequirementKind::Conformance, locator),
334-
NonConformingType(conformance.first), Protocol(conformance.second) {}
334+
NonConformingType(conformance.first), ProtocolType(conformance.second) {
335+
}
335336

336337
bool diagnoseAsError() override;
337338

@@ -341,7 +342,7 @@ class MissingConformanceFailure final : public RequirementFailure {
341342
Type getLHS() const override { return NonConformingType; }
342343

343344
/// The protocol generic requirement expected associated type to conform to.
344-
Type getRHS() const override { return Protocol->getDeclaredType(); }
345+
Type getRHS() const override { return ProtocolType; }
345346

346347
protected:
347348
DiagOnDecl getDiagnosticOnDecl() const override {
@@ -667,7 +668,7 @@ class AssignmentFailure final : public FailureDiagnostic {
667668

668669
/// Intended to diagnose any possible contextual failure
669670
/// e.g. argument/parameter, closure result, conversions etc.
670-
class ContextualFailure final : public FailureDiagnostic {
671+
class ContextualFailure : public FailureDiagnostic {
671672
Type FromType, ToType;
672673

673674
public:
@@ -676,6 +677,10 @@ class ContextualFailure final : public FailureDiagnostic {
676677
: FailureDiagnostic(root, cs, locator), FromType(resolve(lhs)),
677678
ToType(resolve(rhs)) {}
678679

680+
Type getFromType() const { return resolveType(FromType); }
681+
682+
Type getToType() const { return resolveType(ToType); }
683+
679684
bool diagnoseAsError() override;
680685

681686
// If we're trying to convert something of type "() -> T" to T,
@@ -1180,6 +1185,44 @@ class ExtraneousReturnFailure final : public FailureDiagnostic {
11801185
bool diagnoseAsError() override;
11811186
};
11821187

1188+
/// Diagnose a contextual mismatch between expected collection element type
1189+
/// and the one provided (e.g. source of the assignment or argument to a call)
1190+
/// e.g.:
1191+
///
1192+
/// ```swift
1193+
/// let _: [Int] = ["hello"]
1194+
/// ```
1195+
class CollectionElementContextualFailure final : public ContextualFailure {
1196+
public:
1197+
CollectionElementContextualFailure(Expr *root, ConstraintSystem &cs,
1198+
Type eltType, Type contextualType,
1199+
ConstraintLocator *locator)
1200+
: ContextualFailure(root, cs, eltType, contextualType, locator) {}
1201+
1202+
bool diagnoseAsError() override;
1203+
};
1204+
1205+
class MissingContextualConformanceFailure final : public ContextualFailure {
1206+
ContextualTypePurpose Context;
1207+
1208+
public:
1209+
MissingContextualConformanceFailure(Expr *root, ConstraintSystem &cs,
1210+
ContextualTypePurpose context, Type type,
1211+
Type protocolType,
1212+
ConstraintLocator *locator)
1213+
: ContextualFailure(root, cs, type, protocolType, locator),
1214+
Context(context) {
1215+
assert(protocolType->is<ProtocolType>() ||
1216+
protocolType->is<ProtocolCompositionType>());
1217+
}
1218+
1219+
bool diagnoseAsError() override;
1220+
1221+
private:
1222+
static Optional<Diag<Type, Type>>
1223+
getDiagnosticFor(ContextualTypePurpose purpose);
1224+
};
1225+
11831226
} // end namespace constraints
11841227
} // end namespace swift
11851228

0 commit comments

Comments
 (0)