Skip to content

Commit ad369e0

Browse files
committed
implement ~Copyable to suppress implicit conformance to Copyable
Also has been referred to as "without Copyable" See SE-390 for details, or read the discussion here: https://forums.swift.org/t/second-review-se-0390-noncopyable-structs-and-enums/63866
1 parent bfe2edc commit ad369e0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+786
-277
lines changed

docs/Generics/generics.tex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3107,7 +3107,7 @@ \section{Source Code Reference}\label{genericdeclsourceref}
31073107
An associated type declaration.
31083108
\begin{itemize}
31093109
\item \texttt{getTrailingWhereClause()} returns the associated type's trailing \texttt{where} clause, or \texttt{nullptr}.
3110-
\item \texttt{getInherited()} returns the associated type's inheritance clause.
3110+
\item \texttt{getAllInheritedEntries()} returns the associated type's inheritance clause.
31113111
\end{itemize}
31123112

31133113
Trailing \texttt{where} clauses and inheritance clauses are not preserved in serialized associated type declarations. Requirements on associated types are part of a protocol's requirement signature, so except when actually building the requirement signature, most code uses \texttt{getRequirementSignature()} from Section~\ref{genericsigsourceref} instead.

include/swift/AST/Decl.h

Lines changed: 68 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1471,13 +1471,33 @@ class ImportDecl final : public Decl,
14711471
/// An entry in the "inherited" list of a type or extension.
14721472
struct InheritedEntry : public TypeLoc {
14731473
/// Whether there was an @unchecked attribute.
1474-
bool isUnchecked = false;
1474+
bool isUnchecked;
14751475

1476+
/// Whether this entry represents the suppression of implicit conformance to
1477+
/// the type in this entry.
1478+
bool isSuppressed;
1479+
1480+
/// This constructor will automatically try to determine the "isUnchecked"
1481+
/// and "isSuppressed" statuses based on the \c typeLoc.
14761482
InheritedEntry(const TypeLoc &typeLoc);
14771483

1478-
InheritedEntry(const TypeLoc &typeLoc, bool isUnchecked)
1479-
: TypeLoc(typeLoc), isUnchecked(isUnchecked) { }
1484+
InheritedEntry(const TypeLoc &typeLoc, bool isUnchecked, bool isSuppressed)
1485+
: TypeLoc(typeLoc), isUnchecked(isUnchecked), isSuppressed(isSuppressed)
1486+
{}
1487+
};
1488+
1489+
// A predicate Callable used to filter a collection of InheritedEntry
1490+
struct InheritedEntryFilter {
1491+
bool WantSuppressed;
1492+
InheritedEntryFilter(bool wantSuppressed)
1493+
: WantSuppressed(wantSuppressed) {}
1494+
bool operator()(InheritedEntry result) const {
1495+
return result.isSuppressed == WantSuppressed;
1496+
}
14801497
};
1498+
using InheritedEntryIter =
1499+
llvm::filter_iterator<const InheritedEntry *, InheritedEntryFilter>;
1500+
using InheritedEntryRange = iterator_range<InheritedEntryIter>;
14811501

14821502
/// ExtensionDecl - This represents a type extension containing methods
14831503
/// associated with the type. This is not a ValueDecl and has no Type because
@@ -1591,12 +1611,26 @@ class ExtensionDecl final : public GenericContext, public Decl,
15911611
/// Repr would not be available if the extension was been loaded
15921612
/// from a serialized module.
15931613
TypeRepr *getExtendedTypeRepr() const { return ExtendedTypeRepr; }
1594-
1595-
/// Retrieve the set of protocols that this type inherits (i.e,
1596-
/// explicitly conforms to).
1597-
ArrayRef<InheritedEntry> getInherited() const { return Inherited; }
15981614

