mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
AST: Use a builtin conformance for unconditional Copyable/Escapable
This generalizes what we were already doing for classes.
This commit is contained in:
@@ -29,7 +29,6 @@
|
||||
#include "swift/AST/DiagnosticsSema.h"
|
||||
#include "swift/AST/ExistentialLayout.h"
|
||||
#include "swift/AST/GenericEnvironment.h"
|
||||
#include "swift/AST/InverseMarking.h"
|
||||
#include "swift/AST/NameLookup.h"
|
||||
#include "swift/AST/NameLookupRequests.h"
|
||||
#include "swift/AST/PackConformance.h"
|
||||
@@ -403,39 +402,6 @@ static ProtocolConformanceRef getBuiltinMetaTypeTypeConformance(
|
||||
return ProtocolConformanceRef::forMissingOrInvalid(type, protocol);
|
||||
}
|
||||
|
||||
static ProtocolConformanceRef
|
||||
getBuiltinInvertibleProtocolConformance(NominalTypeDecl *nominal,
|
||||
Type type,
|
||||
ProtocolDecl *protocol) {
|
||||
assert(isa<ClassDecl>(nominal));
|
||||
ASTContext &ctx = protocol->getASTContext();
|
||||
|
||||
auto ip = protocol->getInvertibleProtocolKind();
|
||||
switch (*ip) {
|
||||
case InvertibleProtocolKind::Copyable:
|
||||
// If move-only classes is enabled, we'll check the markings.
|
||||
if (ctx.LangOpts.hasFeature(Feature::MoveOnlyClasses)) {
|
||||
switch (nominal->hasInverseMarking(*ip).getKind()) {
|
||||
case InverseMarking::Kind::LegacyExplicit:
|
||||
case InverseMarking::Kind::Explicit:
|
||||
// An inverse ~Copyable prevents conformance.
|
||||
return ProtocolConformanceRef::forInvalid();
|
||||
|
||||
case InverseMarking::Kind::None:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InvertibleProtocolKind::Escapable:
|
||||
// Always conforms.
|
||||
break;
|
||||
}
|
||||
|
||||
return ProtocolConformanceRef(
|
||||
ctx.getBuiltinConformance(type, protocol,
|
||||
BuiltinConformanceKind::Synthesized));
|
||||
}
|
||||
|
||||
/// Synthesize a builtin type conformance to the given protocol, if
|
||||
/// appropriate.
|
||||
static ProtocolConformanceRef
|
||||
@@ -625,13 +591,6 @@ LookupConformanceInModuleRequest::evaluate(
|
||||
if (!nominal || isa<ProtocolDecl>(nominal))
|
||||
return ProtocolConformanceRef::forMissingOrInvalid(type, protocol);
|
||||
|
||||
// We specially avoid recording conformances to invertible protocols in a
|
||||
// class's conformance table. This prevents an evaluator cycle.
|
||||
if (ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics)
|
||||
&& isa<ClassDecl>(nominal)
|
||||
&& protocol->getInvertibleProtocolKind())
|
||||
return getBuiltinInvertibleProtocolConformance(nominal, type, protocol);
|
||||
|
||||
// Expand conformances added by extension macros.
|
||||
//
|
||||
// FIXME: This expansion should only be done if the
|
||||
|
||||
@@ -921,7 +921,22 @@ ConformanceLookupTable::getConformance(NominalTypeDecl *nominal,
|
||||
// Form the conformance.
|
||||
Type type = entry->getDeclContext()->getDeclaredInterfaceType();
|
||||
ASTContext &ctx = nominal->getASTContext();
|
||||
if (entry->getKind() == ConformanceEntryKind::Inherited) {
|
||||
|
||||
if (protocol->getInvertibleProtocolKind() &&
|
||||
entry->getDeclContext() == nominal &&
|
||||
(entry->getKind() == ConformanceEntryKind::Synthesized ||
|
||||
entry->getKind() == ConformanceEntryKind::Inherited)) {
|
||||
// Unconditional conformances to Copyable and Escapable are represented as
|
||||
// builtin conformances, which do not need to store a substitution map.
|
||||
//
|
||||
// This avoids an exponential blowup when constructing the context
|
||||
// substitution map for a type like G<G<G<G<...>>>>.
|
||||
Type conformingType = nominal->getSelfInterfaceType();
|
||||
|
||||
entry->Conformance = ctx.getBuiltinConformance(
|
||||
conformingType, protocol, BuiltinConformanceKind::Synthesized);
|
||||
|
||||
} else if (entry->getKind() == ConformanceEntryKind::Inherited) {
|
||||
// For an inherited conformance, the conforming nominal type will
|
||||
// be different from the nominal type.
|
||||
assert(conformingNominal != nominal && "Broken inherited conformance");
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
#include "swift/AST/FileUnit.h"
|
||||
#include "swift/AST/GenericEnvironment.h"
|
||||
#include "swift/AST/InFlightSubstitution.h"
|
||||
#include "swift/AST/InverseMarking.h"
|
||||
#include "swift/AST/LazyResolver.h"
|
||||
#include "swift/AST/Module.h"
|
||||
#include "swift/AST/NameLookup.h"
|
||||
#include "swift/AST/PackConformance.h"
|
||||
#include "swift/AST/TypeCheckRequests.h"
|
||||
#include "swift/AST/Types.h"
|
||||
@@ -1091,21 +1091,33 @@ void NominalTypeDecl::prepareConformanceTable() const {
|
||||
|
||||
// Synthesize the unconditional conformances to invertible protocols.
|
||||
if (ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics)) {
|
||||
// Classes get their conformances during ModuleDecl::lookupConformance.
|
||||
if (!isa<ClassDecl>(this)) {
|
||||
bool missingOne = false;
|
||||
for (auto ip : InvertibleProtocolSet::full()) {
|
||||
if (!hasInverseMarking(ip))
|
||||
addSynthesized(ctx.getProtocol(getKnownProtocolKind(ip)));
|
||||
else
|
||||
missingOne = true;
|
||||
}
|
||||
// FIXME: We should be able to only resolve the inheritance clause once,
|
||||
// but we also do it in ConformanceLookupTable::updateLookupTable().
|
||||
InvertibleProtocolSet inverses;
|
||||
bool anyObject = false;
|
||||
(void) getDirectlyInheritedNominalTypeDecls(this, inverses, anyObject);
|
||||
|
||||
// Non-copyable and non-escaping types do not implicitly conform to
|
||||
// any other protocols.
|
||||
if (missingOne)
|
||||
return;
|
||||
// Handle deprecated attributes.
|
||||
if (getAttrs().hasAttribute<MoveOnlyAttr>())
|
||||
inverses.insert(InvertibleProtocolKind::Copyable);
|
||||
if (getAttrs().hasAttribute<NonEscapableAttr>())
|
||||
inverses.insert(InvertibleProtocolKind::Escapable);
|
||||
|
||||
bool hasSuppressedConformances = false;
|
||||
for (auto ip : InvertibleProtocolSet::full()) {
|
||||
if (!inverses.contains(ip) ||
|
||||
(isa<ClassDecl>(this) &&
|
||||
!ctx.LangOpts.hasFeature(Feature::MoveOnlyClasses))) {
|
||||
addSynthesized(ctx.getProtocol(getKnownProtocolKind(ip)));
|
||||
} else {
|
||||
hasSuppressedConformances = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Non-copyable and non-escaping types do not implicitly conform to
|
||||
// any other protocols.
|
||||
if (hasSuppressedConformances)
|
||||
return;
|
||||
} else if (!canBeCopyable()) {
|
||||
return; // No synthesized conformances for move-only nominals.
|
||||
}
|
||||
|
||||
@@ -473,7 +473,7 @@ class InheritedProtocolCollector {
|
||||
}
|
||||
|
||||
static bool isUncheckedConformance(ProtocolConformance *conformance) {
|
||||
if (auto normal = conformance->getRootNormalConformance())
|
||||
if (auto normal = dyn_cast<NormalProtocolConformance>(conformance->getRootConformance()))
|
||||
return normal->isUnchecked();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// RUN: %target-typecheck-verify-swift
|
||||
|
||||
// XFAIL: noncopyable_generics
|
||||
|
||||
func returnTuple1<each T>() -> (repeat each T) { fatalError() }
|
||||
// expected-note@-1 {{in call to function 'returnTuple1()'}}
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-swift-frontend -typecheck -verify -disable-availability-checking 2>&1 %s
|
||||
|
||||
// XFAIL: noncopyable_generics
|
||||
|
||||
// REQUIRES: concurrency
|
||||
// REQUIRES: distributed
|
||||
|
||||
@@ -50,4 +48,4 @@ public final class CompletelyHollowActorSystem_NotEvenTypes: DistributedActorSys
|
||||
// expected-error@-3{{class 'CompletelyHollowActorSystem_NotEvenTypes' is missing witness for protocol requirement 'remoteCall'}}
|
||||
// expected-note@-4{{add stubs for conformance}}
|
||||
// expected-note@-5{{add stubs for conformance}}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
// CHECK-LABEL: .Outer.InnerStruct.init()@
|
||||
// CHECK: Generic signature: <A, C where A : Escapable, C : Escapable>
|
||||
|
||||
// CHECK: (normal_conformance type="Outer<A>.InnerStruct<C>" protocol="Escapable")
|
||||
// CHECK: (builtin_conformance type="Outer<A>.InnerStruct<C>" protocol="Escapable")
|
||||
|
||||
// CHECK-LABEL: .Outer.InnerVariation1@
|
||||
// CHECK: Generic signature: <A, D where A : Escapable, D : Escapable>
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
// RUN: %target-typecheck-verify-swift
|
||||
|
||||
// rdar://122287787 (NCGenerics performance issues in regression tests)
|
||||
// UNSUPPORTED: noncopyable_generics
|
||||
|
||||
// This needs a better diagnostic. The real problem is the 'C == G<I>'
|
||||
// requirement in P2 conflicts with the one in P1.
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
// RUN: %target-swift-frontend -O -emit-sil -Xllvm -sil-print-generic-specialization-loops %s 2>&1 | %FileCheck --check-prefix=CHECK %s
|
||||
|
||||
// rdar://122287787 (NCGenerics performance issues in regression tests)
|
||||
// UNSUPPORTED: noncopyable_generics
|
||||
|
||||
// Check that the generic specializer does not hang a compiler by
|
||||
// creating and infinite loop of generic specializations.
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
// RUN: %target-typecheck-verify-swift
|
||||
|
||||
// rdar://122287787 (NCGenerics performance issues in regression tests)
|
||||
// UNSUPPORTED: noncopyable_generics
|
||||
|
||||
struct SelfRecursiveStruct {
|
||||
let a: SelfRecursiveStruct // expected-error{{value type 'SelfRecursiveStruct' cannot have a stored property that recursively contains it}}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %empty-directory(%t/mods)
|
||||
|
||||
// XFAIL: noncopyable_generics
|
||||
|
||||
// RUN: touch %t/empty.swift
|
||||
// RUN: %{python} %utils/split_file.py -o %t %s
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// REQUIRES: VENDOR=apple
|
||||
|
||||
// XFAIL: noncopyable_generics
|
||||
|
||||
// RUN: %empty-directory(%t.mod)
|
||||
// RUN: %empty-directory(%t.sdk)
|
||||
// RUN: %empty-directory(%t.module-cache)
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
// RUN: %target-typecheck-verify-swift
|
||||
|
||||
// rdar://122287787 (NCGenerics performance issues in regression tests)
|
||||
// UNSUPPORTED: noncopyable_generics
|
||||
|
||||
protocol SomeProtocol {
|
||||
associatedtype T
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// RUN: %target-typecheck-verify-swift
|
||||
|
||||
// XFAIL: noncopyable_generics
|
||||
|
||||
public enum E : E.R {
|
||||
// expected-error@-1 {{'E' has a raw type that depends on itself}}
|
||||
// expected-note@-2 2{{through reference here}}
|
||||
|
||||
Reference in New Issue
Block a user