Skip to content

Commit e99ce1c

Browse files
committed
[NCGenerics] add ~Escapable
Basic implementation of `~Escapable` in the type system. rdar://119216918
1 parent b0d4ba0 commit e99ce1c

32 files changed

+572
-281
lines changed

include/swift/AST/Decl.h

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2680,19 +2680,12 @@ class ValueDecl : public Decl {
26802680
/// Whether this declaration produces an implicitly unwrapped
26812681
/// optional result.
26822682
unsigned isIUO : 1;
2683-
2684-
/// Whether the "isEscapable" bit has been computed yet.
2685-
unsigned isEscapable : 1;
2686-
2687-
/// Whether this declaration is escapable.
2688-
unsigned isEscapableComputed : 1;
26892683
} LazySemanticInfo = { };
26902684

26912685
friend class DynamicallyReplacedDeclRequest;
26922686
friend class OverriddenDeclsRequest;
26932687
friend class IsObjCRequest;
26942688
friend class IsFinalRequest;
2695-
friend class IsEscapableRequest;
26962689
friend class IsDynamicRequest;
26972690
friend class IsImplicitlyUnwrappedOptionalRequest;
26982691
friend class InterfaceTypeRequest;
@@ -2980,9 +2973,6 @@ class ValueDecl : public Decl {
29802973
/// Is this declaration 'final'?
29812974
bool isFinal() const;
29822975

2983-
/// Is this declaration escapable?
2984-
bool isEscapable() const;
2985-
29862976
/// Is this declaration marked with 'dynamic'?
29872977
bool isDynamic() const;
29882978

@@ -3190,8 +3180,12 @@ class TypeDecl : public ValueDecl {
31903180
/// Type if it `isNoncopyable` instead of using this.
31913181
bool canBeNoncopyable() const;
31923182

3193-
/// Determine how the ~Copyable was applied to this TypeDecl, if at all.
3194-
InverseMarking getNoncopyableMarking() const;
3183+
/// Is this declaration escapable?
3184+
bool isEscapable() const;
3185+
3186+
/// Determine how the given invertible protocol was written on this TypeDecl,
3187+
/// if at all.
3188+
InverseMarking getMarking(InvertibleProtocolKind ip) const;
31953189

31963190
static bool classof(const Decl *D) {
31973191
return D->getKind() >= DeclKind::First_TypeDecl &&

include/swift/AST/DiagnosticsSema.def

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7555,27 +7555,27 @@ ERROR(accessor_macro_not_single_var, none,
75557555
//------------------------------------------------------------------------------
75567556
// MARK: Noncopyable Types Diagnostics
75577557
//------------------------------------------------------------------------------
7558-
ERROR(noncopyable_but_copyable, none,
7559-
"%kind0 required to be 'Copyable' but is marked with '~Copyable'",
7560-
(const ValueDecl *))
7561-
ERROR(noncopyable_generic_but_copyable, none,
7558+
ERROR(inverse_but_also_conforms, none,
7559+
"%kind0 required to be '%1' but is marked with '~%1'",
7560+
(const ValueDecl *, StringRef))
7561+
ERROR(inverse_generic_but_also_conforms, none,
75627562
"%0 required to be '%1' but is marked with '~%1'",
75637563
(Type, StringRef))
75647564
WARNING(redundant_inverse_constraint,none,
75657565
"redundant constraint %0 : '~%1'", (Type, StringRef))
7566-
ERROR(noncopyable_class, none,
7567-
"classes cannot be noncopyable",
7568-
())
7566+
ERROR(inverse_on_class, none,
7567+
"classes cannot be '~%0'",
7568+
(StringRef))
75697569
ERROR(inverse_extension, none,
75707570
"cannot apply inverse %0 to extension",
75717571
(Type))
75727572
ERROR(copyable_illegal_deinit, none,
75737573
"deinitializer cannot be declared in %kind0 that conforms to 'Copyable'",
75747574
(const ValueDecl *))
7575-
ERROR(noncopyable_type_member_in_copyable,none,
7575+
ERROR(inverse_type_member_in_conforming_type,none,
75767576
"%select{stored property %2|associated value %2}1 of "
7577-
"'Copyable'-conforming %kind3 has noncopyable type %0",
7578-
(Type, bool, DeclName, const ValueDecl *))
7577+
"'%4'-conforming %kind3 has non-%4 type %0",
7578+
(Type, bool, DeclName, const ValueDecl *, StringRef))
75797579
NOTE(add_inverse,none,
75807580
"consider adding '~%1' to %kind0",
75817581
(const ValueDecl *, StringRef))
@@ -7592,6 +7592,9 @@ NOTE(note_inverse_preventing_conformance_explicit,none,
75927592
NOTE(add_explicit_protocol_for_conformance,none,
75937593
"consider making %kind0 explicitly conform to the '%1' protocol",
75947594
(const ValueDecl *, StringRef))
7595+
ERROR(escapable_requires_feature_flag,none,
7596+
"type '~Escapable' requires -enable-experimental-feature NonEscapableTypes",
7597+
())
75957598

75967599
// -- older ones below --
75977600

include/swift/AST/InverseMarking.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
namespace swift {
2121

22-
class NoncopyableAnnotationRequest;
22+
class InvertibleAnnotationRequest;
2323

2424
/// Describes the way an inverse and its corresponding positive contraint
2525
/// appears on a TypeDecl, i.e., the way it was marked.
@@ -87,7 +87,7 @@ struct InverseMarking {
8787
Mark positive;
8888

8989
// This friend initializes the marks.
90-
friend NoncopyableAnnotationRequest;
90+
friend InvertibleAnnotationRequest;
9191
public:
9292

9393
// Creates an empty marking.

include/swift/AST/KnownProtocols.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ PROTOCOL(AsyncIteratorProtocol)
137137
PROTOCOL(FloatingPoint)
138138

139139
INVERTIBLE_PROTOCOL_WITH_NAME(Copyable, "Copyable")
140+
INVERTIBLE_PROTOCOL_WITH_NAME(Escapable, "Escapable")
140141
PROTOCOL_(BitwiseCopyable)
141142

142143
EXPRESSIBLE_BY_LITERAL_PROTOCOL(ExpressibleByArrayLiteral, "Array", false)

include/swift/AST/KnownProtocols.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ llvm::Optional<InvertibleProtocolKind>
7373
/// Returns the KnownProtocolKind corresponding to an InvertibleProtocolKind.
7474
KnownProtocolKind getKnownProtocolKind(InvertibleProtocolKind ip);
7575

76+
void simple_display(llvm::raw_ostream &out,
77+
const InvertibleProtocolKind &value);
78+
7679
} // end namespace swift
7780

7881
#endif

include/swift/AST/TypeCheckRequests.h

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -428,10 +428,12 @@ class IsFinalRequest :
428428
void cacheResult(bool value) const;
429429
};
430430

431-
/// Determine the kind of noncopyable marking present for this declaration.
432-
class NoncopyableAnnotationRequest
433-
: public SimpleRequest<NoncopyableAnnotationRequest,
434-
InverseMarking(TypeDecl *),
431+
/// Determine the kind of invertible protocol markings for this declaration,
432+
/// for example, if a conformance to IP or ~IP was written on it in the
433+
/// inheritance clause and/or where clause.
434+
class InvertibleAnnotationRequest
435+
: public SimpleRequest<InvertibleAnnotationRequest,
436+
InverseMarking(TypeDecl *, InvertibleProtocolKind),
435437
RequestFlags::Cached> {
436438
public:
437439
using SimpleRequest::SimpleRequest;
@@ -440,31 +442,30 @@ class NoncopyableAnnotationRequest
440442
friend SimpleRequest;
441443

442444
// Evaluation.
443-
InverseMarking evaluate(Evaluator &evaluator, TypeDecl *decl) const;
445+
InverseMarking evaluate(Evaluator &evaluator,
446+
TypeDecl *decl, InvertibleProtocolKind ip) const;
444447

445448
public:
446449
// Caching.
447450
bool isCached() const { return true; }
448451
};
449452

450-
/// Determine whether the given declaration is escapable.
453+
/// Determine whether the given type is Escapable.
451454
class IsEscapableRequest
452-
: public SimpleRequest<IsEscapableRequest, bool(ValueDecl *),
453-
RequestFlags::SeparatelyCached> {
455+
: public SimpleRequest<IsEscapableRequest, bool(CanType),
456+
RequestFlags::Cached> {
454457
public:
455458
using SimpleRequest::SimpleRequest;
456459

457460
private:
458461
friend SimpleRequest;
459462

460463
// Evaluation.
461-
bool evaluate(Evaluator &evaluator, ValueDecl *decl) const;
464+
bool evaluate(Evaluator &evaluator, CanType) const;
462465

463466
public:
464-
// Separate caching.
467+
// Caching.
465468
bool isCached() const { return true; }
466-
llvm::Optional<bool> getCachedResult() const;
467-
void cacheResult(bool value) const;
468469
};
469470

470471
/// Determine whether the given type is noncopyable. Assumes type parameters

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -210,14 +210,15 @@ SWIFT_REQUEST(TypeChecker, IsDynamicRequest, bool(ValueDecl *),
210210
SeparatelyCached, NoLocationInfo)
211211
SWIFT_REQUEST(TypeChecker, IsFinalRequest, bool(ValueDecl *), SeparatelyCached,
212212
NoLocationInfo)
213-
SWIFT_REQUEST(TypeChecker, NoncopyableAnnotationRequest,
214-
InverseMarking(TypeDecl *),
213+
SWIFT_REQUEST(TypeChecker, InvertibleAnnotationRequest,
214+
InverseMarking(TypeDecl *, InvertibleProtocolKind),
215215
Cached, NoLocationInfo)
216216
SWIFT_REQUEST(TypeChecker, IsNoncopyableRequest,
217217
bool (CanType),
218218
Cached, NoLocationInfo)
219-
SWIFT_REQUEST(TypeChecker, IsEscapableRequest, bool(ValueDecl *),
220-
SeparatelyCached, NoLocationInfo)
219+
SWIFT_REQUEST(TypeChecker, IsEscapableRequest,
220+
bool (CanType),
221+
Cached, NoLocationInfo)
221222
SWIFT_REQUEST(TypeChecker, IsGetterMutatingRequest, bool(AbstractStorageDecl *),
222223
SeparatelyCached, NoLocationInfo)
223224
SWIFT_REQUEST(TypeChecker, IsImplicitlyUnwrappedOptionalRequest,

include/swift/AST/Types.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -640,11 +640,13 @@ class alignas(1 << TypeAlignInBits) TypeBase
640640

641641
bool isPlaceholder();
642642

643-
/// DEPRECIATED: Returns true if this is a noncopyable type.
644-
bool isNoncopyable();
643+
/// Returns true if this type lacks conformance to Copyable in the context,
644+
/// if provided.
645+
bool isNoncopyable(const DeclContext *dc = nullptr);
645646

646-
/// Returns true if this type lacks conformance to Copyable in the context.
647-
bool isNoncopyable(const DeclContext *dc);
647+
/// Returns true if this type conforms to Escapable in the context,
648+
/// if provided.
649+
bool isEscapable(const DeclContext *dc = nullptr);
648650

649651
/// Does the type have outer parenthesis?
650652
bool hasParenSugar() const { return getKind() == TypeKind::Paren; }

lib/AST/ASTContext.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,11 @@ KnownProtocolKind swift::getKnownProtocolKind(InvertibleProtocolKind ip) {
122122
}
123123
}
124124

125+
void swift::simple_display(llvm::raw_ostream &out,
126+
const InvertibleProtocolKind &value) {
127+
out << getProtocolName(getKnownProtocolKind(value));
128+
}
129+
125130
namespace {
126131
enum class SearchPathKind : uint8_t {
127132
Import = 1 << 0,
@@ -6243,6 +6248,9 @@ BuiltinTupleDecl *ASTContext::getBuiltinTupleDecl() {
62436248
if (auto *proto = getProtocol(KnownProtocolKind::Copyable))
62446249
buildFakeExtension(proto);
62456250

6251+
if (auto *proto = getProtocol(KnownProtocolKind::Escapable))
6252+
buildFakeExtension(proto);
6253+
62466254
return result;
62476255
}
62486256

lib/AST/ASTDumper.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4348,6 +4348,9 @@ namespace {
43484348
case InvertibleProtocolKind::Copyable:
43494349
printFlag("inverse_copyable");
43504350
break;
4351+
case InvertibleProtocolKind::Escapable:
4352+
printFlag("inverse_escapable");
4353+
break;
43514354
}
43524355
}
43534356

lib/AST/ASTPrinter.cpp

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3367,8 +3367,9 @@ static bool usesFeatureFlowSensitiveConcurrencyCaptures(Decl *decl) {
33673367

33683368
/// \param isRelevantInverse the function used to inspect a mark corresponding
33693369
/// to an inverse to determine whether it "has" an inverse that we care about.
3370-
static bool hasInverseCopyable(
3370+
static bool hasInverse(
33713371
Decl *decl,
3372+
InvertibleProtocolKind ip,
33723373
std::function<bool(InverseMarking const&)> isRelevantInverse) {
33733374

33743375
auto getTypeDecl = [](Type type) -> TypeDecl* {
@@ -3381,37 +3382,38 @@ static bool hasInverseCopyable(
33813382

33823383
if (auto *extension = dyn_cast<ExtensionDecl>(decl)) {
33833384
if (auto *nominal = extension->getSelfNominalTypeDecl())
3384-
if (isRelevantInverse(nominal->getNoncopyableMarking()))
3385+
if (isRelevantInverse(nominal->getMarking(ip)))
33853386
return true;
33863387
}
33873388

33883389
if (auto typeDecl = dyn_cast<TypeDecl>(decl)) {
3389-
if (isRelevantInverse(typeDecl->getNoncopyableMarking()))
3390+
if (isRelevantInverse(typeDecl->getMarking(ip)))
33903391
return true;
33913392

33923393
// Check the protocol's associated types too.
33933394
if (auto proto = dyn_cast<ProtocolDecl>(decl)) {
3394-
auto hasNoncopyable = llvm::any_of(proto->getAssociatedTypeMembers(),
3395-
[&](AssociatedTypeDecl *assocTyDecl) {
3396-
return isRelevantInverse(assocTyDecl->getNoncopyableMarking());
3397-
});
3398-
if (hasNoncopyable)
3395+
auto hasInverse =
3396+
llvm::any_of(proto->getAssociatedTypeMembers(),
3397+
[&](AssociatedTypeDecl *assocTyDecl) {
3398+
return isRelevantInverse(assocTyDecl->getMarking(ip));
3399+
});
3400+
if (hasInverse)
33993401
return true;
34003402
}
34013403
}
34023404

34033405
if (auto value = dyn_cast<ValueDecl>(decl)) {
34043406
// Check for noncopyable types in the types of this declaration.
34053407
if (Type type = value->getInterfaceType()) {
3406-
bool hasNoncopyable = type.findIf([&](Type type) {
3408+
bool hasInverse = type.findIf([&](Type type) {
34073409
if (auto *typeDecl = getTypeDecl(type))
3408-
if (isRelevantInverse(typeDecl->getNoncopyableMarking()))
3410+
if (isRelevantInverse(typeDecl->getMarking(ip)))
34093411
return true;
34103412

34113413
return false;
34123414
});
34133415

3414-
if (hasNoncopyable)
3416+
if (hasInverse)
34153417
return true;
34163418
}
34173419
}
@@ -3420,7 +3422,8 @@ static bool hasInverseCopyable(
34203422
}
34213423

34223424
static bool usesFeatureMoveOnly(Decl *decl) {
3423-
return hasInverseCopyable(decl, [](auto &marking) -> bool {
3425+
return hasInverse(decl, InvertibleProtocolKind::Copyable,
3426+
[](auto &marking) -> bool {
34243427
return marking.getInverse().is(InverseMarking::Kind::LegacyExplicit);
34253428
});
34263429
}
@@ -3462,17 +3465,20 @@ static bool usesFeatureMoveOnlyPartialConsumption(Decl *decl) {
34623465
}
34633466

34643467
static bool usesFeatureNoncopyableGenerics(Decl *decl) {
3465-
return hasInverseCopyable(decl, [](auto &marking) -> bool {
3468+
auto checkMarking = [](auto &marking) -> bool {
34663469
switch (marking.getInverse().getKind()) {
34673470
case InverseMarking::Kind::None:
3468-
case InverseMarking::Kind::LegacyExplicit: // covered by MoveOnly
3471+
case InverseMarking::Kind::LegacyExplicit: // covered by other checks.
34693472
return false;
34703473

34713474
case InverseMarking::Kind::Explicit:
34723475
case InverseMarking::Kind::Inferred:
34733476
return true;
34743477
}
3475-
});
3478+
};
3479+
3480+
return hasInverse(decl, InvertibleProtocolKind::Copyable, checkMarking)
3481+
|| hasInverse(decl, InvertibleProtocolKind::Escapable, checkMarking);
34763482
}
34773483

34783484
static bool usesFeatureOneWayClosureParameters(Decl *decl) {

lib/AST/Decl.cpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3684,12 +3684,6 @@ bool ValueDecl::isFinal() const {
36843684
getAttrs().hasAttribute<FinalAttr>());
36853685
}
36863686

3687-
bool ValueDecl::isEscapable() const {
3688-
return evaluateOrDefault(getASTContext().evaluator,
3689-
IsEscapableRequest{const_cast<ValueDecl *>(this)},
3690-
!getAttrs().hasAttribute<NonEscapableAttr>());
3691-
}
3692-
36933687
bool ValueDecl::isDynamic() const {
36943688
ASTContext &ctx = getASTContext();
36953689
return evaluateOrDefault(ctx.evaluator,
@@ -4903,16 +4897,21 @@ GenericParameterReferenceInfo ValueDecl::findExistentialSelfReferences(
49034897
llvm::None);
49044898
}
49054899

4906-
InverseMarking TypeDecl::getNoncopyableMarking() const {
4900+
InverseMarking TypeDecl::getMarking(InvertibleProtocolKind ip) const {
49074901
return evaluateOrDefault(
49084902
getASTContext().evaluator,
4909-
NoncopyableAnnotationRequest{const_cast<TypeDecl *>(this)},
4903+
InvertibleAnnotationRequest{const_cast<TypeDecl *>(this), ip},
49104904
InverseMarking::forInverse(InverseMarking::Kind::None)
49114905
);
49124906
}
49134907

49144908
bool TypeDecl::canBeNoncopyable() const {
4915-
return getNoncopyableMarking().getInverse().isPresent();
4909+
return getMarking(InvertibleProtocolKind::Copyable).getInverse().isPresent();
4910+
}
4911+
4912+
bool TypeDecl::isEscapable() const {
4913+
auto escapable = getMarking(InvertibleProtocolKind::Escapable);
4914+
return !escapable.getInverse().isPresent();
49164915
}
49174916

49184917
Type TypeDecl::getDeclaredInterfaceType() const {
@@ -4926,6 +4925,7 @@ Type TypeDecl::getDeclaredInterfaceType() const {
49264925
return ErrorType::get(ctx);
49274926
return DependentMemberType::get(
49284927
selfTy, const_cast<AssociatedTypeDecl *>(ATD));
4928+
49294929
}
49304930

49314931
return getInterfaceType()->getMetatypeInstanceType();

0 commit comments

Comments
 (0)