Skip to content

Commit 7cb31a2

Browse files
committed
[Generics] ~Copyable in inheritance clauses
Have `~Copyable` change the generic signature of a generic type param, protocol, or associated type if written in the inheritance clause position.
1 parent 0c23e66 commit 7cb31a2

File tree

5 files changed

+40
-11
lines changed

5 files changed

+40
-11
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2349,6 +2349,10 @@ ERROR(inferred_opaque_type,none,
23492349
"property definition has inferred type %0, involving the 'some' "
23502350
"return type of another declaration", (Type))
23512351

2352+
// Inverse Constraints
2353+
ERROR(inverse_type_not_invertable,none,
2354+
"type %0 is not invertable", (Type))
2355+
23522356
// Extensions
23532357
ERROR(non_nominal_extension,none,
23542358
"non-nominal type %0 cannot be extended", (Type))

include/swift/AST/KnownProtocols.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#define SWIFT_AST_KNOWNPROTOCOLS_H
1515

1616
#include "swift/Basic/InlineBitfield.h"
17+
#include "swift/Basic/FixedBitSet.h"
1718
#include "swift/Config.h"
1819

1920
namespace llvm {
@@ -41,6 +42,12 @@ enum : uint8_t {
4142
enum : unsigned { NumKnownProtocolKindBits =
4243
countBitsUsed(static_cast<unsigned>(NumKnownProtocols - 1)) };
4344

45+
using KnownProtocolSet = FixedBitSet<NumKnownProtocols, KnownProtocolKind>;
46+
47+
/// Produces a set of all protocols that have an inverse, i.e., for every
48+
/// known protocol KP in the set, ~KP exists.
49+
KnownProtocolSet getInvertableProtocols();
50+
4451
/// Retrieve the name of the given known protocol.
4552
llvm::StringRef getProtocolName(KnownProtocolKind kind);
4653

lib/AST/ASTContext.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ llvm::StringRef swift::getProtocolName(KnownProtocolKind kind) {
102102
llvm_unreachable("bad KnownProtocolKind");
103103
}
104104

105+
KnownProtocolSet swift::getInvertableProtocols() {
106+
return { KnownProtocolKind::Copyable };
107+
}
108+
105109
namespace {
106110
enum class SearchPathKind : uint8_t {
107111
Import = 1 << 0,

lib/AST/RequirementMachine/RequirementLowering.cpp

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -732,6 +732,7 @@ void swift::rewriting::realizeInheritedRequirements(
732732
auto inheritedTypes = decl->getInherited();
733733
auto *dc = decl->getInnermostDeclContext();
734734
auto *moduleForInference = dc->getParentModule();
735+
auto defaults = getInvertableProtocols();
735736

736737
for (auto index : inheritedTypes.getIndices()) {
737738
Type inheritedType =
@@ -749,6 +750,17 @@ void swift::rewriting::realizeInheritedRequirements(
749750

750751
auto *typeRepr = inheritedTypes.getTypeRepr(index);
751752
SourceLoc loc = (typeRepr ? typeRepr->getStartLoc() : SourceLoc());
753+
754+
// For any inverses, we only need to cancel out a default requirement.
755+
if (dyn_cast_or_null<InverseTypeRepr>(typeRepr)) {
756+
if (auto protoTy = inheritedType->getAs<ProtocolType>())
757+
if (auto protoDecl = protoTy->getDecl())
758+
if (auto kp = protoDecl->getKnownProtocolKind())
759+
defaults.remove(*kp);
760+
761+
continue;
762+
}
763+
752764
if (shouldInferRequirements) {
753765
inferRequirements(inheritedType, loc, moduleForInference,
754766
decl->getInnermostDeclContext(), result);
@@ -759,15 +771,17 @@ void swift::rewriting::realizeInheritedRequirements(
759771

760772
auto &ctx = dc->getASTContext();
761773
if (ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics)) {
762-
// All associated types or generic type params are Copyable by default.
763-
// TODO: if we saw ~Copyable in the inherited types list earlier, skip this!
774+
// Add the remaining default conformance requirements to this
775+
// associated type or generic type param.
776+
for (auto kp : defaults) {
777+
ProtocolDecl *decl = ctx.getProtocol(kp);
778+
assert(decl && "couldn't load protocol??");
764779

765-
if (auto *copyable = ctx.getProtocol(KnownProtocolKind::Copyable)) {
766780
SourceLoc loc = decl->getLoc();
767-
Type copyableType = copyable->getDeclaredInterfaceType();
781+
Type protocolType = decl->getDeclaredInterfaceType();
768782

769-
// Add Copyable as an "inferred" requirement.
770-
Requirement req(RequirementKind::Conformance, type, copyableType);
783+
// Add the protocol as an "inferred" requirement.
784+
Requirement req(RequirementKind::Conformance, type, protocolType);
771785
result.push_back({req, loc, /*wasInferred=*/true});
772786
}
773787
}

lib/Sema/TypeCheckType.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5046,14 +5046,14 @@ NeverNullType TypeResolver::resolveInverseType(InverseTypeRepr *repr,
50465046
if (ty->hasError())
50475047
return ErrorType::get(getASTContext());
50485048

5049-
// TODO: more user-friendly verification
5050-
50515049
if (auto protoTy = ty->getAs<ProtocolType>())
50525050
if (auto protoDecl = protoTy->getDecl())
5053-
if (protoDecl->isSpecificProtocol(KnownProtocolKind::Copyable))
5054-
return ty;
5051+
if (auto kp = protoDecl->getKnownProtocolKind())
5052+
if (getInvertableProtocols().contains(*kp))
5053+
return ty;
50555054

5056-
llvm_unreachable("todo: verification");
5055+
diagnoseInvalid(repr, repr->getLoc(), diag::inverse_type_not_invertable, ty);
5056+
return ErrorType::get(getASTContext());
50575057
}
50585058

50595059
NeverNullType TypeResolver::resolveProtocolType(ProtocolTypeRepr *repr,

0 commit comments

Comments
 (0)