Skip to content

Commit 9ddb5ed

Browse files
authored
Merge pull request #29065 from hborla/subscript-error-diag
[Diagnostics] Finish porting subscript errors
2 parents 1f1603c + 7e05667 commit 9ddb5ed

File tree

6 files changed

+41
-165
lines changed

6 files changed

+41
-165
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 0 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -234,8 +234,6 @@ class FailureDiagnosis :public ASTVisitor<FailureDiagnosis, /*exprresult*/bool>{
234234
Optional<std::function<bool(ArrayRef<OverloadChoice>)>> callback = None,
235235
bool includeInaccessibleMembers = true);
236236

237-
bool diagnoseSubscriptErrors(SubscriptExpr *SE, bool performingSet);
238-
239237
bool visitExpr(Expr *E);
240238
bool visitIdentityExpr(IdentityExpr *E);
241239
bool visitTryExpr(TryExpr *E);
@@ -245,7 +243,6 @@ class FailureDiagnosis :public ASTVisitor<FailureDiagnosis, /*exprresult*/bool>{
245243
bool visitDictionaryExpr(DictionaryExpr *E);
246244
bool visitObjectLiteralExpr(ObjectLiteralExpr *E);
247245

248-
bool visitSubscriptExpr(SubscriptExpr *SE);
249246
bool visitApplyExpr(ApplyExpr *AE);
250247
bool visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *E);
251248
};
@@ -1410,163 +1407,6 @@ bool FailureDiagnosis::diagnoseParameterErrors(CalleeCandidateInfo &CCI,
14101407
return false;
14111408
}
14121409

