Skip to content

Commit 11ef6e5

Browse files
authored
Merge pull request #71659 from xedin/noncopyable-circularity-fixes
[AST/Sema] NonCopyableGenerics: Address some of the request circularity issues
2 parents a0810ec + b6af269 commit 11ef6e5

15 files changed

+339
-356
lines changed

include/swift/AST/Decl.h

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "swift/AST/IfConfigClause.h"
3333
#include "swift/AST/Import.h"
3434
#include "swift/AST/Initializer.h"
35+
#include "swift/AST/InverseMarking.h"
3536
#include "swift/AST/LayoutConstraint.h"
3637
#include "swift/AST/LifetimeAnnotation.h"
3738
#include "swift/AST/ReferenceCounting.h"
@@ -3219,30 +3220,6 @@ class TypeDecl : public ValueDecl {
32193220
};
32203221
};
32213222

3222-
/// "Does a conformance for Copyable exist for this type declaration?"
3223-
///
3224-
/// This doesn't mean that all instance of this type are Copyable, because
3225-
/// if a conditional conformance to Copyable exists, this method will return
3226-
/// true.
3227-
///
3228-
/// If you need a more precise answer, ask this Decl's corresponding
3229-
/// Type if it `isCopyable` instead of using this.
3230-
CanBeInvertible::Result canBeCopyable() const;
3231-
3232-
/// "Does a conformance for Escapable exist for this type declaration?"
3233-
///
3234-
/// This doesn't mean that all instance of this type are Escapable, because
3235-
/// if a conditional conformance to Escapable exists, this method will return
3236-
/// true.
3237-
///
3238-
/// If you need a more precise answer, ask this Decl's corresponding
3239-
/// Type if it `isEscapable` instead of using this.
3240-
CanBeInvertible::Result canBeEscapable() const;
3241-
3242-
/// Determine how the given invertible protocol was written on this TypeDecl,
3243-
/// if at all.
3244-
InverseMarking getMarking(InvertibleProtocolKind ip) const;
3245-
32463223
static bool classof(const Decl *D) {
32473224
return D->getKind() >= DeclKind::First_TypeDecl &&
32483225
D->getKind() <= DeclKind::Last_TypeDecl;
@@ -3260,7 +3237,7 @@ class TypeDecl : public ValueDecl {
32603237
}
32613238
};
32623239

3263-
/// A type declaration that can have generic parameters attached to it. Because
3240+
/// A type declaration that have generic parameters attached to it. Because
32643241
/// it has these generic parameters, it is always a DeclContext.
32653242
class GenericTypeDecl : public GenericContext, public TypeDecl {
32663243
public:
@@ -3935,6 +3912,10 @@ class AssociatedTypeDecl : public TypeDecl {
39353912
TypeDecl::getOverriddenDecl());
39363913
}
39373914

3915+
/// Determine whether this type has ~<target>` stated as
3916+
/// one of its inherited types.
3917+
InverseMarking::Mark hasInverseMarking(InvertibleProtocolKind target) const;
3918+
39383919
/// Retrieve the set of associated types overridden by this associated
39393920
/// type.
39403921
llvm::TinyPtrVector<AssociatedTypeDecl *> getOverriddenDecls() const;
@@ -4372,6 +4353,34 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
43724353
/// Returns null if the type is a class, or does not have a declared `deinit`.
43734354
DestructorDecl *getValueTypeDestructor();
43744355

