Skip to content
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
2 changes: 0 additions & 2 deletions lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2530,8 +2530,6 @@ void ASTMangler::appendModule(const ModuleDecl *module,
/// Mangle the name of a protocol as a substitution candidate.
void ASTMangler::appendProtocolName(const ProtocolDecl *protocol,
bool allowStandardSubstitution) {
assert(!protocol->getInvertibleProtocolKind() &&
"only inverse requirements are mangled");
assert(AllowMarkerProtocols || !protocol->isMarkerProtocol());

if (allowStandardSubstitution && tryAppendStandardSubstitution(protocol))
Expand Down
148 changes: 97 additions & 51 deletions lib/IRGen/GenEnum.cpp

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions lib/IRGen/GenEnum.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,17 @@ class EnumImplStrategy {
TypeInfoKind TIK;
IsFixedSize_t AlwaysFixedSize;
IsABIAccessible_t ElementsAreABIAccessible;
IsTriviallyDestroyable_t TriviallyDestroyable;
IsCopyable_t Copyable;
IsBitwiseTakable_t BitwiseTakable;
unsigned NumElements;

EnumImplStrategy(IRGenModule &IGM,
TypeInfoKind tik,
IsFixedSize_t alwaysFixedSize,
IsTriviallyDestroyable_t triviallyDestroyable,
IsCopyable_t copyable,
IsBitwiseTakable_t bitwiseTakable,
unsigned NumElements,
std::vector<Element> &&ElementsWithPayload,
std::vector<Element> &&ElementsWithNoPayload);
Expand Down
21 changes: 21 additions & 0 deletions lib/IRGen/GenMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6972,6 +6972,27 @@ GenericArgumentMetadata irgen::addGenericRequirements(
case RequirementKind::Conformance: {
auto protocol = requirement.getProtocolDecl();

// If this is an invertible protocol, encode it as an inverted protocol
// check with all but this protocol masked off.
if (auto invertible = protocol->getInvertibleProtocolKind()) {
++metadata.NumRequirements;

InvertibleProtocolSet mask(0xFFFF);
mask.remove(*invertible);

auto flags = GenericRequirementFlags(
GenericRequirementKind::InvertedProtocols,
/*key argument*/ false,
/* is parameter pack */false);
addGenericRequirement(IGM, B, metadata, sig, flags,
requirement.getFirstType(),
[&]{
B.addInt16(0xFFFF);
B.addInt16(mask.rawBits());
});
break;
}

// Marker protocols do not record generic requirements at all.
if (protocol->isMarkerProtocol()) {
break;
Expand Down
5 changes: 5 additions & 0 deletions lib/SILOptimizer/Utils/CastOptimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
//===----------------------------------------------------------------------===//

#include "swift/SILOptimizer/Utils/CastOptimizer.h"
#include "swift/AST/ExistentialLayout.h"
#include "swift/AST/GenericSignature.h"
#include "swift/AST/Module.h"
#include "swift/AST/SubstitutionMap.h"
Expand Down Expand Up @@ -1472,6 +1473,10 @@ static bool optimizeStaticallyKnownProtocolConformance(
if (Conformance.isInvalid())
return false;

auto layout = TargetType->getExistentialLayout();
if (layout.getProtocols().size() != 1)
return false;

SILBuilderWithScope B(Inst);
SmallVector<ProtocolConformanceRef, 1> NewConformances;
NewConformances.push_back(Conformance);
Expand Down
28 changes: 20 additions & 8 deletions stdlib/public/runtime/ProtocolConformance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1349,6 +1349,10 @@ bool swift::_swift_class_isSubclass(const Metadata *subclass,
return isSubclass(subclass, superclass);
}

static std::optional<TypeLookupError>
checkInvertibleRequirements(const Metadata *type,
InvertibleProtocolSet ignored);

static std::optional<TypeLookupError>
checkGenericRequirement(
const GenericRequirementDescriptor &req,
Expand Down Expand Up @@ -1445,8 +1449,10 @@ checkGenericRequirement(
}
case GenericRequirementKind::InvertedProtocols: {
uint16_t index = req.getInvertedProtocolsGenericParamIndex();
if (index == 0xFFFF)
return TYPE_LOOKUP_ERROR_FMT("unable to suppress protocols");
if (index == 0xFFFF) {
return checkInvertibleRequirements(subjectType,
req.getInvertedProtocols());
}

// Expand the suppression set so we can record these protocols.
if (index >= suppressed.size()) {
Expand Down Expand Up @@ -1613,8 +1619,18 @@ checkGenericPackRequirement(

case GenericRequirementKind::InvertedProtocols: {
uint16_t index = req.getInvertedProtocolsGenericParamIndex();
if (index == 0xFFFF)
return TYPE_LOOKUP_ERROR_FMT("unable to suppress protocols");
if (index == 0xFFFF) {
// Check that each pack element meets the invertible requirements.
for (size_t i = 0, e = subjectType.getNumElements(); i < e; ++i) {
const Metadata *elt = subjectType.getElements()[i];

if (auto error = checkInvertibleRequirements(
elt, req.getInvertedProtocols()))
return error;
}

return std::nullopt;
}

// Expand the suppression set so we can record these protocols.
if (index >= suppressed.size()) {
Expand All @@ -1632,10 +1648,6 @@ checkGenericPackRequirement(
(unsigned)req.getKind());
}

static std::optional<TypeLookupError>
checkInvertibleRequirements(const Metadata *type,
InvertibleProtocolSet ignored);

static std::optional<TypeLookupError>
checkInvertibleRequirementsStructural(const Metadata *type,
InvertibleProtocolSet ignored) {
Expand Down
34 changes: 34 additions & 0 deletions test/IRGen/moveonly_deinits.swift
Original file line number Diff line number Diff line change
Expand Up @@ -388,3 +388,37 @@ func testEnclosesEmptyMoveOnlyWithDeinit() {
// CHECK: call swiftcc void @"$s16moveonly_deinits23EmptyMoveOnlyWithDeinitVfD"()
_ = EnclosesEmptyMoveOnlyWithDeinit(stored: EmptyMoveOnlyWithDeinit())
}

enum ESingle: ~Copyable {
case a(EmptyMoveOnlyWithDeinit)
}

struct OtherEmptyMoveOnlyWithDeinit: ~Copyable {
deinit {}
}

enum EMulti: ~Copyable {
case a(EmptyMoveOnlyWithDeinit)
case b(OtherEmptyMoveOnlyWithDeinit)
}


// IR-LABEL: define {{.*}} swiftcc void @"$s16moveonly_deinits14testSingleEnumyyF"()
func testSingleEnum() {
// IR: call swiftcc void @"$s16moveonly_deinits23EmptyMoveOnlyWithDeinitVfD"()
_ = ESingle.a(EmptyMoveOnlyWithDeinit())
}


// IR-LABEL: define {{.*}}swiftcc void @"$s16moveonly_deinits13testMultiEnumyyF"()
func testMultiEnum() {
// IR: call void @"$s16moveonly_deinits6EMultiOWOe"(i1 true)
_ = EMulti.b(OtherEmptyMoveOnlyWithDeinit())
}

// IR-LABEL: define {{.*}}void @"$s16moveonly_deinits6EMultiOWOe"
// IR: br i1
// IR: 1:
// IR: call swiftcc void @"$s16moveonly_deinits23EmptyMoveOnlyWithDeinitVfD"()
// IR: 2:
// IR: call swiftcc void @"$s16moveonly_deinits28OtherEmptyMoveOnlyWithDeinitVfD"()
3 changes: 1 addition & 2 deletions test/Interpreter/moveonly_generics_casting.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,7 @@ func main() {
attemptCall(Dog<Any>())

// CHECK-FIXME: failed to cast (attemptCall)
typealias NoncopyableAny = ~Copyable
// FIXME crashes: attemptCall(Dog<any NoncopyableAny>())
// FIXME crashes: attemptCall(Dog<any ~Copyable>())

// CHECK: cast succeeded
test_radar124171788(.nothing)
Expand Down
36 changes: 36 additions & 0 deletions test/Interpreter/moveonly_generics_casting_assoctypes.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// RUN: %target-run-simple-swift(-Xfrontend -sil-verify-all -enable-experimental-feature NoncopyableGenerics -enable-experimental-feature SuppressedAssociatedTypes)
// RUN: %target-run-simple-swift(-O -Xfrontend -sil-verify-all -enable-experimental-feature NoncopyableGenerics -enable-experimental-feature SuppressedAssociatedTypes)

// REQUIRES: executable_test

// UNSUPPORTED: use_os_stdlib
// UNSUPPORTED: back_deployment_runtime

protocol P: ~Copyable {
associatedtype A: ~Copyable
}

protocol Q: ~Copyable { }

struct X<T: P & ~Copyable> { }

extension X: Q where T: ~Copyable, T.A: Copyable { }

struct NC: ~Copyable { }

struct WithCopyable: P {
typealias A = Int
}

struct WithNonCopyable: P {
typealias A = NC
}

func tryCastToQ<T: P>(_: T.Type) -> Q? {
let x = X<T>()
return x as? Q
}

precondition(tryCastToQ(_: WithCopyable.self) != nil)
precondition(tryCastToQ(_: WithNonCopyable.self) == nil)