1413-
bool FailureDiagnosis::diagnoseSubscriptErrors(SubscriptExpr *SE,
1414-
bool inAssignmentDestination) {
1415-
auto baseExpr = typeCheckChildIndependently(SE->getBase());
1416-
if (!baseExpr) return true;
1417-
auto baseType = CS.getType(baseExpr);
1418-
1419-
if (isa<NilLiteralExpr>(baseExpr)) {
1420-
diagnose(baseExpr->getLoc(), diag::cannot_subscript_nil_literal)
1421-
.highlight(baseExpr->getSourceRange());
1422-
return true;
1423-
}
1424-
1425-
std::function<bool(ArrayRef<OverloadChoice>)> callback =
1426-
[&](ArrayRef<OverloadChoice> candidates) -> bool {
1427-
CalleeCandidateInfo calleeInfo(Type(), candidates, SE->hasTrailingClosure(),
1428-
CS, /*selfAlreadyApplied*/ false);
1429-
1430-
// We're about to typecheck the index list, which needs to be processed with
1431-
// self already applied.
1432-
for (unsigned i = 0, e = calleeInfo.size(); i != e; ++i)
1433-
calleeInfo.candidates[i].skipCurriedSelf = true;
1434-
1435-
auto indexExpr =
1436-
typeCheckArgumentChildIndependently(SE->getIndex(), Type(), calleeInfo);
1437-
if (!indexExpr)
1438-
return true;
1439-
1440-
// Back to analyzing the candidate list with self applied.
1441-
for (unsigned i = 0, e = calleeInfo.size(); i != e; ++i)
1442-
calleeInfo.candidates[i].skipCurriedSelf = false;
1443-
1444-
ArrayRef<Identifier> argLabels = SE->getArgumentLabels();
1445-
if (diagnoseParameterErrors(calleeInfo, SE, indexExpr, argLabels))
1446-
return true;
1447-
1448-
auto indexType = CS.getType(indexExpr);
1449-
1450-
auto decomposedBaseType = decomposeArgType(baseType, {Identifier()});
1451-
auto decomposedIndexType = decomposeArgType(indexType, argLabels);
1452-
calleeInfo.filterList(
1453-
[&](OverloadCandidate cand) -> CalleeCandidateInfo::ClosenessResultTy {
1454-
// Classify how close this match is. Non-subscript decls don't match.
1455-
auto subscriptDecl = dyn_cast_or_null<SubscriptDecl>(cand.getDecl());
1456-
if (!subscriptDecl ||
1457-
(inAssignmentDestination && !subscriptDecl->supportsMutation()))
1458-
return {CC_GeneralMismatch, {}};
1459-
1460-
// Check whether the self type matches.
1461-
auto selfConstraint = CC_ExactMatch;
1462-
if (calleeInfo.evaluateCloseness(cand, decomposedBaseType).first !=
1463-
CC_ExactMatch)
1464-
selfConstraint = CC_SelfMismatch;
1465-
1466-
// Set a flag to look past the self argument to the indices.
1467-
cand.skipCurriedSelf = true;
1468-
1469-
// Explode out multi-index subscripts to find the best match.
1470-
auto indexResult =
1471-
calleeInfo.evaluateCloseness(cand, decomposedIndexType);
1472-
if (selfConstraint > indexResult.first)
1473-
return {selfConstraint, {}};
1474-
return indexResult;
1475-
});
1476-
1477-
// If the closest matches all mismatch on self, we either have something
1478-
// that cannot be subscripted, or an ambiguity.
1479-
if (calleeInfo.closeness == CC_SelfMismatch) {
1480-
diagnose(SE->getLoc(), diag::cannot_subscript_base, baseType)
1481-
.highlight(SE->getBase()->getSourceRange());
1482-
// FIXME: Should suggest overload set, but we're not ready for that until
1483-
// it points to candidates and identifies the self type in the diagnostic.
1484-
// calleeInfo.suggestPotentialOverloads(SE->getLoc());
1485-
return true;
1486-
}
1487-
1488-
// Any other failures relate to the index list.
1489-
for (unsigned i = 0, e = calleeInfo.size(); i != e; ++i)
1490-
calleeInfo.candidates[i].skipCurriedSelf = true;
1491-
1492-
// TODO: Is there any reason to check for CC_NonLValueInOut here?
1493-
1494-
if (calleeInfo.closeness == CC_ExactMatch) {
1495-
auto message = diag::ambiguous_subscript;
1496-
1497-
// If there is an exact match on the argument with
1498-
// a single candidate, let's type-check subscript
1499-
// as a whole to figure out if there is any structural
1500-
// problem after all.
1501-
if (calleeInfo.size() == 1) {
1502-
Expr *expr = SE;
1503-
ConcreteDeclRef decl = nullptr;
1504-
message = diag::cannot_subscript_with_index;
1505-
1506-
if (TypeChecker::getTypeOfExpressionWithoutApplying(expr, CS.DC, decl))
1507-
return false;
1508-
1509-
// If we are down to a single candidate but with an unresolved
1510-
// index type, we can substitute in the base type to get a simpler
1511-
// and more concrete expected type for this subscript decl, in order
1512-
// to diagnose a better error.
1513-
if (baseType && indexType->hasUnresolvedType()) {
1514-
auto cand = calleeInfo.candidates[0];
1515-
auto candType = baseType->getTypeOfMember(CS.DC->getParentModule(),
1516-
cand.getDecl(), nullptr);
1517-
if (auto *candFunc = candType->getAs<FunctionType>()) {
1518-
auto paramsType = FunctionType::composeInput(CS.getASTContext(),
1519-
candFunc->getParams(),
1520-
false);
1521-
if (!typeCheckChildIndependently(
1522-
indexExpr, paramsType, CTP_CallArgument, TCC_ForceRecheck))
1523-
return true;
1524-
}
1525-
}
1526-
}
1527-
1528-
diagnose(SE->getLoc(), message, baseType, indexType)
1529-
.highlight(indexExpr->getSourceRange())
1530-
.highlight(baseExpr->getSourceRange());
1531-
1532-
// FIXME: suggestPotentialOverloads should do this.
1533-
// calleeInfo.suggestPotentialOverloads(SE->getLoc());
1534-
for (auto candidate : calleeInfo.candidates)
1535-
if (auto decl = candidate.getDecl())
1536-
diagnose(decl, diag::found_candidate);
1537-
else
1538-
diagnose(candidate.getExpr()->getLoc(), diag::found_candidate);
1539-
1540-
return true;
1541-
}
1542-
1543-
if (diagnoseParameterErrors(calleeInfo, SE, indexExpr, argLabels))
1544-
return true;
1545-
1546-
// Diagnose some simple and common errors.
1547-
if (calleeInfo.diagnoseSimpleErrors(SE))
1548-
return true;
1549-
1550-
diagnose(SE->getLoc(), diag::cannot_subscript_with_index, baseType,
1551-
indexType);
1552-
1553-
calleeInfo.suggestPotentialOverloads(SE->getLoc());
1554-
return true;
1555-
};
1556-
1557-
auto locator =
1558-
CS.getConstraintLocator(SE, ConstraintLocator::SubscriptMember);
1559-
1560-
return diagnoseMemberFailures(SE, baseExpr, ConstraintKind::ValueMember,
1561-
DeclNameRef::createSubscript(),
1562-
FunctionRefKind::DoubleApply, locator,
1563-
callback);
1564-
}
1565-
1566-
bool FailureDiagnosis::visitSubscriptExpr(SubscriptExpr *SE) {
1567-
return diagnoseSubscriptErrors(SE, /* inAssignmentDestination = */ false);
1568-
}
1569-
15701410
// Check if there is a structural problem in the function expression
15711411
// by performing type checking with the option to allow unresolved
15721412
// type variables. If that is going to produce a function type with

lib/Sema/CSDiagnostics.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3824,6 +3824,21 @@ bool MissingArgumentsFailure::diagnoseAsError() {
38243824
return true;
38253825
}
38263826

