Skip to content

Commit d01fed2

Browse files
[Sema] Implement tailored diagnostics for MissingMemberFailure with subscripts on tuple base types
1 parent 8fc778e commit d01fed2

File tree

3 files changed

+55
-0
lines changed

3 files changed

+55
-0
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,14 @@ ERROR(could_not_find_subscript_member_did_you_mean,none,
8888
"did you mean to use the subscript operator?",
8989
(Type))
9090

91+
ERROR(could_not_find_subscript_member_tuple, none,
92+
"tuple type %0 element cannot be accessed using subscript",
93+
(Type))
94+
ERROR(could_not_find_subscript_member_tuple_did_you_mean_use_dot, none,
95+
"tuple type %0 element cannot be accessed using subscript; "
96+
"did you mean to use '.' to access element?",
97+
(Type))
98+
9199
ERROR(could_not_find_enum_case,none,
92100
"enum type %0 has no case %1; did you mean %2?",
93101
(Type, DeclNameRef, DeclName))

lib/Sema/CSDiagnostics.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3212,6 +3212,9 @@ bool MissingMemberFailure::diagnoseAsError() {
32123212
if (diagnoseInLiteralCollectionContext())
32133213
return true;
32143214

3215+
if (diagnoseForSubscriptMemberWithTupleBase())
3216+
return true;
3217+
32153218
auto baseType = resolveType(getBaseType())->getWithoutSpecifierType();
32163219

32173220
DeclNameLoc nameLoc(::getLoc(anchor));
@@ -3428,6 +3431,42 @@ bool MissingMemberFailure::diagnoseInLiteralCollectionContext() const {
34283431
return false;
34293432
}
34303433

3434+
bool MissingMemberFailure::diagnoseForSubscriptMemberWithTupleBase() const {
3435+
auto locator = getLocator();
3436+
auto baseType = resolveType(getBaseType())->getWithoutSpecifierType();
3437+
3438+
if (!locator->isLastElement<LocatorPathElt::SubscriptMember>())
3439+
return false;
3440+
3441+
auto tupleType = baseType->getAs<TupleType>();
3442+
// For non-tuple type or empty tuples, let's fallback to the general
3443+
// diagnostic logic.
3444+
if (!tupleType || tupleType->getNumElements() == 0)
3445+
return false;
3446+
3447+
auto *SE = castToExpr<SubscriptExpr>(locator->getAnchor());
3448+
auto *index = SE->getIndex();
3449+
3450+
if (SE->getNumArguments() == 1) {
3451+
auto *literal =
3452+
dyn_cast<IntegerLiteralExpr>(index->getSemanticsProvidingExpr());
3453+
if (literal && !literal->isNegative()) {
3454+
llvm::SmallString<4> dotAccess;
3455+
llvm::raw_svector_ostream OS(dotAccess);
3456+
OS << "." << literal->getDigitsText();
3457+
3458+
emitDiagnostic(
3459+
diag::could_not_find_subscript_member_tuple_did_you_mean_use_dot,
3460+
baseType)
3461+
.fixItReplace(index->getSourceRange(), OS.str());
3462+
return true;
3463+
}
3464+
}
3465+
3466+
emitDiagnostic(diag::could_not_find_subscript_member_tuple, baseType);
3467+
return true;
3468+
}
3469+
34313470
bool UnintendedExtraGenericParamMemberFailure::diagnoseAsError() {
34323471
MissingMemberFailure::diagnoseAsError();
34333472

lib/Sema/CSDiagnostics.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,6 +1075,14 @@ class MissingMemberFailure : public InvalidMemberRefFailure {
10751075
/// that defaults the element type. e.g. _ = [.e]
10761076
bool diagnoseInLiteralCollectionContext() const;
10771077

1078+
/// Tailored diagnostics for missing subscript member on a tuple base type.
1079+
/// e.g
1080+
/// ```swift
1081+
/// let tuple: (Int, Int) = (0, 0)
1082+
/// _ = tuple[0]
1083+
/// ```
1084+
bool diagnoseForSubscriptMemberWithTupleBase() const;
1085+
10781086
static DeclName findCorrectEnumCaseName(Type Ty,
10791087
TypoCorrectionResults &corrections,
10801088
DeclNameRef memberName);

0 commit comments

Comments
 (0)