1599-
void setInherited(ArrayRef<InheritedEntry> i) { Inherited = i; }
1615+
/// Retrieve the list of all protocols that this type either inherits from
1616+
/// (i.e, explicitly conforms to) or is suppressing implicit conformance to.
1617+
ArrayRef<InheritedEntry> getAllInheritedEntries() const { return Inherited; }
1618+
1619+
void setAllInheritedEntries(ArrayRef<InheritedEntry> i) { Inherited = i; }
1620+
1621+
/// Retrieve an iterator range of protocols that this type is suppressing
1622+
/// implicit conformances to.
1623+
InheritedEntryRange getSuppressed() const {
1624+
return llvm::make_filter_range(getAllInheritedEntries(),
1625+
InheritedEntryFilter(/*wantSuppressed*/true));
1626+
}
1627+
1628+
/// Retrieve an iterator range of protocols that this type inherits (i.e,
1629+
/// explicitly conforms to).
1630+
InheritedEntryRange getInherited() const {
1631+
return llvm::make_filter_range(getAllInheritedEntries(),
1632+
InheritedEntryFilter(/*wantSuppressed*/false));
1633+
}
16001634

16011635
bool hasDefaultAccessLevel() const {
16021636
return Bits.ExtensionDecl.DefaultAndMaxAccessLevel != 0;
@@ -2451,18 +2485,18 @@ class ValueDecl : public Decl {
24512485
/// optional result.
24522486
unsigned isIUO : 1;
24532487

2454-
/// Whether the "isMoveOnly" bit has been computed yet.
2455-
unsigned isMoveOnlyComputed : 1;
2488+
/// Whether the "isNoncopyable" bit has been computed yet.
2489+
unsigned isNoncopyableComputed : 1;
24562490

2457-
/// Whether this declaration can not be copied and thus is move only.
2458-
unsigned isMoveOnly : 1;
2491+
/// Whether this declaration is noncopyable.
2492+
unsigned isNoncopyable : 1;
24592493
} LazySemanticInfo = { };
24602494

24612495
friend class DynamicallyReplacedDeclRequest;
24622496
friend class OverriddenDeclsRequest;
24632497
friend class IsObjCRequest;
24642498
friend class IsFinalRequest;
2465-
friend class IsMoveOnlyRequest;
2499+
friend class IsNoncopyableRequest;
24662500
friend class IsDynamicRequest;
24672501
friend class IsImplicitlyUnwrappedOptionalRequest;
24682502
friend class InterfaceTypeRequest;
@@ -2952,11 +2986,29 @@ class TypeDecl : public ValueDecl {
29522986
/// metatype.
29532987
Type getDeclaredInterfaceType() const;
29542988

2955-
/// Retrieve the set of protocols that this type inherits (i.e,
2989+
/// Retrieve the list of all protocols that this type either inherits from
2990+
/// (i.e, explicitly conforms to) or is suppressing implicit conformance to.
2991+
ArrayRef<InheritedEntry> getAllInheritedEntries() const { return Inherited; }
2992+
2993+
void setAllInheritedEntries(ArrayRef<InheritedEntry> i) { Inherited = i; }
2994+
2995+
/// Retrieve an iterator range of protocols that this type is suppressing
2996+
/// implicit conformances to.
2997+
InheritedEntryRange getSuppressed() const {
2998+
return llvm::make_filter_range(getAllInheritedEntries(),
2999+
InheritedEntryFilter(/*wantSuppressed*/true));
3000+
}
3001+
3002+
/// Retrieve an iterator range of protocols that this type inherits (i.e,
29563003
/// explicitly conforms to).
2957-
ArrayRef<InheritedEntry> getInherited() const { return Inherited; }
3004+
InheritedEntryRange getInherited() const {
3005+
return llvm::make_filter_range(getAllInheritedEntries(),
3006+
InheritedEntryFilter(/*wantSuppressed*/false));
3007+
}
29583008

2959-
void setInherited(ArrayRef<InheritedEntry> i) { Inherited = i; }
3009+
/// Does this decl suppress implicit conformance to the given protocol?
3010+
/// That is, it is "without KP"
3011+
bool isSuppressingConformance(KnownProtocolKind kp) const;
29603012

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

include/swift/AST/DiagnosticsSema.def

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6888,8 +6888,26 @@ ERROR(moveonly_cast,none,
68886888
"move-only types cannot be conditionally cast", ())
68896889
ERROR(moveonly_failable_init,none,
68906890
"move-only types cannot have failable initializers yet", ())
6891-
ERROR(moveonly_objc_enum_banned, none,
6892-
"@objc enums cannot be marked as move-only", ())
6891+
ERROR(noncopyable_objc_enum, none,
6892+
"@objc enums cannot be noncopyable", ())
6893+
6894+
//------------------------------------------------------------------------------
6895+
// MARK: Conformance suppression diagnostics
6896+
//------------------------------------------------------------------------------
6897+
6898+
ERROR(suppress_cannot_suppress,none,
6899+
"cannot suppress implicit conformance to %0", (Type))
6900+
6901+
ERROR(suppress_on_wrong_decl,none,
6902+
"cannot suppress conformance on %0", (DescriptiveDeclKind))
6903+
6904+
ERROR(suppress_duplicate,none,
6905+
"implicit conformance to %0 already suppressed", (Type))
6906+
NOTE(suppress_previously_here,none,
6907+
"%0 previously suppressed here", (Type))
6908+
6909+
ERROR(suppress_not_protocol,none,
6910+
"suppression of non-protocol type %0", (Type))
68936911

68946912
//------------------------------------------------------------------------------
68956913
// MARK: Type inference from default expressions
@@ -6948,17 +6966,21 @@ ERROR(concurrency_task_to_thread_model_global_actor_annotation,none,
69486966
"annotating a type with a global actor %0 is not permitted within %1",
69496967
(TypeRepr*, StringRef))
69506968

6951-
ERROR(moveOnly_not_allowed_here,none,
6952-
"'moveOnly' only applies to structs or enums", ())
6969+
ERROR(noncopyable_only_struct_enum,none,
6970+
"only structs or enums can be noncopyable", ())
69536971
ERROR(move_expression_not_passed_lvalue,none,
69546972
"'consume' can only be applied to lvalues", ())
69556973
ERROR(borrow_expression_not_passed_lvalue,none,
69566974
"'borrow' can only be applied to lvalues", ())
69576975

6958-
ERROR(moveOnly_requires_lexical_lifetimes,none,
6976+
ERROR(noncopyable_requires_sil_option,none,
69596977
"noncopyable types require lexical borrow scopes "
69606978
"(add -enable-lexical-borrow-scopes=true)", ())
69616979

6980+
ERROR(moveOnly_attr_deprecated,none,
6981+
"'@_moveOnly' attribute is deprecated; "
6982+
"use the ~Copyable constraint suppression instead", ())
6983+
69626984
//------------------------------------------------------------------------------
69636985
// MARK: #_hasSymbol
69646986
//------------------------------------------------------------------------------

include/swift/AST/NameLookup.h

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -602,15 +602,41 @@ SelfBounds getSelfBoundsFromWhereClause(
602602
/// given protocol or protocol extension.
603603
SelfBounds getSelfBoundsFromGenericSignature(const ExtensionDecl *extDecl);
604604

605+
/// Retrieve the InheritedEntry at the given \c index from among the list of
606+
/// all inherited entries.
607+
inline const InheritedEntry &getInheritedEntryAtIndex(
608+
llvm::PointerUnion<const TypeDecl *, const ExtensionDecl *> decl,
609+
unsigned index) {
610+
llvm::ArrayRef<InheritedEntry> allEntries;
611+
612+
if (auto typeDecl = decl.dyn_cast<const TypeDecl *>())
613+
allEntries = typeDecl->getAllInheritedEntries();
614+
else
615+
allEntries = decl.get<const ExtensionDecl *>()->getAllInheritedEntries();
616+
617+
return allEntries[index];
618+
}
619+
605620
/// Retrieve the TypeLoc at the given \c index from among the set of
606621
/// type declarations that are directly "inherited" by the given declaration.
607622
inline const TypeLoc &getInheritedTypeLocAtIndex(
608623
llvm::PointerUnion<const TypeDecl *, const ExtensionDecl *> decl,
609624
unsigned index) {
610-
if (auto typeDecl = decl.dyn_cast<const TypeDecl *>())
611-
return typeDecl->getInherited()[index];
625+
InheritedEntry const& entry = getInheritedEntryAtIndex(decl, index);
626+
627+
if (entry.isSuppressed) {
628+
#ifndef NDEBUG
629+
llvm::dbgs() << "index " << index << " of inherited entries of \n";
630+
if (auto td = decl.dyn_cast<const TypeDecl *>())
631+
td->dump(llvm::dbgs(), 1);
632+
else
633+
decl.dyn_cast<const ExtensionDecl *>()->dump(llvm::dbgs(), 1);
634+
llvm::dbgs() << "\n";
635+
#endif
636+
llvm_unreachable("index unexpectedly refers to a suppressed entry");
637+
}
612638

613-
return decl.get<const ExtensionDecl *>()->getInherited()[index];
639+
return entry;
614640
}
615641

616642
namespace namelookup {

include/swift/AST/TypeCheckRequests.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -404,9 +404,10 @@ class IsFinalRequest :
404404
void cacheResult(bool value) const;
405405
};
406406

407-
/// Determine whether the given declaration is 'moveOnly'.
408-
class IsMoveOnlyRequest
409-
: public SimpleRequest<IsMoveOnlyRequest, bool(ValueDecl *),
407+
/// Determine whether the given declaration is noncopyable (i.e., does not
408+
/// offer the ability to copy values of that type.)
409+
class IsNoncopyableRequest
410+
: public SimpleRequest<IsNoncopyableRequest, bool(ValueDecl *),
410411
RequestFlags::SeparatelyCached> {
411412
public:
412413
using SimpleRequest::SimpleRequest;

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ SWIFT_REQUEST(TypeChecker, IsDynamicRequest, bool(ValueDecl *),
207207
SeparatelyCached, NoLocationInfo)
208208
SWIFT_REQUEST(TypeChecker, IsFinalRequest, bool(ValueDecl *), SeparatelyCached,
209209
NoLocationInfo)
210-
SWIFT_REQUEST(TypeChecker, IsMoveOnlyRequest, bool(ValueDecl *), SeparatelyCached,
210+
SWIFT_REQUEST(TypeChecker, IsNoncopyableRequest, bool(ValueDecl *), SeparatelyCached,
211211
NoLocationInfo)
212212
SWIFT_REQUEST(TypeChecker, IsGetterMutatingRequest, bool(AbstractStorageDecl *),
213213
SeparatelyCached, NoLocationInfo)

include/swift/AST/TypeRepr.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1066,7 +1066,8 @@ class SpecifierTypeRepr : public TypeRepr {
10661066
static bool classof(const TypeRepr *T) {
10671067
return T->getKind() == TypeReprKind::Ownership ||
10681068
T->getKind() == TypeReprKind::Isolated ||
1069-
T->getKind() == TypeReprKind::CompileTimeConst;
1069+
T->getKind() == TypeReprKind::CompileTimeConst ||
1070+
T->getKind() == TypeReprKind::Suppressed;
10701071
}
10711072
static bool classof(const SpecifierTypeRepr *T) { return true; }
10721073

@@ -1106,6 +1107,22 @@ class OwnershipTypeRepr : public SpecifierTypeRepr {
11061107
}
11071108
static bool classof(const OwnershipTypeRepr *T) { return true; }
11081109
};
1110+
1111+
/// A representation of a suppressed conformance to a type. That is, "without T"
1112+
/// means "implicit conformance to T is suppressed".
1113+
/// \code
1114+
/// x : ~Copyable
1115+
/// \endcode
1116+
class SuppressedTypeRepr : public SpecifierTypeRepr {
1117+
public:
1118+
SuppressedTypeRepr(TypeRepr *Base, SourceLoc WithoutLoc)
1119+
: SpecifierTypeRepr(TypeReprKind::Suppressed, Base, WithoutLoc) {}
1120+
1121+
static bool classof(const TypeRepr *T) {
1122+
return T->getKind() == TypeReprKind::Suppressed;
1123+
}
1124+
static bool classof(const SuppressedTypeRepr *T) { return true; }
1125+
};
11091126

11101127
/// An 'isolated' type.
11111128
/// \code
@@ -1420,6 +1437,7 @@ inline bool TypeRepr::isSimple() const {
14201437
case TypeReprKind::NamedOpaqueReturn:
14211438
case TypeReprKind::Existential:
14221439
case TypeReprKind::PackElement:
1440+
case TypeReprKind::Suppressed:
14231441
return false;
14241442
case TypeReprKind::SimpleIdent:
14251443
case TypeReprKind::GenericIdent:

include/swift/AST/TypeReprNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ ABSTRACT_TYPEREPR(Specifier, TypeRepr)
7272
SPECIFIER_TYPEREPR(Ownership, SpecifierTypeRepr)
7373
SPECIFIER_TYPEREPR(Isolated, SpecifierTypeRepr)
7474
SPECIFIER_TYPEREPR(CompileTimeConst, SpecifierTypeRepr)
75+
SPECIFIER_TYPEREPR(Suppressed, SpecifierTypeRepr)
7576
TYPEREPR(Fixed, TypeRepr)
7677
TYPEREPR(SILBox, TypeRepr)
7778
LAST_TYPEREPR(SILBox)

include/swift/Parse/Parser.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,9 +1194,20 @@ class Parser {
11941194

11951195
ParserResult<ImportDecl> parseDeclImport(ParseDeclOptions Flags,
11961196
DeclAttributes &Attributes);
1197+
1198+
/// Flags that control the parsing of inheritance clauses.
1199+
enum ParseInheritanceFlags {
1200+
PI_Default = 0,
1201+
PI_AllowClassRequirement = 1 << 1,
1202+
PI_AllowAnyObject = 1 << 2,
1203+
PI_AllowSuppression = 1 << 3,
1204+
};
1205+
1206+
using ParseInheritanceOptions = OptionSet<ParseInheritanceFlags>;
1207+
11971208
ParserStatus parseInheritance(SmallVectorImpl<InheritedEntry> &Inherited,
1198-
bool allowClassRequirement,
1199-
bool allowAnyObject);
1209+
ParseInheritanceOptions options);
1210+
12001211
ParserStatus parseDeclItem(bool &PreviousHadSemi,
12011212
ParseDeclOptions Options,
12021213
llvm::function_ref<void(Decl*)> handler);

include/swift/Parse/Token.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,10 @@ class Token {
124124
return !isEllipsis();
125125
}
126126

127+
bool isTilde() const {
128+
return isAnyOperator() && Text == "~";
129+
}
130+
127131
/// Determine whether this token occurred at the start of a line.
128132
bool isAtStartOfLine() const { return AtStartOfLine; }
129133

lib/APIDigester/ModuleAnalyzerNodes.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1813,7 +1813,7 @@ SwiftDeclCollector::constructExternalExtensionNode(NominalTypeDecl *NTD,
18131813
// inherit from other internal protocols. It should also consider
18141814
// conditional conformances with internal requirements that are still
18151815
// part of the ABI.
1816-
if (!Ext->getInherited().empty())
1816+
if (!Ext->getAllInheritedEntries().empty())
18171817
anyConformancesAdded = true;
18181818
}
18191819

lib/AST/ASTDumper.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,11 @@ namespace {
574574
return;
575575
OS << " inherits: ";
576576
interleave(Inherited,
577-
[&](InheritedEntry Super) { Super.getType().print(OS); },
577+
[&](InheritedEntry Super) {
578+
if (Super.isSuppressed)
579+
OS << "~";
580+
Super.getType().print(OS);
581+
},
578582
[&] { OS << ", "; });
579583
}
580584

@@ -777,13 +781,13 @@ namespace {
777781
switch (IDC->getIterableContextKind()) {
778782
case IterableDeclContextKind::NominalTypeDecl: {
779783
const auto NTD = cast<NominalTypeDecl>(IDC);
780-
printInherited(NTD->getInherited());
784+
printInherited(NTD->getAllInheritedEntries());
781785
printWhereRequirements(NTD);
782786
break;
783787
}
784788
case IterableDeclContextKind::ExtensionDecl:
785789
const auto ED = cast<ExtensionDecl>(IDC);
786-
printInherited(ED->getInherited());
790+
printInherited(ED->getAllInheritedEntries());
787791
printWhereRequirements(ED);
788792
break;
789793
}
@@ -3270,6 +3274,12 @@ class PrintTypeRepr : public TypeReprVisitor<PrintTypeRepr> {
32703274
printRec(T->getBase());
32713275
PrintWithColorRAII(OS, ParenthesisColor) << ')';
32723276
}
3277+
3278+
void visitSuppressedTypeRepr(SuppressedTypeRepr *T) {
3279+
printCommon("suppressing") << '\n';
3280+
printRec(T->getBase());
3281+
PrintWithColorRAII(OS, ParenthesisColor) << ')';
3282+
}
32733283

32743284
void visitIsolatedTypeRepr(IsolatedTypeRepr *T) {
32753285
printCommon("isolated") << '\n';

0 commit comments

Comments
 (0)