3827+
bool MissingArgumentsFailure::diagnoseAsNote() {
3828+
auto *locator = getLocator();
3829+
if (auto overload = getChoiceFor(locator)) {
3830+
auto *fn = resolveType(overload->openedType)->getAs<AnyFunctionType>();
3831+
auto loc = overload->choice.getDecl()->getLoc();
3832+
if (loc.isInvalid())
3833+
loc = getAnchor()->getLoc();
3834+
emitDiagnostic(loc, diag::candidate_partial_match,
3835+
fn->getParamListAsString(fn->getParams()));
3836+
return true;
3837+
}
3838+
3839+
return false;
3840+
}
3841+
38273842
bool MissingArgumentsFailure::diagnoseSingleMissingArgument() const {
38283843
auto &ctx = getASTContext();
38293844

lib/Sema/CSDiagnostics.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,6 +1210,8 @@ class MissingArgumentsFailure final : public FailureDiagnostic {
12101210

12111211
bool diagnoseAsError() override;
12121212

1213+
bool diagnoseAsNote() override;
1214+
12131215
bool diagnoseSingleMissingArgument() const;
12141216

12151217
private:

lib/Sema/CSGen.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -930,6 +930,16 @@ namespace {
930930
= { nullptr, nullptr };
931931
unsigned currentEditorPlaceholderVariable = 0;
932932

933+
/// Returns false and emits the specified diagnostic if the member reference
934+
/// base is a nil literal. Returns true otherwise.
935+
bool isValidBaseOfMemberRef(Expr *base, Diag<> diagnostic) {
936+
if (auto nilLiteral = dyn_cast<NilLiteralExpr>(base)) {
937+
CS.getASTContext().Diags.diagnose(nilLiteral->getLoc(), diagnostic);
938+
return false;
939+
}
940+
return true;
941+
}
942+
933943
/// Add constraints for a reference to a named member of the given
934944
/// base type, and return the type of such a reference.
935945
Type addMemberRefConstraints(Expr *expr, Expr *base, DeclNameRef name,
@@ -1792,7 +1802,11 @@ namespace {
17921802
return Type();
17931803
}
17941804

1795-
return addSubscriptConstraints(expr, CS.getType(expr->getBase()),
1805+
auto *base = expr->getBase();
1806+
if (!isValidBaseOfMemberRef(base, diag::cannot_subscript_nil_literal))
1807+
return nullptr;
1808+
1809+
return addSubscriptConstraints(expr, CS.getType(base),
17961810
expr->getIndex(),
17971811
decl, expr->getArgumentLabels(),
17981812
expr->hasTrailingClosure());

test/decl/subscript/subscripting.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -398,12 +398,13 @@ func testSubscript1(_ s1 : SubscriptTest1) {
398398
struct SubscriptTest2 {
399399
subscript(a : String, b : Int) -> Int { return 0 } // expected-note {{candidate expects value of type 'Int' for parameter #2}}
400400
// expected-note@-1 {{declared here}}
401+
// expected-note@-2 {{candidate has partially matching parameter list (String, Int)}}
401402
subscript(a : String, b : String) -> Int { return 0 } // expected-note {{candidate expects value of type 'String' for parameter #2}}
403+
// expected-note@-1 {{candidate has partially matching parameter list (String, String)}}
402404
}
403405

404406
func testSubscript1(_ s2 : SubscriptTest2) {
405-
_ = s2["foo"] // expected-error {{cannot subscript a value of type 'SubscriptTest2' with an argument of type 'String'}}
406-
// expected-note @-1 {{overloads for 'subscript' exist with these partially matching parameter lists: (String, Int), (String, String)}}
407+
_ = s2["foo"] // expected-error {{no exact matches in call to subscript}}
407408

408409
let a = s2["foo", 1.0] // expected-error {{no exact matches in call to subscript}}
409410

test/type/types.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,12 @@ var d3 : () -> Float = { 4 }
1919
var d4 : () -> Int = { d2 } // expected-error{{function produces expected type 'Int'; did you mean to call it with '()'?}} {{26-26=()}}
2020

2121
var e0 : [Int]
22-
e0[] // expected-error {{cannot subscript a value of type '[Int]' with an argument of type '()'}}
23-
// expected-note @-1 {{overloads for 'subscript' exist with these partially matching parameter lists: ((UnboundedRange_) -> ()), (Int), (R), (Range<Int>), (Range<Self.Index>)}}
22+
e0[] // expected-error {{no exact matches in call to subscript}}
23+
// expected-note@-1 {{candidate has partially matching parameter list (Int)}}
24+
// expected-note@-2 {{candidate has partially matching parameter list (Range<Int>)}}
25+
// expected-note@-3 {{candidate has partially matching parameter list ((UnboundedRange_) -> ())}}
26+
// expected-note@-4 {{candidate has partially matching parameter list (Range<Array<Int>.Index>)}}
27+
// expected-note@-5 {{candidate has partially matching parameter list ((UnboundedRange_) -> ())}}
2428

2529
var f0 : [Float]
2630
var f1 : [(Int,Int)]

0 commit comments

Comments
 (0)