Skip to content

Commit 41df661

Browse files
committed
AST: Use a builtin conformance for unconditional Copyable/Escapable
This generalizes what we were already doing for classes.
1 parent 02c30d1 commit 41df661

14 files changed

+47
-79
lines changed

lib/AST/ConformanceLookup.cpp

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
#include "swift/AST/DiagnosticsSema.h"
3030
#include "swift/AST/ExistentialLayout.h"
3131
#include "swift/AST/GenericEnvironment.h"
32-
#include "swift/AST/InverseMarking.h"
3332
#include "swift/AST/NameLookup.h"
3433
#include "swift/AST/NameLookupRequests.h"
3534
#include "swift/AST/PackConformance.h"
@@ -403,39 +402,6 @@ static ProtocolConformanceRef getBuiltinMetaTypeTypeConformance(
403402
return ProtocolConformanceRef::forMissingOrInvalid(type, protocol);
404403
}
405404

406-
static ProtocolConformanceRef
407-
getBuiltinInvertibleProtocolConformance(NominalTypeDecl *nominal,
408-
Type type,
409-
ProtocolDecl *protocol) {
410-
assert(isa<ClassDecl>(nominal));
411-
ASTContext &ctx = protocol->getASTContext();
412-
413-
auto ip = protocol->getInvertibleProtocolKind();
414-
switch (*ip) {
415-
case InvertibleProtocolKind::Copyable:
416-
// If move-only classes is enabled, we'll check the markings.
417-
if (ctx.LangOpts.hasFeature(Feature::MoveOnlyClasses)) {
418-
switch (nominal->hasInverseMarking(*ip).getKind()) {
419-
case InverseMarking::Kind::LegacyExplicit:
420-
case InverseMarking::Kind::Explicit:
421-
// An inverse ~Copyable prevents conformance.
422-
return ProtocolConformanceRef::forInvalid();
423-
424-
case InverseMarking::Kind::None:
425-
break;
426-
}
427-
}
428-
break;
429-
case InvertibleProtocolKind::Escapable:
430-
// Always conforms.
431-
break;
432-
}
433-
434-
return ProtocolConformanceRef(
435-
ctx.getBuiltinConformance(type, protocol,
436-
BuiltinConformanceKind::Synthesized));
437-
}
438-
439405
/// Synthesize a builtin type conformance to the given protocol, if
440406
/// appropriate.
441407
static ProtocolConformanceRef
@@ -625,13 +591,6 @@ LookupConformanceInModuleRequest::evaluate(
625591
if (!nominal || isa<ProtocolDecl>(nominal))
626592
return ProtocolConformanceRef::forMissingOrInvalid(type, protocol);
627593

628-
// We specially avoid recording conformances to invertible protocols in a
629-
// class's conformance table. This prevents an evaluator cycle.
630-
if (ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics)
631-
&& isa<ClassDecl>(nominal)
632-
&& protocol->getInvertibleProtocolKind())
633-
return getBuiltinInvertibleProtocolConformance(nominal, type, protocol);
634-
635594
// Expand conformances added by extension macros.
636595
//
637596
// FIXME: This expansion should only be done if the

