Skip to content

Commit 427190d

Browse files
committed
Sema: Handle generic-signature-based existential availability
1 parent 3206f5a commit 427190d

File tree

2 files changed

+115
-0
lines changed

2 files changed

+115
-0
lines changed

lib/Sema/ConstraintSystem.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5789,6 +5789,68 @@ void ConstraintSystem::maybeProduceFallbackDiagnostic(
57895789
ctx.Diags.diagnose(target.getLoc(), diag::failed_to_produce_diagnostic);
57905790
}
57915791

5792+
/// A protocol member accessed with an existential value might have generic
5793+
/// constraints that require the ability to spell an opened archetype in order
5794+
/// to be satisfied. Such are
5795+
/// - superclass requirements, when the object is a non-'Self'-rooted type
5796+
/// parameter, and the subject is dependent on 'Self', e.g. U : G<Self.A>
5797+
/// - same-type requirements, when one side is dependent on 'Self', and the
5798+
/// other is a non-'Self'-rooted type parameter, e.g. U.Element == Self.
5799+
///
5800+
/// Because opened archetypes are not part of the surface language, these
5801+
/// constraints render the member inaccessible.
5802+
static bool doesMemberHaveUnfulfillableConstraintsWithExistentialBase(
5803+
const ValueDecl *member) {
5804+
const auto sig =
5805+
member->getInnermostDeclContext()->getGenericSignatureOfContext();
5806+
5807+
// Fast path: the member is generic only over 'Self'.
5808+
if (sig.getGenericParams().size() == 1) {
5809+
return false;
5810+
}
5811+
5812+
const auto selfTy = sig.getGenericParams().front();
5813+
5814+
const auto isDependentOnSelf = [&](Type ty) {
5815+
return ty.findIf([&](Type ty) {
5816+
return ty->is<GenericTypeParamType>() && ty->isEqual(selfTy);
5817+
});
5818+
};
5819+
5820+
for (const auto &req : sig.getRequirements()) {
5821+
switch (req.getKind()) {
5822+
case RequirementKind::Superclass: {
5823+
if (!req.getFirstType()->getRootGenericParam()->isEqual(selfTy) &&
5824+
isDependentOnSelf(req.getSecondType())) {
5825+
return true;
5826+
}
5827+
5828+
break;
5829+
}
5830+
case RequirementKind::SameType: {
5831+
const auto isNonSelfRootedTypeParam = [&](Type ty) {
5832+
return ty->isTypeParameter() &&
5833+
!ty->getRootGenericParam()->isEqual(selfTy);
5834+
};
5835+
5836+
const auto lhs = req.getFirstType();
5837+
const auto rhs = req.getSecondType();
5838+
if ((isNonSelfRootedTypeParam(lhs) && isDependentOnSelf(rhs)) ||
5839+
(isNonSelfRootedTypeParam(rhs) && isDependentOnSelf(lhs))) {
5840+
return true;
5841+
}
5842+
5843+
break;
5844+
}
5845+
case RequirementKind::Conformance:
5846+
case RequirementKind::Layout:
5847+
break;
5848+
}
5849+
}
5850+
5851+
return false;
5852+
}
5853+
57925854
bool ConstraintSystem::isAvailableInExistential(const ProtocolDecl *proto,
57935855
const ValueDecl *member) const {
57945856
// If the type of the member references 'Self' in non-covariant position, or
@@ -5805,6 +5867,10 @@ bool ConstraintSystem::isAvailableInExistential(const ProtocolDecl *proto,
58055867
return false;
58065868
}
58075869

5870+
if (doesMemberHaveUnfulfillableConstraintsWithExistentialBase(member)) {
5871+
return false;
5872+
}
5873+
58085874
return true;
58095875
}
58105876

test/decl/protocol/protocols_with_self_or_assoc_reqs.swift

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,55 @@ do {
474474
}
475475
}
476476

