mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[NCGenerics] fix TypeLowering
This commit is contained in:
@@ -1671,8 +1671,10 @@ ProtocolConformanceRef ModuleDecl::lookupConformance(Type type,
|
|||||||
if (auto nominal = type->getAnyNominal()) {
|
if (auto nominal = type->getAnyNominal()) {
|
||||||
ImplicitKnownProtocolConformanceRequest icvRequest{nominal, *kp};
|
ImplicitKnownProtocolConformanceRequest icvRequest{nominal, *kp};
|
||||||
if (getASTContext().evaluator.hasActiveRequest(icvRequest) ||
|
if (getASTContext().evaluator.hasActiveRequest(icvRequest) ||
|
||||||
getASTContext().evaluator.hasActiveRequest(request))
|
getASTContext().evaluator.hasActiveRequest(request)) {
|
||||||
|
assert(!getInvertibleProtocolKind(*kp));
|
||||||
return ProtocolConformanceRef::forInvalid();
|
return ProtocolConformanceRef::forInvalid();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1731,13 +1733,35 @@ static ProtocolConformanceRef getBuiltinTupleTypeConformance(
|
|||||||
return ProtocolConformanceRef::forMissingOrInvalid(type, protocol);
|
return ProtocolConformanceRef::forMissingOrInvalid(type, protocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using EitherFunctionType =
|
||||||
|
llvm::PointerUnion<const SILFunctionType *, const FunctionType *>;
|
||||||
|
|
||||||
/// Whether the given function type conforms to Sendable.
|
/// Whether the given function type conforms to Sendable.
|
||||||
static bool isSendableFunctionType(const FunctionType *functionType) {
|
static bool isSendableFunctionType(EitherFunctionType eitherFnTy) {
|
||||||
if (functionType->isSendable())
|
FunctionTypeRepresentation representation;
|
||||||
return true;
|
|
||||||
|
if (auto silFnTy = eitherFnTy.dyn_cast<const SILFunctionType *>()) {
|
||||||
|
if (silFnTy->isSendable())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// convert SILFunctionTypeRepresentation -> FunctionTypeRepresentation
|
||||||
|
auto converted = convertRepresentation(silFnTy->getRepresentation());
|
||||||
|
if (!converted)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
representation = *converted;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
auto functionType = eitherFnTy.get<const FunctionType *>();
|
||||||
|
|
||||||
|
if (functionType->isSendable())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
representation = functionType->getExtInfo().getRepresentation();
|
||||||
|
}
|
||||||
|
|
||||||
// C and thin function types have no captures, so they are Sendable.
|
// C and thin function types have no captures, so they are Sendable.
|
||||||
switch (functionType->getExtInfo().getRepresentation()) {
|
switch (representation) {
|
||||||
case FunctionTypeRepresentation::Block:
|
case FunctionTypeRepresentation::Block:
|
||||||
case FunctionTypeRepresentation::Swift:
|
case FunctionTypeRepresentation::Swift:
|
||||||
return false;
|
return false;
|
||||||
@@ -1749,41 +1773,47 @@ static bool isSendableFunctionType(const FunctionType *functionType) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Whether the given function type conforms to Escapable.
|
/// Whether the given function type conforms to Escapable.
|
||||||
static bool isEscapableFunctionType(const FunctionType *functionType) {
|
static bool isEscapableFunctionType(EitherFunctionType eitherFnTy) {
|
||||||
if (functionType->isNoEscape())
|
if (auto silFnTy = eitherFnTy.dyn_cast<const SILFunctionType *>()) {
|
||||||
return false;
|
return !silFnTy->isNoEscape();
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: do we need to also include autoclosures??
|
auto functionType = eitherFnTy.get<const FunctionType *>();
|
||||||
|
|
||||||
return true;
|
// TODO: what about autoclosures?
|
||||||
|
return !functionType->isNoEscape();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Synthesize a builtin function type conformance to the given protocol, if
|
/// Synthesize a builtin function type conformance to the given protocol, if
|
||||||
/// appropriate.
|
/// appropriate.
|
||||||
static ProtocolConformanceRef getBuiltinFunctionTypeConformance(
|
static ProtocolConformanceRef getBuiltinFunctionTypeConformance(
|
||||||
Type type, const FunctionType *functionType, ProtocolDecl *protocol) {
|
Type type, EitherFunctionType functionType, ProtocolDecl *protocol) {
|
||||||
ASTContext &ctx = protocol->getASTContext();
|
ASTContext &ctx = protocol->getASTContext();
|
||||||
// @Sendable function types are Sendable.
|
|
||||||
if (protocol->isSpecificProtocol(KnownProtocolKind::Sendable) &&
|
|
||||||
isSendableFunctionType(functionType)) {
|
|
||||||
return ProtocolConformanceRef(
|
|
||||||
ctx.getBuiltinConformance(type, protocol,
|
|
||||||
BuiltinConformanceKind::Synthesized));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Functions cannot permanently destroy a move-only var/let
|
auto synthesizeConformance = [&]() -> ProtocolConformanceRef {
|
||||||
// that they capture, so it's safe to copy functions, like classes.
|
|
||||||
if (protocol->isSpecificProtocol(KnownProtocolKind::Copyable)) {
|
|
||||||
return ProtocolConformanceRef(
|
return ProtocolConformanceRef(
|
||||||
ctx.getBuiltinConformance(type, protocol,
|
ctx.getBuiltinConformance(type, protocol,
|
||||||
BuiltinConformanceKind::Synthesized));
|
BuiltinConformanceKind::Synthesized));
|
||||||
}
|
};
|
||||||
|
|
||||||
if (protocol->isSpecificProtocol(KnownProtocolKind::Escapable) &&
|
if (auto kp = protocol->getKnownProtocolKind()) {
|
||||||
isEscapableFunctionType(functionType)) {
|
switch (*kp) {
|
||||||
return ProtocolConformanceRef(
|
case KnownProtocolKind::Escapable:
|
||||||
ctx.getBuiltinConformance(type, protocol,
|
if (isEscapableFunctionType(functionType))
|
||||||
BuiltinConformanceKind::Synthesized));
|
return synthesizeConformance();
|
||||||
|
break;
|
||||||
|
case KnownProtocolKind::Sendable:
|
||||||
|
// @Sendable function types are Sendable.
|
||||||
|
if (isSendableFunctionType(functionType))
|
||||||
|
return synthesizeConformance();
|
||||||
|
break;
|
||||||
|
case KnownProtocolKind::Copyable:
|
||||||
|
// Functions cannot permanently destroy a move-only var/let
|
||||||
|
// that they capture, so it's safe to copy functions, like classes.
|
||||||
|
return synthesizeConformance();
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ProtocolConformanceRef::forMissingOrInvalid(type, protocol);
|
return ProtocolConformanceRef::forMissingOrInvalid(type, protocol);
|
||||||
@@ -1959,6 +1989,11 @@ LookupConformanceInModuleRequest::evaluate(
|
|||||||
return getBuiltinFunctionTypeConformance(type, functionType, protocol);
|
return getBuiltinFunctionTypeConformance(type, functionType, protocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SIL function types in the AST can conform to protocols
|
||||||
|
if (auto silFn = type->getAs<SILFunctionType>()) {
|
||||||
|
return getBuiltinFunctionTypeConformance(type, silFn, protocol);
|
||||||
|
}
|
||||||
|
|
||||||
// Metatypes can conform to protocols.
|
// Metatypes can conform to protocols.
|
||||||
if (auto metatypeType = type->getAs<AnyMetatypeType>()) {
|
if (auto metatypeType = type->getAs<AnyMetatypeType>()) {
|
||||||
return getBuiltinMetaTypeTypeConformance(type, metatypeType, protocol);
|
return getBuiltinMetaTypeTypeConformance(type, metatypeType, protocol);
|
||||||
@@ -1969,6 +2004,18 @@ LookupConformanceInModuleRequest::evaluate(
|
|||||||
return getBuiltinBuiltinTypeConformance(type, builtinType, protocol);
|
return getBuiltinBuiltinTypeConformance(type, builtinType, protocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
// Ensure we haven't missed queries for the specialty SIL types
|
||||||
|
// in the AST in conformance to one of the invertible protocols.
|
||||||
|
if (auto kp = protocol->getKnownProtocolKind())
|
||||||
|
if (getInvertibleProtocolKind(*kp))
|
||||||
|
assert(!(type->is<SILFunctionType,
|
||||||
|
SILBoxType,
|
||||||
|
SILMoveOnlyWrappedType,
|
||||||
|
SILPackType,
|
||||||
|
SILTokenType>()));
|
||||||
|
#endif
|
||||||
|
|
||||||
auto nominal = type->getAnyNominal();
|
auto nominal = type->getAnyNominal();
|
||||||
|
|
||||||
// If we don't have a nominal type, there are no conformances.
|
// If we don't have a nominal type, there are no conformances.
|
||||||
|
|||||||
@@ -116,15 +116,16 @@ CaptureKind TypeConverter::getDeclCaptureKind(CapturedValue capture,
|
|||||||
assert(var->hasStorage() &&
|
assert(var->hasStorage() &&
|
||||||
"should not have attempted to directly capture this variable");
|
"should not have attempted to directly capture this variable");
|
||||||
|
|
||||||
|
auto contextTy = var->getTypeInContext();
|
||||||
auto &lowering = getTypeLowering(
|
auto &lowering = getTypeLowering(
|
||||||
var->getTypeInContext(), TypeExpansionContext::noOpaqueTypeArchetypesSubstitution(
|
contextTy, TypeExpansionContext::noOpaqueTypeArchetypesSubstitution(
|
||||||
expansion.getResilienceExpansion()));
|
expansion.getResilienceExpansion()));
|
||||||
|
|
||||||
// If this is a noncopyable 'let' constant that is not a shared paramdecl or
|
// If this is a noncopyable 'let' constant that is not a shared paramdecl or
|
||||||
// used by a noescape capture, then we know it is boxed and want to pass it in
|
// used by a noescape capture, then we know it is boxed and want to pass it in
|
||||||
// its boxed form so we can obey Swift's capture reference semantics.
|
// its boxed form so we can obey Swift's capture reference semantics.
|
||||||
if (!var->supportsMutation()
|
if (!var->supportsMutation()
|
||||||
&& lowering.getLoweredType().getASTType()->isNoncopyable()
|
&& contextTy->isNoncopyable()
|
||||||
&& !capture.isNoEscape()) {
|
&& !capture.isNoEscape()) {
|
||||||
auto *param = dyn_cast<ParamDecl>(var);
|
auto *param = dyn_cast<ParamDecl>(var);
|
||||||
if (!param || (param->getValueOwnership() != ValueOwnership::Shared &&
|
if (!param || (param->getValueOwnership() != ValueOwnership::Shared &&
|
||||||
|
|||||||
@@ -159,17 +159,28 @@ static void tryEmitContainmentFixits(InFlightDiagnostic &&diag,
|
|||||||
/// MARK: conformance queries
|
/// MARK: conformance queries
|
||||||
|
|
||||||
static bool conformsToInvertible(CanType type, InvertibleProtocolKind ip) {
|
static bool conformsToInvertible(CanType type, InvertibleProtocolKind ip) {
|
||||||
assert(!type->hasTypeParameter() && "forgot to mapTypeIntoContext first");
|
|
||||||
auto &ctx = type->getASTContext();
|
auto &ctx = type->getASTContext();
|
||||||
|
|
||||||
|
auto *invertible = ctx.getProtocol(getKnownProtocolKind(ip));
|
||||||
|
assert(invertible);
|
||||||
|
|
||||||
// Pack expansions such as `repeat T` themselves do not have conformances,
|
// Pack expansions such as `repeat T` themselves do not have conformances,
|
||||||
// so check its pattern type for conformance.
|
// so check its pattern type for conformance.
|
||||||
if (auto *pet = type->getAs<PackExpansionType>()) {
|
if (auto *pet = type->getAs<PackExpansionType>()) {
|
||||||
type = pet->getPatternType()->getCanonicalType();
|
type = pet->getPatternType()->getCanonicalType();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *invertible = ctx.getProtocol(getKnownProtocolKind(ip));
|
// Must either not have a type parameter, or in the case of a
|
||||||
assert(invertible);
|
// BoundGenericXType, have a nominal available.
|
||||||
|
assert(!type->hasTypeParameter() || type.getAnyNominal()
|
||||||
|
&& "caller forgot to mapTypeIntoContext!");
|
||||||
|
|
||||||
|
// The SIL types in the AST do not have real conformances, and should have
|
||||||
|
// been handled earlier.
|
||||||
|
assert(!(type->is<SILBoxType,
|
||||||
|
SILMoveOnlyWrappedType,
|
||||||
|
SILPackType,
|
||||||
|
SILTokenType>()));
|
||||||
|
|
||||||
const bool conforms =
|
const bool conforms =
|
||||||
(bool)TypeChecker::conformsToProtocol(type,
|
(bool)TypeChecker::conformsToProtocol(type,
|
||||||
|
|||||||
Reference in New Issue
Block a user