4356+
/// "Does a conformance for Copyable exist for this type declaration?"
4357+
///
4358+
/// This doesn't mean that all instance of this type are Copyable, because
4359+
/// if a conditional conformance to Copyable exists, this method will return
4360+
/// true.
4361+
///
4362+
/// If you need a more precise answer, ask this Decl's corresponding
4363+
/// Type if it `isCopyable` instead of using this.
4364+
CanBeInvertible::Result canBeCopyable() const;
4365+
4366+
/// "Does a conformance for Escapable exist for this type declaration?"
4367+
///
4368+
/// This doesn't mean that all instance of this type are Escapable, because
4369+
/// if a conditional conformance to Escapable exists, this method will return
4370+
/// true.
4371+
///
4372+
/// If you need a more precise answer, ask this Decl's corresponding
4373+
/// Type if it `isEscapable` instead of using this.
4374+
CanBeInvertible::Result canBeEscapable() const;
4375+
4376+
/// Determine whether this type has `: <target>` stated explicitly in
4377+
/// its inheritance clause.
4378+
bool hasMarking(InvertibleProtocolKind target) const;
4379+
4380+
/// Determine whether this type has ~<target>` stated on
4381+
/// itself, one of its inherited types or `Self` requirements.
4382+
InverseMarking::Mark hasInverseMarking(InvertibleProtocolKind target) const;
4383+
43754384
// Implement isa/cast/dyncast/etc.
43764385
static bool classof(const Decl *D) {
43774386
return D->getKind() >= DeclKind::First_NominalTypeDecl &&
@@ -5227,6 +5236,10 @@ class ProtocolDecl final : public NominalTypeDecl {
52275236
/// protocol.
52285237
bool inheritsFrom(const ProtocolDecl *Super) const;
52295238

5239+
/// Determine whether this protocol has ~<target>` stated on
5240+
/// itself, one of its inherited types or `Self` requirements.
5241+
InverseMarking::Mark hasInverseMarking(InvertibleProtocolKind target) const;
5242+
52305243
/// Determine whether this protocol requires conformance to `IP`, without
52315244
/// querying a generic signature.
52325245
bool requiresInvertible(InvertibleProtocolKind ip) const;

include/swift/AST/InverseMarking.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919

2020
namespace swift {
2121

22-
class InvertibleAnnotationRequest;
23-
2422
/// Describes the way an inverse and its corresponding positive contraint
2523
/// appears on a TypeDecl, i.e., the way it was marked.
2624
struct InverseMarking {
@@ -91,8 +89,6 @@ struct InverseMarking {
9189
Mark inverse;
9290
Mark positive;
9391

94-
// This friend initializes the marks.
95-
friend InvertibleAnnotationRequest;
9692
public:
9793

9894
// Creates an empty marking.

include/swift/AST/TypeCheckRequests.h

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -429,28 +429,6 @@ class IsFinalRequest :
429429
void cacheResult(bool value) const;
430430
};
431431

432-
/// Determine the kind of invertible protocol markings for this declaration,
433-
/// for example, if a conformance to IP or ~IP was written on it in the
434-
/// inheritance clause and/or where clause.
435-
class InvertibleAnnotationRequest
436-
: public SimpleRequest<InvertibleAnnotationRequest,
437-
InverseMarking(TypeDecl *, InvertibleProtocolKind),
438-
RequestFlags::Cached> {
439-
public:
440-
using SimpleRequest::SimpleRequest;
441-
442-
private:
443-
friend SimpleRequest;
444-
445-
// Evaluation.
446-
InverseMarking evaluate(Evaluator &evaluator,
447-
TypeDecl *decl, InvertibleProtocolKind ip) const;
448-
449-
public:
450-
// Caching.
451-
bool isCached() const { return true; }
452-
};
453-
454432
/// Determine whether the given declaration is 'dynamic''.
455433
class IsDynamicRequest :
456434
public SimpleRequest<IsDynamicRequest,

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -217,9 +217,6 @@ SWIFT_REQUEST(TypeChecker, IsDynamicRequest, bool(ValueDecl *),
217217
SeparatelyCached, NoLocationInfo)
218218
SWIFT_REQUEST(TypeChecker, IsFinalRequest, bool(ValueDecl *), SeparatelyCached,
219219
NoLocationInfo)
220-
SWIFT_REQUEST(TypeChecker, InvertibleAnnotationRequest,
221-
InverseMarking(TypeDecl *, InvertibleProtocolKind),
222-
Cached, NoLocationInfo)
223220
SWIFT_REQUEST(TypeChecker, IsGetterMutatingRequest, bool(AbstractStorageDecl *),
224221
SeparatelyCached, NoLocationInfo)
225222
SWIFT_REQUEST(TypeChecker, IsImplicitlyUnwrappedOptionalRequest,

include/swift/AST/TypeRepr.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,10 @@ class alignas(1 << TypeReprAlignInBits) TypeRepr
137137
/// Is this type representation a protocol?
138138
bool isProtocolOrProtocolComposition(DeclContext *dc);
139139

140+
/// Is this `~<target>` representation.
141+
bool isInverseOf(InvertibleProtocolKind target,
142+
DeclContext *dc);
143+
140144
/// Is this type representation known to be invalid?
141145
bool isInvalid() const { return Bits.TypeRepr.Invalid; }
142146

lib/AST/ASTPrinter.cpp

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3407,9 +3407,8 @@ static bool usesFeatureFlowSensitiveConcurrencyCaptures(Decl *decl) {
34073407
/// \param isRelevantInverse the function used to inspect a mark corresponding
34083408
/// to an inverse to determine whether it "has" an inverse that we care about.
34093409
static bool hasInverse(
3410-
Decl *decl,
3411-
InvertibleProtocolKind ip,
3412-
std::function<bool(InverseMarking const&)> isRelevantInverse) {
3410+
Decl *decl, InvertibleProtocolKind ip,
3411+
std::function<bool(InverseMarking::Mark const &)> isRelevantInverse) {
34133412

34143413
auto getTypeDecl = [](Type type) -> TypeDecl* {
34153414
if (auto genericTy = type->getAnyGeneric())
@@ -3421,40 +3420,41 @@ static bool hasInverse(
34213420

34223421
if (auto *extension = dyn_cast<ExtensionDecl>(decl)) {
34233422
if (auto *nominal = extension->getSelfNominalTypeDecl())
3424-
if (isRelevantInverse(nominal->getMarking(ip)))
3425-
return true;
3423+
return hasInverse(nominal, ip, isRelevantInverse);
3424+
return false;
34263425
}
34273426

3428-
if (auto typeDecl = dyn_cast<TypeDecl>(decl)) {
3429-
if (isRelevantInverse(typeDecl->getMarking(ip)))
3430-
return true;
3427+
auto hasInverseInType = [&](Type type) {
3428+
return type.findIf([&](Type type) -> bool {
3429+
if (auto *typeDecl = getTypeDecl(type))
3430+
return hasInverse(typeDecl, ip, isRelevantInverse);
3431+
return false;
3432+
});
3433+
};
34313434

3432-
// Check the protocol's associated types too.
3433-
if (auto proto = dyn_cast<ProtocolDecl>(decl)) {
3434-
auto hasInverse =
3435-
llvm::any_of(proto->getAssociatedTypeMembers(),
3436-
[&](AssociatedTypeDecl *assocTyDecl) {
3437-
return isRelevantInverse(assocTyDecl->getMarking(ip));
3438-
});
3439-
if (hasInverse)
3435+
if (auto *TD = dyn_cast<TypeDecl>(decl)) {
3436+
if (auto *alias = dyn_cast<TypeAliasDecl>(TD))
3437+
return hasInverseInType(alias->getUnderlyingType());
3438+
3439+
if (auto *NTD = dyn_cast<NominalTypeDecl>(TD)) {
3440+
if (isRelevantInverse(NTD->hasInverseMarking(ip)))
34403441
return true;
34413442
}
3442-
}
34433443

3444-
if (auto value = dyn_cast<ValueDecl>(decl)) {
3445-
// Check for noncopyable types in the types of this declaration.
3446-
if (Type type = value->getInterfaceType()) {
3447-
bool hasInverse = type.findIf([&](Type type) {
3448-
if (auto *typeDecl = getTypeDecl(type))
3449-
if (isRelevantInverse(typeDecl->getMarking(ip)))
3450-
return true;
3444+
if (auto *P = dyn_cast<ProtocolDecl>(TD)) {
3445+
// Check the protocol's associated types too.
3446+
return llvm::any_of(
3447+
P->getAssociatedTypeMembers(), [&](AssociatedTypeDecl *ATD) {
3448+
return isRelevantInverse(ATD->hasInverseMarking(ip));
3449+
});
3450+
}
34513451

3452-
return false;
3453-
});
3452+
return false;
3453+
}
34543454

3455-
if (hasInverse)
3456-
return true;
3457-
}
3455+
if (auto *VD = dyn_cast<ValueDecl>(decl)) {
3456+
if (VD->hasInterfaceType())
3457+
return hasInverseInType(VD->getInterfaceType());
34583458
}
34593459

34603460
return false;
@@ -3463,8 +3463,8 @@ static bool hasInverse(
34633463
static bool usesFeatureMoveOnly(Decl *decl) {
34643464
return hasInverse(decl, InvertibleProtocolKind::Copyable,
34653465
[](auto &marking) -> bool {
3466-
return marking.getInverse().is(InverseMarking::Kind::LegacyExplicit);
3467-
});
3466+
return marking.is(InverseMarking::Kind::LegacyExplicit);
3467+
});
34683468
}
34693469

34703470
static bool usesFeatureLazyImmediate(Decl *D) { return false; }
@@ -3508,8 +3508,8 @@ static bool usesFeatureMoveOnlyPartialReinitialization(Decl *decl) {
35083508
}
35093509

35103510
static bool usesFeatureNoncopyableGenerics(Decl *decl) {
3511-
auto checkMarking = [](auto &marking) -> bool {
3512-
switch (marking.getInverse().getKind()) {
3511+
auto checkInverseMarking = [](auto &marking) -> bool {
3512+
switch (marking.getKind()) {
35133513
case InverseMarking::Kind::None:
35143514
case InverseMarking::Kind::LegacyExplicit: // covered by other checks.
35153515
return false;
@@ -3520,8 +3520,10 @@ static bool usesFeatureNoncopyableGenerics(Decl *decl) {
35203520
}
35213521
};
35223522

3523-
return hasInverse(decl, InvertibleProtocolKind::Copyable, checkMarking)
3524-
|| hasInverse(decl, InvertibleProtocolKind::Escapable, checkMarking);
3523+
return hasInverse(decl, InvertibleProtocolKind::Copyable,
3524+
checkInverseMarking) ||
3525+
hasInverse(decl, InvertibleProtocolKind::Escapable,
3526+
checkInverseMarking);
35253527
}
35263528

35273529
static bool usesFeatureOneWayClosureParameters(Decl *decl) {

lib/AST/ConformanceLookup.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -415,8 +415,7 @@ getBuiltinInvertibleProtocolConformance(NominalTypeDecl *nominal,
415415
case InvertibleProtocolKind::Copyable:
416416
// If move-only classes is enabled, we'll check the markings.
417417
if (ctx.LangOpts.hasFeature(Feature::MoveOnlyClasses)) {
418-
auto marking = nominal->getMarking(*ip);
419-
switch (marking.getInverse().getKind()) {
418+
switch (nominal->hasInverseMarking(*ip).getKind()) {
420419
case InverseMarking::Kind::LegacyExplicit:
421420
case InverseMarking::Kind::Explicit:
422421
// An inverse ~Copyable prevents conformance.

0 commit comments

Comments
 (0)