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/DiagnosticsSema.h"
|
||||||
#include "swift/AST/ExistentialLayout.h"
|
#include "swift/AST/ExistentialLayout.h"
|
||||||
#include "swift/AST/GenericEnvironment.h"
|
#include "swift/AST/GenericEnvironment.h"
|
||||||
#include "swift/AST/InverseMarking.h"
|
|
||||||
#include "swift/AST/NameLookup.h"
|
#include "swift/AST/NameLookup.h"
|
||||||
#include "swift/AST/NameLookupRequests.h"
|
#include "swift/AST/NameLookupRequests.h"
|
||||||
#include "swift/AST/PackConformance.h"
|
#include "swift/AST/PackConformance.h"
|
||||||
@@ -403,39 +402,6 @@ static ProtocolConformanceRef getBuiltinMetaTypeTypeConformance(
|
|||||||
return ProtocolConformanceRef::forMissingOrInvalid(type, protocol);
|
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
|
/// Synthesize a builtin type conformance to the given protocol, if
|
||||||
/// appropriate.
|
/// appropriate.
|
||||||
static ProtocolConformanceRef
|
static ProtocolConformanceRef
|
||||||
@@ -625,13 +591,6 @@ LookupConformanceInModuleRequest::evaluate(
|
|||||||
if (!nominal || isa<ProtocolDecl>(nominal))
|
if (!nominal || isa<ProtocolDecl>(nominal))
|
||||||
return ProtocolConformanceRef::forMissingOrInvalid(type, protocol);
|
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.
|
// Expand conformances added by extension macros.
|
||||||
//
|
//
|
||||||
// FIXME: This expansion should only be done if the
|
// FIXME: This expansion should only be done if the
|
||||||
|
|||||||
@@ -921,7 +921,22 @@ ConformanceLookupTable::getConformance(NominalTypeDecl *nominal,
|
|||||||
// Form the conformance.
|
// Form the conformance.
|
||||||
Type type = entry->getDeclContext()->getDeclaredInterfaceType();
|
Type type = entry->getDeclContext()->getDeclaredInterfaceType();
|
||||||
ASTContext &ctx = nominal->getASTContext();
|
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
|
// For an inherited conformance, the conforming nominal type will
|
||||||
// be different from the nominal type.
|
// be different from the nominal type.
|
||||||
assert(conformingNominal != nominal && "Broken inherited conformance");
|
assert(conformingNominal != nominal && "Broken inherited conformance");
|
||||||
|
|||||||
@@ -23,9 +23,9 @@
|
|||||||
#include "swift/AST/FileUnit.h"
|
#include "swift/AST/FileUnit.h"
|
||||||
#include "swift/AST/GenericEnvironment.h"
|
#include "swift/AST/GenericEnvironment.h"
|
||||||
#include "swift/AST/InFlightSubstitution.h"
|
#include "swift/AST/InFlightSubstitution.h"
|
||||||
#include "swift/AST/InverseMarking.h"
|
|
||||||
#include "swift/AST/LazyResolver.h"
|
#include "swift/AST/LazyResolver.h"
|
||||||
#include "swift/AST/Module.h"
|
#include "swift/AST/Module.h"
|
||||||
|
#include "swift/AST/NameLookup.h"
|
||||||
#include "swift/AST/PackConformance.h"
|
#include "swift/AST/PackConformance.h"
|
||||||
#include "swift/AST/TypeCheckRequests.h"
|
#include "swift/AST/TypeCheckRequests.h"
|
||||||
#include "swift/AST/Types.h"
|
#include "swift/AST/Types.h"
|
||||||
@@ -1091,21 +1091,33 @@ void NominalTypeDecl::prepareConformanceTable() const {
|
|||||||
|
|
||||||
// Synthesize the unconditional conformances to invertible protocols.
|
// Synthesize the unconditional conformances to invertible protocols.
|
||||||
if (ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics)) {
|
if (ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics)) {
|
||||||
// Classes get their conformances during ModuleDecl::lookupConformance.
|
// FIXME: We should be able to only resolve the inheritance clause once,
|
||||||
if (!isa<ClassDecl>(this)) {
|
// but we also do it in ConformanceLookupTable::updateLookupTable().
|
||||||
bool missingOne = false;
|
InvertibleProtocolSet inverses;
|
||||||
|
bool anyObject = false;
|
||||||
|
(void) getDirectlyInheritedNominalTypeDecls(this, inverses, anyObject);
|
||||||
|
|
||||||
|
// 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()) {
|
for (auto ip : InvertibleProtocolSet::full()) {
|
||||||
if (!hasInverseMarking(ip))
|
if (!inverses.contains(ip) ||
|
||||||
|
(isa<ClassDecl>(this) &&
|
||||||
|
!ctx.LangOpts.hasFeature(Feature::MoveOnlyClasses))) {
|
||||||
addSynthesized(ctx.getProtocol(getKnownProtocolKind(ip)));
|
addSynthesized(ctx.getProtocol(getKnownProtocolKind(ip)));
|
||||||
else
|
} else {
|
||||||
missingOne = true;
|
hasSuppressedConformances = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non-copyable and non-escaping types do not implicitly conform to
|
// Non-copyable and non-escaping types do not implicitly conform to
|
||||||
// any other protocols.
|
// any other protocols.
|
||||||
if (missingOne)
|
if (hasSuppressedConformances)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
} else if (!canBeCopyable()) {
|
} else if (!canBeCopyable()) {
|
||||||
return; // No synthesized conformances for move-only nominals.
|
return; // No synthesized conformances for move-only nominals.
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -473,7 +473,7 @@ class InheritedProtocolCollector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool isUncheckedConformance(ProtocolConformance *conformance) {
|
static bool isUncheckedConformance(ProtocolConformance *conformance) {
|
||||||
if (auto normal = conformance->getRootNormalConformance())
|
if (auto normal = dyn_cast<NormalProtocolConformance>(conformance->getRootConformance()))
|
||||||
return normal->isUnchecked();
|
return normal->isUnchecked();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
// RUN: %target-typecheck-verify-swift
|
// RUN: %target-typecheck-verify-swift
|
||||||
|
|
||||||
// XFAIL: noncopyable_generics
|
|
||||||
|
|
||||||
func returnTuple1<each T>() -> (repeat each T) { fatalError() }
|
func returnTuple1<each T>() -> (repeat each T) { fatalError() }
|
||||||
// expected-note@-1 {{in call to function 'returnTuple1()'}}
|
// expected-note@-1 {{in call to function 'returnTuple1()'}}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
// RUN: %empty-directory(%t)
|
// RUN: %empty-directory(%t)
|
||||||
// RUN: %target-swift-frontend -typecheck -verify -disable-availability-checking 2>&1 %s
|
// RUN: %target-swift-frontend -typecheck -verify -disable-availability-checking 2>&1 %s
|
||||||
|
|
||||||
// XFAIL: noncopyable_generics
|
|
||||||
|
|
||||||
// REQUIRES: concurrency
|
// REQUIRES: concurrency
|
||||||
// REQUIRES: distributed
|
// REQUIRES: distributed
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
// CHECK-LABEL: .Outer.InnerStruct.init()@
|
// CHECK-LABEL: .Outer.InnerStruct.init()@
|
||||||
// CHECK: Generic signature: <A, C where A : Escapable, C : Escapable>
|
// 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-LABEL: .Outer.InnerVariation1@
|
||||||
// CHECK: Generic signature: <A, D where A : Escapable, D : Escapable>
|
// CHECK: Generic signature: <A, D where A : Escapable, D : Escapable>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
// RUN: %target-typecheck-verify-swift
|
// 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>'
|
// This needs a better diagnostic. The real problem is the 'C == G<I>'
|
||||||
// requirement in P2 conflicts with the one in P1.
|
// 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
|
// 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
|
// Check that the generic specializer does not hang a compiler by
|
||||||
// creating and infinite loop of generic specializations.
|
// creating and infinite loop of generic specializations.
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
// RUN: %target-typecheck-verify-swift
|
// RUN: %target-typecheck-verify-swift
|
||||||
|
|
||||||
// rdar://122287787 (NCGenerics performance issues in regression tests)
|
|
||||||
// UNSUPPORTED: noncopyable_generics
|
|
||||||
|
|
||||||
struct SelfRecursiveStruct {
|
struct SelfRecursiveStruct {
|
||||||
let a: SelfRecursiveStruct // expected-error{{value type 'SelfRecursiveStruct' cannot have a stored property that recursively contains it}}
|
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)
|
||||||
// RUN: %empty-directory(%t/mods)
|
// RUN: %empty-directory(%t/mods)
|
||||||
|
|
||||||
// XFAIL: noncopyable_generics
|
|
||||||
|
|
||||||
// RUN: touch %t/empty.swift
|
// RUN: touch %t/empty.swift
|
||||||
// RUN: %{python} %utils/split_file.py -o %t %s
|
// RUN: %{python} %utils/split_file.py -o %t %s
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
// REQUIRES: VENDOR=apple
|
// REQUIRES: VENDOR=apple
|
||||||
|
|
||||||
|
// XFAIL: noncopyable_generics
|
||||||
|
|
||||||
// RUN: %empty-directory(%t.mod)
|
// RUN: %empty-directory(%t.mod)
|
||||||
// RUN: %empty-directory(%t.sdk)
|
// RUN: %empty-directory(%t.sdk)
|
||||||
// RUN: %empty-directory(%t.module-cache)
|
// RUN: %empty-directory(%t.module-cache)
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
// RUN: %target-typecheck-verify-swift
|
// RUN: %target-typecheck-verify-swift
|
||||||
|
|
||||||
// rdar://122287787 (NCGenerics performance issues in regression tests)
|
|
||||||
// UNSUPPORTED: noncopyable_generics
|
|
||||||
|
|
||||||
protocol SomeProtocol {
|
protocol SomeProtocol {
|
||||||
associatedtype T
|
associatedtype T
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
// RUN: %target-typecheck-verify-swift
|
// RUN: %target-typecheck-verify-swift
|
||||||
|
|
||||||
// XFAIL: noncopyable_generics
|
|
||||||
|
|
||||||
public enum E : E.R {
|
public enum E : E.R {
|
||||||
// expected-error@-1 {{'E' has a raw type that depends on itself}}
|
// expected-error@-1 {{'E' has a raw type that depends on itself}}
|
||||||
// expected-note@-2 2{{through reference here}}
|
// expected-note@-2 2{{through reference here}}
|
||||||
|
|||||||
Reference in New Issue
Block a user