Skip to content

Commit d5f2d54

Browse files
committed
[Sema] initial overhaul of isNoncopyable
This implementation has the function execute a request to scan the inheritance clause of non-protocol nominals for a `~Copyable`. For protocols, we look in the requirement signature. This isn't our final state, as the GenericEnvironment needs to be queried in general to determine of a Type is noncopyable. So for now checking for a `~Copyable` only makes sense for Decls.
1 parent 578db55 commit d5f2d54

21 files changed

+347
-46
lines changed

include/swift/AST/Decl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3145,7 +3145,8 @@ class TypeDecl : public ValueDecl {
31453145

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

3148-
/// Is this declaration noncopyable?
3148+
/// Is this type _always_ noncopyable? Will answer 'false' if the type is
3149+
/// conditionally copyable.
31493150
bool isNoncopyable() const;
31503151

31513152
static bool classof(const Decl *D) {

include/swift/AST/DiagnosticsSema.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2392,6 +2392,10 @@ ERROR(inferred_opaque_type,none,
23922392
// Inverse Constraints
23932393
ERROR(inverse_type_not_invertible,none,
23942394
"type %0 is not invertible", (Type))
2395+
ERROR(inverse_duplicate,none,
2396+
"duplicate inverse constraint", ())
2397+
NOTE(inverse_duplicate_previous,none,
2398+
"previous inverse constraint here", ())
23952399

23962400
// Extensions
23972401
ERROR(non_nominal_extension,none,
@@ -7445,6 +7449,9 @@ ERROR(accessor_macro_not_single_var, none,
74457449
// MARK: Noncopyable Types Diagnostics
74467450
//------------------------------------------------------------------------------
74477451

7452+
ERROR(noncopyable_class, none,
7453+
"classes cannot be noncopyable",
7454+
())
74487455
ERROR(noncopyable_within_copyable, none,
74497456
"%kind0 cannot contain a noncopyable type without also being noncopyable",
74507457
(const ValueDecl *))

include/swift/AST/TypeCheckRequests.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3779,11 +3779,11 @@ class SynthesizeMainFunctionRequest
37793779
bool isCached() const { return true; }
37803780
};
37813781

3782-
/// Retrieve the implicit conformance for the given nominal type to
3783-
/// the Sendable protocol.
3784-
class GetImplicitSendableRequest :
3785-
public SimpleRequest<GetImplicitSendableRequest,
3786-
ProtocolConformance *(NominalTypeDecl *),
3782+
/// Compute the implicit conformance for the given nominal type to
3783+
/// an known protocol, if implicit conformances are permitted.
3784+
class ImplicitKnownProtocolConformanceRequest :
3785+
public SimpleRequest<ImplicitKnownProtocolConformanceRequest,
3786+
ProtocolConformance *(NominalTypeDecl *, KnownProtocolKind),
37873787
RequestFlags::Cached> {
37883788
public:
37893789
using SimpleRequest::SimpleRequest;
@@ -3792,7 +3792,7 @@ class GetImplicitSendableRequest :
37923792
friend SimpleRequest;
37933793

37943794
ProtocolConformance *evaluate(
3795-
Evaluator &evaluator, NominalTypeDecl *nominal) const;
3795+
Evaluator &evaluator, NominalTypeDecl *nominal, KnownProtocolKind kp) const;
37963796

37973797
public:
37983798
// Caching

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -426,8 +426,8 @@ SWIFT_REQUEST(TypeChecker, SimpleDidSetRequest,
426426
bool(AccessorDecl *), Cached, NoLocationInfo)
427427
SWIFT_REQUEST(TypeChecker, SynthesizeMainFunctionRequest,
428428
FuncDecl *(Decl *), Cached, NoLocationInfo)
429-
SWIFT_REQUEST(TypeChecker, GetImplicitSendableRequest,
430-
ProtocolConformance *(NominalTypeDecl *),
429+
SWIFT_REQUEST(TypeChecker, ImplicitKnownProtocolConformanceRequest,
430+
ProtocolConformance *(NominalTypeDecl *, KnownProtocolKind),
431431
Cached, NoLocationInfo)
432432
SWIFT_REQUEST(TypeChecker, RenamedDeclRequest,
433433
ValueDecl *(const ValueDecl *, const AvailableAttr *),

include/swift/AST/Types.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -928,6 +928,9 @@ class alignas(1 << TypeAlignInBits) TypeBase
928928
return getAnyBufferPointerElementType(Ignore);
929929
}
930930

931+
/// If this type is a known protocol, return its kind.
932+
llvm::Optional<KnownProtocolKind> getKnownProtocol();
933+
931934
/// Determine whether the given type is "specialized", meaning that
932935
/// it involves generic types for which generic arguments have been provided.
933936
/// For example, the types Vector<Int> and Vector<Int>.Element are both
@@ -7333,6 +7336,10 @@ inline GenericTypeDecl *TypeBase::getAnyGeneric() {
73337336
return getCanonicalType().getAnyGeneric();
73347337
}
73357338

7339+
//inline TypeDecl *TypeBase::getAnyTypeDecl() {
7340+
// return getCanonicalType().getAnyTypeDecl();
7341+
//}
7342+
73367343
inline bool TypeBase::isBuiltinIntegerType(unsigned n) {
73377344
if (auto intTy = dyn_cast<BuiltinIntegerType>(getCanonicalType()))
73387345
return intTy->getWidth().isFixedWidth()

lib/AST/Decl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4838,7 +4838,7 @@ GenericParameterReferenceInfo ValueDecl::findExistentialSelfReferences(
48384838
bool TypeDecl::isNoncopyable() const {
48394839
return evaluateOrDefault(getASTContext().evaluator,
48404840
IsNoncopyableRequest{const_cast<TypeDecl *>(this)},
4841-
getAttrs().hasAttribute<MoveOnlyAttr>());
4841+
true); // default to true for safety
48424842
}
48434843

48444844
Type TypeDecl::getDeclaredInterfaceType() const {

lib/AST/Module.cpp

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1681,12 +1681,12 @@ ProtocolConformanceRef ModuleDecl::lookupConformance(Type type,
16811681
ProtocolDecl *protocol,
16821682
bool allowMissing) {
16831683
// If we are recursively checking for implicit conformance of a nominal
1684-
// type to Sendable, fail without evaluating this request. This
1684+
// type to a KnownProtocol, fail without evaluating this request. This
16851685
// squashes cycles.
16861686
LookupConformanceInModuleRequest request{{this, type, protocol}};
1687-
if (protocol->isSpecificProtocol(KnownProtocolKind::Sendable)) {
1687+
if (auto kp = protocol->getKnownProtocolKind()) {
16881688
if (auto nominal = type->getAnyNominal()) {
1689-
GetImplicitSendableRequest icvRequest{nominal};
1689+
ImplicitKnownProtocolConformanceRequest icvRequest{nominal, *kp};
16901690
if (getASTContext().evaluator.hasActiveRequest(icvRequest) ||
16911691
getASTContext().evaluator.hasActiveRequest(request))
16921692
return ProtocolConformanceRef::forInvalid();
@@ -1972,7 +1972,8 @@ LookupConformanceInModuleRequest::evaluate(
19721972
if (!nominal->lookupConformance(protocol, conformances)) {
19731973
if (protocol->isSpecificProtocol(KnownProtocolKind::Sendable)) {
19741974
// Try to infer Sendable conformance.
1975-
GetImplicitSendableRequest cvRequest{nominal};
1975+
ImplicitKnownProtocolConformanceRequest
1976+
cvRequest{nominal, KnownProtocolKind::Sendable};
19761977
if (auto conformance = evaluateOrDefault(
19771978
ctx.evaluator, cvRequest, nullptr)) {
19781979
conformances.clear();
@@ -2001,16 +2002,15 @@ LookupConformanceInModuleRequest::evaluate(
20012002
return ProtocolConformanceRef::forMissingOrInvalid(type, protocol);
20022003
}
20032004
} else if (protocol->isSpecificProtocol(KnownProtocolKind::Copyable)) {
2004-
// Only move-only nominals are not Copyable
2005-
if (nominal->isNoncopyable()) {
2006-
return ProtocolConformanceRef::forInvalid();
2005+
// Try to infer Copyable conformance.
2006+
ImplicitKnownProtocolConformanceRequest
2007+
cvRequest{nominal, KnownProtocolKind::Copyable};
2008+
if (auto conformance = evaluateOrDefault(
2009+
ctx.evaluator, cvRequest, nullptr)) {
2010+
conformances.clear();
2011+
conformances.push_back(conformance);
20072012
} else {
2008-
// Specifically do not create a concrete conformance to Copyable. At
2009-
// this stage, we don't even want Copyable to appear in swiftinterface
2010-
// files, which will happen for a marker protocol that's registered
2011-
// in a nominal type's conformance table. We can reconsider this
2012-
// decision later once there's a clearer picture of noncopyable generics
2013-
return ProtocolConformanceRef(protocol);
2013+
return ProtocolConformanceRef::forMissingOrInvalid(type, protocol);
20142014
}
20152015
} else {
20162016
// Was unable to infer the missing conformance.

lib/AST/ProtocolConformance.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,6 +1211,9 @@ static SmallVector<ProtocolConformance *, 2> findSynthesizedConformances(
12111211
// Concrete types may synthesize some conformances
12121212
if (!isa<ProtocolDecl>(nominal)) {
12131213
trySynthesize(KnownProtocolKind::Sendable);
1214+
1215+
if (nominal->getASTContext().LangOpts.hasFeature(Feature::NoncopyableGenerics))
1216+
trySynthesize(KnownProtocolKind::Copyable);
12141217
}
12151218

12161219
/// Distributed actors can synthesize Encodable/Decodable, so look for those

lib/AST/Type.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ bool TypeBase::isMarkerExistential() {
158158
}
159159

160160
bool TypeBase::isNoncopyable() {
161+
// FIXME: we need to support the full spectrum of TypeDecls here.
161162
if (auto *nom = getAnyNominal())
162163
return nom->isNoncopyable();
163164

@@ -471,6 +472,14 @@ bool TypeBase::isDistributedActor() {
471472
return false;
472473
}
473474

475+
llvm::Optional<KnownProtocolKind> TypeBase::getKnownProtocol() {
476+
if (auto protoTy = this->castTo<ProtocolType>())
477+
if (auto protoDecl = protoTy->getDecl())
478+
return protoDecl->getKnownProtocolKind();
479+
480+
return llvm::None;
481+
}
482+
474483
bool TypeBase::isSpecialized() {
475484
Type t = getCanonicalType();
476485

lib/Sema/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ add_swift_host_library(swiftSema STATIC
5959
TypeCheckExpr.cpp
6060
TypeCheckExprObjC.cpp
6161
TypeCheckGeneric.cpp
62+
TypeCheckInvertible.cpp
6263
TypeCheckMacros.cpp
6364
TypeCheckNameLookup.cpp
6465
TypeCheckPattern.cpp

0 commit comments

Comments
 (0)