477+
protocol UnfulfillableGenericRequirements {
478+
associatedtype A
479+
}
480+
extension UnfulfillableGenericRequirements {
481+
func method1() where A : C<Self> {}
482+
// expected-note@-1 {{where 'Self.A' = '(UnfulfillableGenericRequirements).A', 'C<Self>' = 'C<UnfulfillableGenericRequirements>'}}
483+
func method2() where A: Sequence, A.Element == Self {}
484+
// expected-note@-1 {{where 'Self' = 'UnfulfillableGenericRequirements', 'Self.A.Element' = '(UnfulfillableGenericRequirements).A.Element'}}
485+
// expected-note@-2 {{where 'Self.A' = '(UnfulfillableGenericRequirements).A'}}
486+
func method3<U>(_: U) -> U {}
487+
func method4<U>(_: U) where U : C<Self> {}
488+
// expected-note@-1 {{where 'U' = 'Bool', 'C<Self>' = 'C<UnfulfillableGenericRequirements>'}}
489+
func method5<U>(_: U) where U: Sequence, Self == U.Element {}
490+
// expected-note@-1 {{where 'U' = 'Bool'}}
491+
492+
// expected-note@+3 {{where 'Self.A' = '(UnfulfillableGenericRequirements).A'}}
493+
// expected-note@+2 {{where 'Self.A.Element' = '(UnfulfillableGenericRequirements).A.Element'}}
494+
// expected-note@+1 {{where 'U' = 'Bool'}}
495+
func method6<U>(_: U) where U: UnfulfillableGenericRequirements,
496+
A: Sequence, A.Element: Sequence,
497+
U.A == A.Element.Element {}
498+
func method7<U>(_: U) where U: UnfulfillableGenericRequirements & C<Self> {}
499+
// expected-note@-1 {{where 'U' = 'C<UnfulfillableGenericRequirements>'}}
500+
}
501+
do {
502+
let exist: any UnfulfillableGenericRequirements
503+
504+
exist.method1() // expected-error {{instance method 'method1()' requires that '(UnfulfillableGenericRequirements).A' inherit from 'C<UnfulfillableGenericRequirements>'}}
505+
exist.method2()
506+
// expected-error@-1 {{instance method 'method2()' requires the types 'UnfulfillableGenericRequirements' and '(UnfulfillableGenericRequirements).A.Element' be equivalent}}
507+
// expected-error@-2 {{instance method 'method2()' requires that '(UnfulfillableGenericRequirements).A' conform to 'Sequence'}}
508+
_ = exist.method3(false)
509+
exist.method4(false)
510+
// expected-error@-1 {{instance method 'method4' requires that 'Bool' inherit from 'C<UnfulfillableGenericRequirements>'}}
511+
// expected-error@-2 {{member 'method4' cannot be used on value of protocol type 'UnfulfillableGenericRequirements'; use a generic constraint instead}}
512+
exist.method5(false)
513+
// expected-error@-1 {{instance method 'method5' requires that 'Bool' conform to 'Sequence'}}
514+
// expected-error@-2 {{member 'method5' cannot be used on value of protocol type 'UnfulfillableGenericRequirements'; use a generic constraint instead}}
515+
exist.method6(false)
516+
// expected-error@-1 {{instance method 'method6' requires that '(UnfulfillableGenericRequirements).A.Element' conform to 'Sequence'}}
517+
// expected-error@-2 {{instance method 'method6' requires that '(UnfulfillableGenericRequirements).A' conform to 'Sequence'}}
518+
// expected-error@-3 {{instance method 'method6' requires that 'Bool' conform to 'UnfulfillableGenericRequirements'}}
519+
// expected-error@-4 {{member 'method6' cannot be used on value of protocol type 'UnfulfillableGenericRequirements'; use a generic constraint instead}}
520+
exist.method7(false)
521+
// expected-error@-1 {{instance method 'method7' requires that 'C<UnfulfillableGenericRequirements>' conform to 'UnfulfillableGenericRequirements'}}
522+
// expected-error@-2 {{member 'method7' cannot be used on value of protocol type 'UnfulfillableGenericRequirements'; use a generic constraint instead}}
523+
// expected-error@-3 {{cannot convert value of type 'Bool' to expected argument type 'C<UnfulfillableGenericRequirements>'}}
524+
}
525+
477526
// Settable storage members with a 'Self' result type may not be used with an
478527
// existential base.
479528
protocol P2 {

0 commit comments

Comments
 (0)