mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[BitwiseCopyable] Infer and check constraint.
When the BitwiseCopyable experimental feature is enabled, infer types to conform to `_BitwiseCopyable`. The `_BitwiseCopyable` inference broadly follows the approach taken to infer `Sendable`. (1) Special types are conformed: - function types if trivial - metatypes - builtin types if trivial (2) TheTupleType is conditionally conformed. (3) Nominal types are conformed if: - non-public or public+fixed-layout - enum or struct (non-class) - every field conforms to _BitwiseCopyable Additionally, check that nominal types which are explicitly conformed to `_BitwiseCopyable` satisfy the latter two conditions of (3). For a public, non-fixed-layout type to conform to `_BitwiseCopyable`, the user must conform the type explicitly. Finally, verify that conformances correspond to TypeLowering's notion of triviality to the appropriate extent: - if a type isn't trivial, it doesn't conform to `_BitwiseCopyable` unless it's an archetype - if a type is trivial, it conforms to `_BitwiseCopyable` unless some field in its layout doesn't conform to `_BitwiseCopyable`, which is only permitted under certain circumstances (the type has generic parameters, the type is public non-fixed-layout, the type is a reference but has ReferenceStorage::Unmanaged, the type is a ModuleType, etc.)
This commit is contained in:
@@ -1808,6 +1808,34 @@ static bool isEscapableFunctionType(EitherFunctionType eitherFnTy) {
|
||||
return !functionType->isNoEscape();
|
||||
}
|
||||
|
||||
static bool isBitwiseCopyableFunctionType(EitherFunctionType eitherFnTy) {
|
||||
SILFunctionTypeRepresentation representation;
|
||||
if (auto silFnTy = eitherFnTy.dyn_cast<const SILFunctionType *>()) {
|
||||
representation = silFnTy->getRepresentation();
|
||||
} else {
|
||||
auto fnTy = eitherFnTy.get<const FunctionType *>();
|
||||
representation = convertRepresentation(fnTy->getRepresentation());
|
||||
}
|
||||
|
||||
switch (representation) {
|
||||
case SILFunctionTypeRepresentation::Thick:
|
||||
case SILFunctionTypeRepresentation::Block:
|
||||
return false;
|
||||
case SILFunctionTypeRepresentation::Thin:
|
||||
case SILFunctionTypeRepresentation::CXXMethod:
|
||||
case SILFunctionTypeRepresentation::CFunctionPointer:
|
||||
case SILFunctionTypeRepresentation::Method:
|
||||
case SILFunctionTypeRepresentation::ObjCMethod:
|
||||
case SILFunctionTypeRepresentation::WitnessMethod:
|
||||
case SILFunctionTypeRepresentation::Closure:
|
||||
case SILFunctionTypeRepresentation::KeyPathAccessorGetter:
|
||||
case SILFunctionTypeRepresentation::KeyPathAccessorSetter:
|
||||
case SILFunctionTypeRepresentation::KeyPathAccessorEquals:
|
||||
case SILFunctionTypeRepresentation::KeyPathAccessorHash:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// Synthesize a builtin function type conformance to the given protocol, if
|
||||
/// appropriate.
|
||||
static ProtocolConformanceRef getBuiltinFunctionTypeConformance(
|
||||
@@ -1835,6 +1863,10 @@ static ProtocolConformanceRef getBuiltinFunctionTypeConformance(
|
||||
// Functions cannot permanently destroy a move-only var/let
|
||||
// that they capture, so it's safe to copy functions, like classes.
|
||||
return synthesizeConformance();
|
||||
case KnownProtocolKind::BitwiseCopyable:
|
||||
if (isBitwiseCopyableFunctionType(functionType))
|
||||
return synthesizeConformance();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1861,12 +1893,13 @@ static ProtocolConformanceRef getBuiltinMetaTypeTypeConformance(
|
||||
}
|
||||
}
|
||||
|
||||
// All metatypes are Sendable, Copyable, and Escapable.
|
||||
// All metatypes are Sendable, Copyable, Escapable, and BitwiseCopyable.
|
||||
if (auto kp = protocol->getKnownProtocolKind()) {
|
||||
switch (*kp) {
|
||||
case KnownProtocolKind::Sendable:
|
||||
case KnownProtocolKind::Copyable:
|
||||
case KnownProtocolKind::Escapable:
|
||||
case KnownProtocolKind::BitwiseCopyable:
|
||||
return ProtocolConformanceRef(
|
||||
ctx.getBuiltinConformance(type, protocol,
|
||||
BuiltinConformanceKind::Synthesized));
|
||||
@@ -1880,11 +1913,12 @@ static ProtocolConformanceRef getBuiltinMetaTypeTypeConformance(
|
||||
|
||||
/// Synthesize a builtin type conformance to the given protocol, if
|
||||
/// appropriate.
|
||||
static ProtocolConformanceRef getBuiltinBuiltinTypeConformance(
|
||||
Type type, const BuiltinType *builtinType, ProtocolDecl *protocol) {
|
||||
// All builtin are Sendable, Copyable, and Escapable
|
||||
static ProtocolConformanceRef
|
||||
getBuiltinBuiltinTypeConformance(Type type, const BuiltinType *builtinType,
|
||||
ProtocolDecl *protocol) {
|
||||
if (auto kp = protocol->getKnownProtocolKind()) {
|
||||
switch (*kp) {
|
||||
// All builtin types are Sendable, Copyable, and Escapable.
|
||||
case KnownProtocolKind::Sendable:
|
||||
case KnownProtocolKind::Copyable:
|
||||
case KnownProtocolKind::Escapable: {
|
||||
@@ -1893,6 +1927,15 @@ static ProtocolConformanceRef getBuiltinBuiltinTypeConformance(
|
||||
ctx.getBuiltinConformance(type, protocol,
|
||||
BuiltinConformanceKind::Synthesized));
|
||||
}
|
||||
// Some builtin types are BitwiseCopyable.
|
||||
case KnownProtocolKind::BitwiseCopyable: {
|
||||
if (builtinType->isBitwiseCopyable()) {
|
||||
ASTContext &ctx = protocol->getASTContext();
|
||||
return ProtocolConformanceRef(ctx.getBuiltinConformance(
|
||||
type, protocol, BuiltinConformanceKind::Synthesized));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -2116,6 +2159,18 @@ LookupConformanceInModuleRequest::evaluate(
|
||||
} else {
|
||||
return ProtocolConformanceRef::forMissingOrInvalid(type, protocol);
|
||||
}
|
||||
} else if (protocol->isSpecificProtocol(
|
||||
KnownProtocolKind::BitwiseCopyable)) {
|
||||
// Try to infer BitwiseCopyable conformance.
|
||||
ImplicitKnownProtocolConformanceRequest request{
|
||||
nominal, KnownProtocolKind::BitwiseCopyable};
|
||||
if (auto conformance =
|
||||
evaluateOrDefault(ctx.evaluator, request, nullptr)) {
|
||||
conformances.clear();
|
||||
conformances.push_back(conformance);
|
||||
} else {
|
||||
return ProtocolConformanceRef::forMissingOrInvalid(type, protocol);
|
||||
}
|
||||
} else {
|
||||
// Was unable to infer the missing conformance.
|
||||
return ProtocolConformanceRef::forMissingOrInvalid(type, protocol);
|
||||
|
||||
Reference in New Issue
Block a user