lib/AST/ConformanceLookupTable.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -921,7 +921,22 @@ ConformanceLookupTable::getConformance(NominalTypeDecl *nominal,
921921
// Form the conformance.
922922
Type type = entry->getDeclContext()->getDeclaredInterfaceType();
923923
ASTContext &ctx = nominal->getASTContext();
924-
if (entry->getKind() == ConformanceEntryKind::Inherited) {
924+
925+
if (protocol->getInvertibleProtocolKind() &&
926+
entry->getDeclContext() == nominal &&
927+
(entry->getKind() == ConformanceEntryKind::Synthesized ||
928+
entry->getKind() == ConformanceEntryKind::Inherited)) {
929+
// Unconditional conformances to Copyable and Escapable are represented as
930+
// builtin conformances, which do not need to store a substitution map.
931+
//
932+
// This avoids an exponential blowup when constructing the context
933+
// substitution map for a type like G<G<G<G<...>>>>.
934+
Type conformingType = nominal->getSelfInterfaceType();
935+
936+
entry->Conformance = ctx.getBuiltinConformance(
937+
conformingType, protocol, BuiltinConformanceKind::Synthesized);
938+
939+
} else if (entry->getKind() == ConformanceEntryKind::Inherited) {
925940
// For an inherited conformance, the conforming nominal type will
926941
// be different from the nominal type.
927942
assert(conformingNominal != nominal && "Broken inherited conformance");

lib/AST/ProtocolConformance.cpp

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@
2323
#include "swift/AST/FileUnit.h"
2424
#include "swift/AST/GenericEnvironment.h"
2525
#include "swift/AST/InFlightSubstitution.h"
26-
#include "swift/AST/InverseMarking.h"
2726
#include "swift/AST/LazyResolver.h"
2827
#include "swift/AST/Module.h"
28+
#include "swift/AST/NameLookup.h"
2929
#include "swift/AST/PackConformance.h"
3030
#include "swift/AST/TypeCheckRequests.h"
3131
#include "swift/AST/Types.h"
@@ -1091,21 +1091,33 @@ void NominalTypeDecl::prepareConformanceTable() const {
10911091

10921092
// Synthesize the unconditional conformances to invertible protocols.
10931093
if (ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics)) {
1094-
// Classes get their conformances during ModuleDecl::lookupConformance.
1095-
if (!isa<ClassDecl>(this)) {
1096-
bool missingOne = false;
1097-
for (auto ip : InvertibleProtocolSet::full()) {
1098-
if (!hasInverseMarking(ip))
1099-
addSynthesized(ctx.getProtocol(getKnownProtocolKind(ip)));
1100-
else
1101-
missingOne = true;
1094+
// FIXME: We should be able to only resolve the inheritance clause once,
1095+
// but we also do it in ConformanceLookupTable::updateLookupTable().
1096+
InvertibleProtocolSet inverses;
1097+
bool anyObject = false;
1098+
(void) getDirectlyInheritedNominalTypeDecls(this, inverses, anyObject);
1099+
1100+
// Handle deprecated attributes.
1101+
if (getAttrs().hasAttribute<MoveOnlyAttr>())
1102+
inverses.insert(InvertibleProtocolKind::Copyable);
1103+
if (getAttrs().hasAttribute<NonEscapableAttr>())
1104+
inverses.insert(InvertibleProtocolKind::Escapable);
1105+
1106+
bool hasSuppressedConformances = false;
1107+
for (auto ip : InvertibleProtocolSet::full()) {
1108+
if (!inverses.contains(ip) ||
1109+
(isa<ClassDecl>(this) &&
1110+
!ctx.LangOpts.hasFeature(Feature::MoveOnlyClasses))) {
1111+
addSynthesized(ctx.getProtocol(getKnownProtocolKind(ip)));
1112+
} else {
1113+
hasSuppressedConformances = true;
11021114
}
1103-
1104-
// Non-copyable and non-escaping types do not implicitly conform to
1105-
// any other protocols.
1106-
if (missingOne)
1107-
return;
11081115
}
1116+
1117+
// Non-copyable and non-escaping types do not implicitly conform to
1118+
// any other protocols.
1119+
if (hasSuppressedConformances)
1120+
return;
11091121
} else if (!canBeCopyable()) {
11101122
return; // No synthesized conformances for move-only nominals.
11111123
}

lib/Frontend/ModuleInterfaceSupport.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ class InheritedProtocolCollector {
473473
}
474474

475475
static bool isUncheckedConformance(ProtocolConformance *conformance) {
476-
if (auto normal = conformance->getRootNormalConformance())
476+
if (auto normal = dyn_cast<NormalProtocolConformance>(conformance->getRootConformance()))
477477
return normal->isUnchecked();
478478
return false;
479479
}

test/Constraints/pack_expansion_types.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
// RUN: %target-typecheck-verify-swift
22

3-
// XFAIL: noncopyable_generics
4-
53
func returnTuple1<each T>() -> (repeat each T) { fatalError() }
64
// expected-note@-1 {{in call to function 'returnTuple1()'}}
75

test/Distributed/distributed_incomplete_system_no_crash.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
// RUN: %empty-directory(%t)
22
// RUN: %target-swift-frontend -typecheck -verify -disable-availability-checking 2>&1 %s
33

4-
// XFAIL: noncopyable_generics
5-
64
// REQUIRES: concurrency
75
// REQUIRES: distributed
86

@@ -50,4 +48,4 @@ public final class CompletelyHollowActorSystem_NotEvenTypes: DistributedActorSys
5048
// expected-error@-3{{class 'CompletelyHollowActorSystem_NotEvenTypes' is missing witness for protocol requirement 'remoteCall'}}
5149
// expected-note@-4{{add stubs for conformance}}
5250
// expected-note@-5{{add stubs for conformance}}
53-
}
51+
}

test/Generics/inverse_extension_signatures.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
// CHECK-LABEL: .Outer.InnerStruct.init()@
2020
// CHECK: Generic signature: <A, C where A : Escapable, C : Escapable>
2121

22-
// CHECK: (normal_conformance type="Outer<A>.InnerStruct<C>" protocol="Escapable")
22+
// CHECK: (builtin_conformance type="Outer<A>.InnerStruct<C>" protocol="Escapable")
2323

2424
// CHECK-LABEL: .Outer.InnerVariation1@
2525
// CHECK: Generic signature: <A, D where A : Escapable, D : Escapable>

test/Generics/rdar90402519.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
// RUN: %target-typecheck-verify-swift
22

3-
// rdar://122287787 (NCGenerics performance issues in regression tests)
4-
// UNSUPPORTED: noncopyable_generics
5-
63
// This needs a better diagnostic. The real problem is the 'C == G<I>'
74
// requirement in P2 conflicts with the one in P1.
85

test/SILOptimizer/generic_specialization_loops_detection_without_loops.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
// RUN: %target-swift-frontend -O -emit-sil -Xllvm -sil-print-generic-specialization-loops %s 2>&1 | %FileCheck --check-prefix=CHECK %s
22

3-
// rdar://122287787 (NCGenerics performance issues in regression tests)
4-
// UNSUPPORTED: noncopyable_generics
5-
63
// Check that the generic specializer does not hang a compiler by
74
// creating and infinite loop of generic specializations.
85

test/Sema/unsupported_recursive_value_type.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
// RUN: %target-typecheck-verify-swift
22

3-
// rdar://122287787 (NCGenerics performance issues in regression tests)
4-
// UNSUPPORTED: noncopyable_generics
5-
63
struct SelfRecursiveStruct {
74
let a: SelfRecursiveStruct // expected-error{{value type 'SelfRecursiveStruct' cannot have a stored property that recursively contains it}}
85
}

0 commit comments

Comments
 (0)