Skip to content

Noncopyable means no conformance to Copyable #68818

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Oct 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 25 additions & 10 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1596,6 +1596,9 @@ class InheritedTypes {
size_t size() const { return Entries.size(); }
IntRange<size_t> const getIndices() { return indices(Entries); }

/// Returns the ASTContext associated with the wrapped declaration.
ASTContext &getASTContext() const;

/// Returns the `TypeRepr *` for the entry of the inheritance clause at the
/// given index.
TypeRepr *getTypeRepr(unsigned i) const { return Entries[i].getTypeRepr(); }
Expand All @@ -1615,6 +1618,10 @@ class InheritedTypes {
/// NOTE: The `Type` associated with the entry may not be resolved yet.
const InheritedEntry &getEntry(unsigned i) const { return Entries[i]; }

// Retrieve the location of the colon character introducing the inheritance
// clause.
SourceLoc getColonLoc() const;

/// Returns the source location of the beginning of the inheritance clause.
SourceLoc getStartLoc() const {
return getEntries().front().getSourceRange().Start;
Expand All @@ -1624,6 +1631,10 @@ class InheritedTypes {
SourceLoc getEndLoc() const {
return getEntries().back().getSourceRange().End;
}

/// Compute the SourceRange to be used when removing entry \c i from the
/// inheritance clause. Accounts for commas and colons as-needed.
SourceRange getRemovalRange(unsigned i) const;
};

/// ExtensionDecl - This represents a type extension containing methods
Expand Down Expand Up @@ -2606,12 +2617,6 @@ class ValueDecl : public Decl {
/// optional result.
unsigned isIUO : 1;

/// Whether the "isMoveOnly" bit has been computed yet.
unsigned isMoveOnlyComputed : 1;

/// Whether this declaration can not be copied and thus is move only.
unsigned isMoveOnly : 1;

/// Whether the "isEscapable" bit has been computed yet.
unsigned isEscapable : 1;

Expand All @@ -2623,7 +2628,6 @@ class ValueDecl : public Decl {
friend class OverriddenDeclsRequest;
friend class IsObjCRequest;
friend class IsFinalRequest;
friend class IsMoveOnlyRequest;
friend class IsEscapableRequest;
friend class IsDynamicRequest;
friend class IsImplicitlyUnwrappedOptionalRequest;
Expand Down Expand Up @@ -2927,9 +2931,6 @@ class ValueDecl : public Decl {
/// Is this declaration 'final'?
bool isFinal() const;

/// Is this declaration 'moveOnly'?
bool isMoveOnly() const;

/// Is this declaration escapable?
bool isEscapable() const;

Expand Down Expand Up @@ -3105,8 +3106,18 @@ class ValueDecl : public Decl {

/// This is a common base class for declarations which declare a type.
class TypeDecl : public ValueDecl {
private:
ArrayRef<InheritedEntry> Inherited;

struct {
/// Whether the "hasNoncopyableAnnotation" bit has been computed yet.
unsigned isNoncopyableAnnotationComputed : 1;

/// Whether this declaration had a noncopyable inverse written somewhere.
unsigned hasNoncopyableAnnotation : 1;
} LazySemanticInfo = { };
friend class HasNoncopyableAnnotationRequest;

protected:
TypeDecl(DeclKind K, llvm::PointerUnion<DeclContext *, ASTContext *> context,
Identifier name, SourceLoc NameLoc,
Expand Down Expand Up @@ -3134,6 +3145,10 @@ class TypeDecl : public ValueDecl {

void setInherited(ArrayRef<InheritedEntry> i) { Inherited = i; }

/// Is this type _always_ noncopyable? Will answer 'false' if the type is
/// conditionally copyable.
bool isNoncopyable() const;

static bool classof(const Decl *D) {
return D->getKind() >= DeclKind::First_TypeDecl &&
D->getKind() <= DeclKind::Last_TypeDecl;
Expand Down
31 changes: 26 additions & 5 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -2392,6 +2392,10 @@ ERROR(inferred_opaque_type,none,
// Inverse Constraints
ERROR(inverse_type_not_invertible,none,
"type %0 is not invertible", (Type))
ERROR(inverse_duplicate,none,
"duplicate inverse constraint", ())
NOTE(inverse_duplicate_previous,none,
"previous inverse constraint here", ())

// Extensions
ERROR(non_nominal_extension,none,
Expand Down Expand Up @@ -7445,6 +7449,28 @@ ERROR(accessor_macro_not_single_var, none,
// MARK: Noncopyable Types Diagnostics
//------------------------------------------------------------------------------

ERROR(noncopyable_class, none,
"classes cannot be noncopyable",
())
ERROR(noncopyable_type_member_in_copyable,none,
"%select{stored property %2|associated value %2}1 of "
"'Copyable'-conforming %kind3 has noncopyable type %0",
(Type, bool, DeclName, const ValueDecl *))
NOTE(add_inverse_for_containment,none,
"consider removing implicit '%1' conformance from %kind0",
(const ValueDecl *, StringRef))
NOTE(remove_inverse_on_generic_parameter_for_conformance,none,
"consider removing '~%1' from generic parameter %0 so it conforms to the '%1' protocol",
(Type, StringRef))
NOTE(remove_inverse_on_nominal_for_conformance,none,
"consider removing '~%1' from %kind0 so it conforms to the '%1' protocol",
(const ValueDecl *, StringRef))
NOTE(add_explicit_protocol_for_conformance,none,
"consider making %kind0 explicitly conform to the '%1' protocol",
(const ValueDecl *, StringRef))

// -- older ones below --

ERROR(noncopyable_within_copyable, none,
"%kind0 cannot contain a noncopyable type without also being noncopyable",
(const ValueDecl *))
Expand All @@ -7460,11 +7486,6 @@ ERROR(noncopyable_parameter_subscript_unsupported, none,
"subscripts cannot have noncopyable parameters yet", ())
NOTE(noncopyable_parameter_ownership_suggestion, none,
"add '%0' %1", (StringRef, StringRef))
ERROR(ownership_specifier_copyable,none,
"copyable types cannot be 'consuming' or 'borrowing' yet", ())
ERROR(self_ownership_specifier_copyable,none,
"%0 is not yet valid on %1s of a copyable type",
(SelfAccessKind, DescriptiveDeclKind))
ERROR(ownership_specifier_nonescaping_closure,none,
"'%0' cannot be applied to nonescaping closure", (StringRef))
ERROR(noncopyable_generics, none,
Expand Down
41 changes: 30 additions & 11 deletions include/swift/AST/TypeCheckRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -407,9 +407,10 @@ class IsFinalRequest :
void cacheResult(bool value) const;
};

/// Determine whether the given declaration is 'moveOnly'.
class IsMoveOnlyRequest
: public SimpleRequest<IsMoveOnlyRequest, bool(ValueDecl *),
/// Determine whether the given declaration has any markings that would cause it
/// to not have an implicit, unconditional conformance to Copyable.
class HasNoncopyableAnnotationRequest
: public SimpleRequest<HasNoncopyableAnnotationRequest, bool(TypeDecl *),
RequestFlags::SeparatelyCached> {
public:
using SimpleRequest::SimpleRequest;
Expand All @@ -418,7 +419,7 @@ class IsMoveOnlyRequest
friend SimpleRequest;

// Evaluation.
bool evaluate(Evaluator &evaluator, ValueDecl *decl) const;
bool evaluate(Evaluator &evaluator, TypeDecl *decl) const;

public:
// Separate caching.
Expand All @@ -427,7 +428,6 @@ class IsMoveOnlyRequest
void cacheResult(bool value) const;
};


/// Determine whether the given declaration is escapable.
class IsEscapableRequest
: public SimpleRequest<IsEscapableRequest, bool(ValueDecl *),
Expand All @@ -448,6 +448,25 @@ class IsEscapableRequest
void cacheResult(bool value) const;
};

/// Determine whether the given type is noncopyable. Assumes type parameters
/// have become archetypes.
class IsNoncopyableRequest
: public SimpleRequest<IsNoncopyableRequest, bool(CanType),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;

private:
friend SimpleRequest;

// Evaluation.
bool evaluate(Evaluator &evaluator, CanType type) const;

public:
// Caching.
bool isCached() const { return true; }
};

/// Determine whether the given declaration is 'dynamic''.
class IsDynamicRequest :
public SimpleRequest<IsDynamicRequest,
Expand Down Expand Up @@ -3779,11 +3798,11 @@ class SynthesizeMainFunctionRequest
bool isCached() const { return true; }
};

/// Retrieve the implicit conformance for the given nominal type to
/// the Sendable protocol.
class GetImplicitSendableRequest :
public SimpleRequest<GetImplicitSendableRequest,
ProtocolConformance *(NominalTypeDecl *),
/// Compute the implicit conformance for the given nominal type to
/// an known protocol, if implicit conformances are permitted.
class ImplicitKnownProtocolConformanceRequest :
public SimpleRequest<ImplicitKnownProtocolConformanceRequest,
ProtocolConformance *(NominalTypeDecl *, KnownProtocolKind),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;
Expand All @@ -3792,7 +3811,7 @@ class GetImplicitSendableRequest :
friend SimpleRequest;

ProtocolConformance *evaluate(
Evaluator &evaluator, NominalTypeDecl *nominal) const;
Evaluator &evaluator, NominalTypeDecl *nominal, KnownProtocolKind kp) const;

public:
// Caching
Expand Down
9 changes: 6 additions & 3 deletions include/swift/AST/TypeCheckerTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,11 @@ SWIFT_REQUEST(TypeChecker, IsDynamicRequest, bool(ValueDecl *),
SeparatelyCached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, IsFinalRequest, bool(ValueDecl *), SeparatelyCached,
NoLocationInfo)
SWIFT_REQUEST(TypeChecker, IsMoveOnlyRequest, bool(ValueDecl *), SeparatelyCached,
SWIFT_REQUEST(TypeChecker, HasNoncopyableAnnotationRequest, bool(TypeDecl *), SeparatelyCached,
NoLocationInfo)
SWIFT_REQUEST(TypeChecker, IsNoncopyableRequest,
bool (CanType),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, IsEscapableRequest, bool(ValueDecl *),
SeparatelyCached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, IsGetterMutatingRequest, bool(AbstractStorageDecl *),
Expand Down Expand Up @@ -426,8 +429,8 @@ SWIFT_REQUEST(TypeChecker, SimpleDidSetRequest,
bool(AccessorDecl *), Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, SynthesizeMainFunctionRequest,
FuncDecl *(Decl *), Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, GetImplicitSendableRequest,
ProtocolConformance *(NominalTypeDecl *),
SWIFT_REQUEST(TypeChecker, ImplicitKnownProtocolConformanceRequest,
ProtocolConformance *(NominalTypeDecl *, KnownProtocolKind),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, RenamedDeclRequest,
ValueDecl *(const ValueDecl *, const AvailableAttr *),
Expand Down
2 changes: 1 addition & 1 deletion include/swift/AST/TypeRepr.h
Original file line number Diff line number Diff line change
Expand Up @@ -1325,7 +1325,7 @@ class ExistentialTypeRepr: public TypeRepr {
friend class TypeRepr;
};

/// A type repr represeting the inverse of some constraint. For example,
/// A type repr representing the inverse of some constraint. For example,
/// ~Copyable
/// where `Copyable` is the constraint type.
class InverseTypeRepr : public TypeRepr {
Expand Down
13 changes: 12 additions & 1 deletion include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ class ProtocolConformance;
enum PointerTypeKind : unsigned;
struct ValueOwnershipKind;
class ErrorExpr;
enum class KnownProtocolKind : uint8_t;

typedef CanTypeWrapper<SILFunctionType> CanSILFunctionType;

Expand Down Expand Up @@ -636,9 +637,12 @@ class alignas(1 << TypeAlignInBits) TypeBase

bool isPlaceholder();

/// Returns true if this is a noncopyable type.
/// DEPRECIATED: Returns true if this is a noncopyable type.
bool isNoncopyable();

/// Returns true if this type lacks conformance to Copyable in the context.
bool isNoncopyable(const DeclContext *dc);

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

Expand Down Expand Up @@ -928,6 +932,9 @@ class alignas(1 << TypeAlignInBits) TypeBase
return getAnyBufferPointerElementType(Ignore);
}

/// If this type is a known protocol, return its kind.
llvm::Optional<KnownProtocolKind> getKnownProtocol();

/// Determine whether the given type is "specialized", meaning that
/// it involves generic types for which generic arguments have been provided.
/// For example, the types Vector<Int> and Vector<Int>.Element are both
Expand Down Expand Up @@ -7333,6 +7340,10 @@ inline GenericTypeDecl *TypeBase::getAnyGeneric() {
return getCanonicalType().getAnyGeneric();
}

//inline TypeDecl *TypeBase::getAnyTypeDecl() {
// return getCanonicalType().getAnyTypeDecl();
//}

inline bool TypeBase::isBuiltinIntegerType(unsigned n) {
if (auto intTy = dyn_cast<BuiltinIntegerType>(getCanonicalType()))
return intTy->getWidth().isFixedWidth()
Expand Down
11 changes: 11 additions & 0 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6174,6 +6174,17 @@ BuiltinTupleDecl *ASTContext::getBuiltinTupleDecl() {
result = new (*this) BuiltinTupleDecl(Id_TheTupleType, dc);
result->setAccess(AccessLevel::Public);

// Avoid going through InferredGenericSignatureRequest and directly set the
// generic signature to <each Element>
{
GenericParamList *list = result->getGenericParams();
assert(list->size() == 1);
auto paramTy = (*list->begin())->getDeclaredInterfaceType()
->castTo<GenericTypeParamType>();
auto baseSig = GenericSignature::get({paramTy}, {});
result->setGenericSignature(baseSig);
}

// Cook up conditional conformances to Sendable and Copyable.
auto buildFakeExtension = [&](ProtocolDecl *proto) {
auto protoTy = proto->getDeclaredInterfaceType();
Expand Down
10 changes: 6 additions & 4 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3327,14 +3327,16 @@ static bool usesFeatureFlowSensitiveConcurrencyCaptures(Decl *decl) {
static bool usesFeatureMoveOnly(Decl *decl) {
if (auto *extension = dyn_cast<ExtensionDecl>(decl)) {
if (auto *nominal = extension->getSelfNominalTypeDecl())
if (nominal->isMoveOnly())
if (nominal->isNoncopyable())
return true;
}

if (auto value = dyn_cast<ValueDecl>(decl)) {
if (value->isMoveOnly())
return true;
if (auto typeDecl = dyn_cast<TypeDecl>(decl)) {
if (typeDecl->isNoncopyable())
return true;
}

if (auto value = dyn_cast<ValueDecl>(decl)) {
// Check for move-only types in the types of this declaration.
if (Type type = value->getInterfaceType()) {
bool hasMoveOnly = type.findIf([](Type type) {
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/ASTVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3238,7 +3238,7 @@ class Verifier : public ASTWalker {
PrettyStackTraceDecl debugStack("verifying DestructorDecl", DD);

auto *ND = DD->getDeclContext()->getSelfNominalTypeDecl();
if (!isa<ClassDecl>(ND) && !ND->isMoveOnly() && !DD->isInvalid()) {
if (!isa<ClassDecl>(ND) && !ND->isNoncopyable() && !DD->isInvalid()) {
Out << "DestructorDecls outside classes/move only types should be "
"marked invalid\n";
abort();
Expand Down
3 changes: 2 additions & 1 deletion lib/AST/ConformanceLookupTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -848,7 +848,8 @@ DeclContext *ConformanceLookupTable::getConformingContext(
const auto &superclassConformances =
superclassDecl->ConformanceTable->Conformances[protocol];
if (superclassConformances.empty()) {
assert(protocol->isSpecificProtocol(KnownProtocolKind::Sendable));
assert(protocol->isSpecificProtocol(KnownProtocolKind::Sendable) ||
protocol->isSpecificProtocol(KnownProtocolKind::Copyable));

// Go dig for a superclass that does conform to Sendable.
// FIXME: This is a hack because the inherited conformances aren't
Expand Down
Loading