Skip to content

Commit 049ec0f

Browse files
committed
Sema: Port member access on existentials diagnostic to new diagnostic framework
1 parent 79ceeaa commit 049ec0f

File tree

6 files changed

+111
-7
lines changed

6 files changed

+111
-7
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -754,12 +754,8 @@ void FailureDiagnosis::diagnoseUnviableLookupResults(
754754
case MemberLookupResult::UR_WritableKeyPathOnReadOnlyMember:
755755
case MemberLookupResult::UR_ReferenceWritableKeyPathOnMutatingMember:
756756
case MemberLookupResult::UR_KeyPathWithAnyObjectRootType:
757-
break;
758757
case MemberLookupResult::UR_UnavailableInExistential:
759-
diagnose(loc, diag::could_not_use_member_on_existential,
760-
instanceTy, memberName)
761-
.highlight(baseRange).highlight(nameLoc.getSourceRange());
762-
return;
758+
break;
763759
case MemberLookupResult::UR_InstanceMemberOnType:
764760
case MemberLookupResult::UR_TypeMemberOnInstance: {
765761
auto locatorKind = isa<SubscriptExpr>(E)
@@ -6671,7 +6667,7 @@ bool FailureDiagnosis::diagnoseMemberFailures(
66716667
locator = simplifyLocator(CS, locator, memberRange);
66726668

66736669
BaseLoc = baseExpr->getLoc();
6674-
NameLoc = DeclNameLoc(memberRange.Start);
6670+
NameLoc = DeclNameLoc(memberRange.Start);
66756671

66766672
// Retypecheck the anchor type, which is the base of the member expression.
66776673
baseExpr =

lib/Sema/CSDiagnostics.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1961,6 +1961,30 @@ bool MissingMemberFailure::diagnoseAsError() {
19611961
return true;
19621962
}
19631963

1964+
bool AllowProtocolTypeMemberFailure::diagnoseAsError() {
1965+
auto *anchor = getRawAnchor();
1966+
1967+
Expr *baseExpr = getAnchor();
1968+
DeclNameLoc nameLoc;
1969+
if (auto *UDE = dyn_cast<UnresolvedDotExpr>(anchor)) {
1970+
baseExpr = UDE->getBase();
1971+
nameLoc = UDE->getNameLoc();
1972+
} else if (auto *UME = dyn_cast<UnresolvedMemberExpr>(anchor)) {
1973+
nameLoc = UME->getNameLoc();
1974+
} else if (auto *SE = dyn_cast<SubscriptExpr>(anchor)) {
1975+
baseExpr = SE->getBase();
1976+
} else if (auto *call = dyn_cast<CallExpr>(anchor)) {
1977+
baseExpr = call->getFn();
1978+
}
1979+
1980+
emitDiagnostic(getAnchor()->getLoc(),
1981+
diag::could_not_use_member_on_existential,
1982+
getBaseType(), getName())
1983+
.highlight(nameLoc.getSourceRange())
1984+
.highlight(baseExpr->getSourceRange());
1985+
return true;
1986+
}
1987+
19641988
bool AllowTypeOrInstanceMemberFailure::diagnoseAsError() {
19651989
auto loc = getAnchor()->getLoc();
19661990
auto &cs = getConstraintSystem();

lib/Sema/CSDiagnostics.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,39 @@ class MissingMemberFailure final : public FailureDiagnostic {
789789
DeclName memberName);
790790
};
791791

792+
/// Diagnose cases where a member only accessible on generic constraints
793+
/// requiring conformance to a protocol is used on a value of the
794+
/// existential protocol type e.g.
795+
///
796+
/// ```swift
797+
/// protocol P {
798+
/// var foo: Self { get }
799+
/// }
800+
///
801+
/// func bar<X : P>(p: X) {
802+
/// p.foo
803+
/// }
804+
/// ```
805+
class AllowProtocolTypeMemberFailure final : public FailureDiagnostic {
806+
Type BaseType;
807+
ValueDecl *Member;
808+
DeclName Name;
809+
810+
public:
811+
AllowProtocolTypeMemberFailure(Expr *root, ConstraintSystem &cs,
812+
Type baseType, ValueDecl *member, DeclName memberName,
813+
ConstraintLocator *locator)
814+
: FailureDiagnostic(root, cs, locator), BaseType(baseType),
815+
Member(member), Name(memberName) {}
816+
817+
bool diagnoseAsError() override;
818+
819+
private:
820+
Type getBaseType() const { return BaseType; }
821+
ValueDecl *getMember() const { return Member; }
822+
DeclName getName() const { return Name; }
823+
};
824+
792825
/// Diagnose situations when we use an instance member on a type
793826
/// or a type member on an instance
794827
///

lib/Sema/CSFix.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,19 @@ DefineMemberBasedOnUse::create(ConstraintSystem &cs, Type baseType,
283283
DefineMemberBasedOnUse(cs, baseType, member, locator);
284284
}
285285

286+
AllowProtocolTypeMember *
287+
AllowProtocolTypeMember::create(ConstraintSystem &cs, Type baseType,
288+
ValueDecl *member, DeclName memberName, ConstraintLocator *locator) {
289+
return new (cs.getAllocator())
290+
AllowProtocolTypeMember(cs, baseType, memberName, member, locator);
291+
}
292+
293+
bool AllowProtocolTypeMember::diagnose(Expr *root, bool asNote) const {
294+
auto failure = AllowProtocolTypeMemberFailure(root, getConstraintSystem(),
295+
BaseType, Member, Name, getLocator());
296+
return failure.diagnose(asNote);
297+
}
298+
286299
bool AllowTypeOrInstanceMember::diagnose(Expr *root, bool asNote) const {
287300
auto failure = AllowTypeOrInstanceMemberFailure(
288301
root, getConstraintSystem(), BaseType, Member, UsedName, getLocator());

lib/Sema/CSFix.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,11 @@ enum class FixKind : uint8_t {
124124
/// derived (rather than an arbitrary value of metatype type) or the
125125
/// referenced constructor must be required.
126126
AllowInvalidInitRef,
127+
128+
/// Allow an invalid member access on a value of protocol type as if
129+
/// that protocol type were a generic constraint requiring conformance
130+
/// to that protocol.
131+
AllowProtocolTypeMember,
127132

128133
/// If there are fewer arguments than parameters, let's fix that up
129134
/// by adding new arguments to the list represented as type variables.
@@ -592,6 +597,32 @@ class DefineMemberBasedOnUse final : public ConstraintFix {
592597
DeclName member,
593598
ConstraintLocator *locator);
594599
};
600+
601+
class AllowProtocolTypeMember final : public ConstraintFix {
602+
Type BaseType;
603+
ValueDecl *Member;
604+
DeclName Name;
605+
606+
AllowProtocolTypeMember(ConstraintSystem &cs, Type baseType,
607+
DeclName memberName, ValueDecl *member,
608+
ConstraintLocator *locator)
609+
: ConstraintFix(cs, FixKind::AllowProtocolTypeMember,
610+
locator), BaseType(baseType), Member(member), Name(memberName) {}
611+
612+
public:
613+
std::string getName() const override {
614+
llvm::SmallVector<char, 16> scratch;
615+
auto memberName = Name.getString(scratch);
616+
return "allow access to invalid member '" + memberName.str() +
617+
"' on value of protocol type";
618+
}
619+
620+
bool diagnose(Expr *root, bool asNote = false) const override;
621+
622+
static AllowProtocolTypeMember *create(ConstraintSystem &cs,
623+
Type baseType, ValueDecl *member, DeclName memberName,
624+
ConstraintLocator *locator);
625+
};
595626

596627
class AllowTypeOrInstanceMember final : public ConstraintFix {
597628
Type BaseType;

lib/Sema/CSSimplify.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4528,11 +4528,17 @@ fixMemberRef(ConstraintSystem &cs, Type baseTy,
45284528
case MemberLookupResult::UR_Inaccessible:
45294529
assert(choice.isDecl());
45304530
return AllowInaccessibleMember::create(cs, choice.getDecl(), locator);
4531+
4532+
case MemberLookupResult::UR_UnavailableInExistential: {
4533+
return choice.isDecl()
4534+
? AllowProtocolTypeMember::create(
4535+
cs, baseTy, choice.getDecl(), memberName, locator)
4536+
: nullptr;
4537+
}
45314538

45324539
case MemberLookupResult::UR_MutatingMemberOnRValue:
45334540
case MemberLookupResult::UR_MutatingGetterOnRValue:
45344541
case MemberLookupResult::UR_LabelMismatch:
4535-
case MemberLookupResult::UR_UnavailableInExistential:
45364542
// TODO(diagnostics): Add a new fix that is suggests to
45374543
// add `subscript(dynamicMember: {Writable}KeyPath<T, U>)`
45384544
// overload here, that would help if such subscript has
@@ -6637,6 +6643,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
66376643
case FixKind::RelabelArguments:
66386644
case FixKind::RemoveUnwrap:
66396645
case FixKind::DefineMemberBasedOnUse:
6646+
case FixKind::AllowProtocolTypeMember:
66406647
case FixKind::AllowTypeOrInstanceMember:
66416648
case FixKind::AllowInvalidPartialApplication:
66426649
case FixKind::AllowInvalidInitRef:

0 commit comments

Comments
 (0)