Skip to content

Commit 228bee7

Browse files
committed
Rearrange how CalleeCandidateInfo processes candidates in its list, to
make sure that properties and subscripts have a self type in their tracked type. This makes SubscriptExpr processing more logical (given that it applies both self and an index list), by putting hacks in more principled places. It would be great to someday eliminate SubscriptExpr entirely, but this isn't going to happen in the short term. NFC.
1 parent 46e3590 commit 228bee7

File tree

1 file changed

+61
-41
lines changed

1 file changed

+61
-41
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 61 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,14 @@ namespace {
717717

718718
UncurriedCandidate(ValueDecl *decl, unsigned level)
719719
: declOrExpr(decl), level(level), entityType(decl->getType()) {
720+
// For some reason, subscripts and properties don't include their self
721+
// type. Tack it on for consistency with other members.
722+
if (isa<AbstractStorageDecl>(decl)) {
723+
if (decl->getDeclContext()->isTypeContext()) {
724+
auto instanceTy = decl->getDeclContext()->getSelfTypeInContext();
725+
entityType = FunctionType::get(instanceTy, entityType);
726+
}
727+
}
720728
}
721729
UncurriedCandidate(Expr *expr)
722730
: declOrExpr(expr), level(0), entityType(expr->getType()) {
@@ -843,7 +851,8 @@ namespace {
843851
}
844852

845853
CalleeCandidateInfo(Type baseType, ArrayRef<OverloadChoice> candidates,
846-
bool hasTrailingClosure, ConstraintSystem *CS);
854+
bool hasTrailingClosure, ConstraintSystem *CS,
855+
bool selfAlreadyApplied = true);
847856

848857
typedef std::pair<CandidateCloseness, FailedArgumentInfo> ClosenessResultTy;
849858
typedef const std::function<ClosenessResultTy(UncurriedCandidate)>
@@ -852,8 +861,9 @@ namespace {
852861
/// After the candidate list is formed, it can be filtered down to discard
853862
/// obviously mismatching candidates and compute a "closeness" for the
854863
/// resultant set.
855-
std::pair<CandidateCloseness, CalleeCandidateInfo::FailedArgumentInfo>
856-
evaluateCloseness(DeclContext *dc, Type candArgListType, ArrayRef<CallArgParam> actualArgs);
864+
ClosenessResultTy
865+
evaluateCloseness(DeclContext *dc, Type candArgListType,
866+
ArrayRef<CallArgParam> actualArgs);
857867

858868
void filterList(ArrayRef<CallArgParam> actualArgs);
859869
void filterList(Type actualArgsType) {
@@ -1063,9 +1073,9 @@ static bool findGenericSubstitutions(DeclContext *dc, Type paramType,
10631073
/// Determine how close an argument list is to an already decomposed argument
10641074
/// list. If the closeness is a miss by a single argument, then this returns
10651075
/// information about that failure.
1066-
std::pair<CandidateCloseness, CalleeCandidateInfo::FailedArgumentInfo>
1076+
CalleeCandidateInfo::ClosenessResultTy
10671077
CalleeCandidateInfo::evaluateCloseness(DeclContext *dc, Type candArgListType,
1068-
ArrayRef<CallArgParam> actualArgs) {
1078+
ArrayRef<CallArgParam> actualArgs) {
10691079
auto candArgs = decomposeArgParamType(candArgListType);
10701080

10711081
struct OurListener : public MatchCallArgumentListener {
@@ -1156,7 +1166,7 @@ CalleeCandidateInfo::evaluateCloseness(DeclContext *dc, Type candArgListType,
11561166
// against the type contained therein.
11571167
if (paramType->is<InOutType>() && argType->is<LValueType>())
11581168
matchType = matchType->getInOutObjectType();
1159-
matched = findGenericSubstitutions(dc, matchType , rArgType,
1169+
matched = findGenericSubstitutions(dc, matchType, rArgType,
11601170
archetypesMap);
11611171
}
11621172

@@ -1513,12 +1523,13 @@ void CalleeCandidateInfo::filterContextualMemberList(Expr *argExpr) {
15131523
CalleeCandidateInfo::CalleeCandidateInfo(Type baseType,
15141524
ArrayRef<OverloadChoice> overloads,
15151525
bool hasTrailingClosure,
1516-
ConstraintSystem *CS)
1526+
ConstraintSystem *CS,
1527+
bool selfAlreadyApplied)
15171528
: CS(CS), hasTrailingClosure(hasTrailingClosure) {
15181529

15191530
// If we have a useful base type for the candidate set, we'll want to
15201531
// substitute it into each member. If not, ignore it.
1521-
if (isUnresolvedOrTypeVarType(baseType))
1532+
if (baseType && isUnresolvedOrTypeVarType(baseType))
15221533
baseType = Type();
15231534

15241535
for (auto cand : overloads) {
@@ -1527,10 +1538,10 @@ CalleeCandidateInfo::CalleeCandidateInfo(Type baseType,
15271538
auto decl = cand.getDecl();
15281539

15291540
// If this is a method or enum case member (not a var or subscript), then
1530-
// the uncurry level is 1.
1541+
// the uncurry level is 1 if self has already been applied.
15311542
unsigned uncurryLevel = 0;
1532-
if (!isa<AbstractStorageDecl>(decl) &&
1533-
decl->getDeclContext()->isTypeContext())
1543+
if (decl->getDeclContext()->isTypeContext() &&
1544+
selfAlreadyApplied)
15341545
uncurryLevel = 1;
15351546

15361547
candidates.push_back({ decl, uncurryLevel });
@@ -1561,7 +1572,7 @@ CalleeCandidateInfo::CalleeCandidateInfo(Type baseType,
15611572
substType = Type();
15621573
}
15631574

1564-
if (substType)
1575+
if (substType && selfAlreadyApplied)
15651576
substType = substType->getTypeOfMember(CS->DC->getParentModule(),
15661577
decl, nullptr);
15671578
if (substType)
@@ -3913,8 +3924,6 @@ bool FailureDiagnosis::diagnoseParameterErrors(CalleeCandidateInfo &CCI,
39133924

39143925

39153926
bool FailureDiagnosis::visitSubscriptExpr(SubscriptExpr *SE) {
3916-
// FIXME: Why isn't this passing TCC_AllowLValue? It seems that this could
3917-
// cause problems with subscripts that have mutating getters.
39183927
auto baseExpr = typeCheckChildIndependently(SE->getBase());
39193928
if (!baseExpr) return true;
39203929
auto baseType = baseExpr->getType();
@@ -3951,19 +3960,30 @@ bool FailureDiagnosis::visitSubscriptExpr(SubscriptExpr *SE) {
39513960

39523961

39533962

3954-
CalleeCandidateInfo calleeInfo(baseType, result.ViableCandidates,
3963+
CalleeCandidateInfo calleeInfo(Type(), result.ViableCandidates,
39553964
/*FIXME: Subscript trailing closures*/
3956-
/*hasTrailingClosure*/false, CS);
3965+
/*hasTrailingClosure*/false, CS,
3966+
/*selfAlreadyApplied*/false);
39573967

3968+
// We're about to typecheck the index list, which needs to be processed with
3969+
// self already applied.
3970+
for (unsigned i = 0, e = calleeInfo.size(); i != e; ++i)
3971+
++calleeInfo.candidates[i].level;
3972+
39583973
auto indexExpr = typeCheckArgumentChildIndependently(SE->getIndex(),
39593974
Type(), calleeInfo);
39603975
if (!indexExpr) return true;
39613976

3977+
// Back to analyzing the candidate list with self applied.
3978+
for (unsigned i = 0, e = calleeInfo.size(); i != e; ++i)
3979+
--calleeInfo.candidates[i].level;
3980+
39623981
if (diagnoseParameterErrors(calleeInfo, SE, indexExpr))
39633982
return true;
39643983

39653984
auto indexType = indexExpr->getType();
39663985

3986+
auto decomposedBaseType = decomposeArgParamType(baseType);
39673987
auto decomposedIndexType = decomposeArgParamType(indexType);
39683988
calleeInfo.filterList([&](UncurriedCandidate cand) ->
39693989
CalleeCandidateInfo::ClosenessResultTy
@@ -3972,31 +3992,40 @@ bool FailureDiagnosis::visitSubscriptExpr(SubscriptExpr *SE) {
39723992
auto *SD = dyn_cast_or_null<SubscriptDecl>(cand.getDecl());
39733993
if (!SD) return { CC_GeneralMismatch, {}};
39743994

3975-
// Check to make sure the base expr type is convertible to the expected base
3976-
// type. We check either the getter, or if it isn't present, the addressor.
3995+
// Check whether the self type matches.
39773996
auto selfConstraint = CC_ExactMatch;
3978-
auto getter = SD->getGetter();
3979-
if (!getter) getter = SD->getAddressor();
3980-
3981-
auto instanceTy =
3982-
getter->getImplicitSelfDecl()->getType()->getInOutObjectType();
3983-
if (!isUnresolvedOrTypeVarType(baseType) &&
3984-
// TODO: We're not handling archetypes well here.
3985-
!instanceTy->hasArchetype() &&
3986-
!CS->TC.isConvertibleTo(baseType, instanceTy, CS->DC)) {
3997+
if (calleeInfo.evaluateCloseness(SD->getInnermostDeclContext(),
3998+
cand.getArgumentType(), decomposedBaseType)
3999+
.first != CC_ExactMatch)
39874000
selfConstraint = CC_SelfMismatch;
3988-
}
4001+
4002+
// Increase the uncurry level to look past the self argument to the indices.
4003+
cand.level++;
39894004

39904005
// Explode out multi-index subscripts to find the best match.
3991-
Decl *decl = cand.getDecl();
39924006
auto indexResult =
3993-
calleeInfo.evaluateCloseness(decl ? decl->getInnermostDeclContext() : nullptr,
4007+
calleeInfo.evaluateCloseness(SD->getInnermostDeclContext(),
39944008
cand.getArgumentType(), decomposedIndexType);
39954009
if (selfConstraint > indexResult.first)
39964010
return {selfConstraint, {}};
39974011
return indexResult;
39984012
});
39994013

4014+
// If the closest matches all mismatch on self, we either have something that
4015+
// cannot be subscripted, or an ambiguity.
4016+
if (calleeInfo.closeness == CC_SelfMismatch) {
4017+
diagnose(SE->getLoc(), diag::cannot_subscript_base, baseType)
4018+
.highlight(SE->getBase()->getSourceRange());
4019+
// FIXME: Should suggest overload set, but we're not ready for that until
4020+
// it points to candidates and identifies the self type in the diagnostic.
4021+
//calleeInfo.suggestPotentialOverloads(SE->getLoc());
4022+
return true;
4023+
}
4024+
4025+
// Any other failures relate to the index list.
4026+
for (unsigned i = 0, e = calleeInfo.size(); i != e; ++i)
4027+
++calleeInfo.candidates[i].level;
4028+
40004029
// TODO: Is there any reason to check for CC_NonLValueInOut here?
40014030

40024031
if (calleeInfo.closeness == CC_ExactMatch) {
@@ -4028,16 +4057,6 @@ bool FailureDiagnosis::visitSubscriptExpr(SubscriptExpr *SE) {
40284057
if (calleeInfo.diagnoseSimpleErrors(SE->getLoc()))
40294058
return true;
40304059

4031-
// If the closest matches all mismatch on self, we either have something that
4032-
// cannot be subscripted, or an ambiguity.
4033-
if (calleeInfo.closeness == CC_SelfMismatch) {
4034-
diagnose(SE->getLoc(), diag::cannot_subscript_base, baseType)
4035-
.highlight(SE->getBase()->getSourceRange());
4036-
// FIXME: Should suggest overload set, but we're not ready for that until
4037-
// it points to candidates and identifies the self type in the diagnostic.
4038-
//calleeInfo.suggestPotentialOverloads(SE->getLoc());
4039-
return true;
4040-
}
40414060

40424061
diagnose(SE->getLoc(), diag::cannot_subscript_with_index,
40434062
baseType, indexType);
@@ -5067,7 +5086,7 @@ bool FailureDiagnosis::visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
50675086
bool hasTrailingClosure = callArgHasTrailingClosure(E->getArgument());
50685087

50695088
// Dump all of our viable candidates into a CalleeCandidateInfo & sort it out.
5070-
CalleeCandidateInfo candidateInfo(baseObjTy, result.ViableCandidates,
5089+
CalleeCandidateInfo candidateInfo(Type(), result.ViableCandidates,
50715090
hasTrailingClosure, CS);
50725091

50735092
// Filter the candidate list based on the argument we may or may not have.
@@ -5189,6 +5208,7 @@ bool FailureDiagnosis::visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
51895208
llvm_unreachable("all cases should be handled");
51905209
}
51915210

5211+
51925212
/// A TupleExpr propagate contextual type information down to its children and
51935213
/// can be erroneous when there is a label mismatch etc.
51945214
bool FailureDiagnosis::visitTupleExpr(TupleExpr *TE) {

0 commit comments

Comments
 (0)