Skip to content

Commit 34f359d

Browse files
committed
[NCGenerics] fix TypeLowering
1 parent d807198 commit 34f359d

File tree

3 files changed

+91
-32
lines changed

3 files changed

+91
-32
lines changed

lib/AST/Module.cpp

Lines changed: 74 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1671,8 +1671,10 @@ ProtocolConformanceRef ModuleDecl::lookupConformance(Type type,
16711671
if (auto nominal = type->getAnyNominal()) {
16721672
ImplicitKnownProtocolConformanceRequest icvRequest{nominal, *kp};
16731673
if (getASTContext().evaluator.hasActiveRequest(icvRequest) ||
1674-
getASTContext().evaluator.hasActiveRequest(request))
1674+
getASTContext().evaluator.hasActiveRequest(request)) {
1675+
assert(!getInvertibleProtocolKind(*kp));
16751676
return ProtocolConformanceRef::forInvalid();
1677+
}
16761678
}
16771679
}
16781680

@@ -1731,13 +1733,35 @@ static ProtocolConformanceRef getBuiltinTupleTypeConformance(
17311733
return ProtocolConformanceRef::forMissingOrInvalid(type, protocol);
17321734
}
17331735

1736+
using EitherFunctionType =
1737+
llvm::PointerUnion<const SILFunctionType *, const FunctionType *>;
1738+
17341739
/// Whether the given function type conforms to Sendable.
1735-
static bool isSendableFunctionType(const FunctionType *functionType) {
1736-
if (functionType->isSendable())
1737-
return true;
1740+
static bool isSendableFunctionType(EitherFunctionType eitherFnTy) {
1741+
FunctionTypeRepresentation representation;
1742+
1743+
if (auto silFnTy = eitherFnTy.dyn_cast<const SILFunctionType *>()) {
1744+
if (silFnTy->isSendable())
1745+
return true;
1746+
1747+
// convert SILFunctionTypeRepresentation -> FunctionTypeRepresentation
1748+
auto converted = convertRepresentation(silFnTy->getRepresentation());
1749+
if (!converted)
1750+
return false;
1751+
1752+
representation = *converted;
1753+
1754+
} else {
1755+
auto functionType = eitherFnTy.get<const FunctionType *>();
1756+
1757+
if (functionType->isSendable())
1758+
return true;
1759+
1760+
representation = functionType->getExtInfo().getRepresentation();
1761+
}
17381762

17391763
// C and thin function types have no captures, so they are Sendable.
1740-
switch (functionType->getExtInfo().getRepresentation()) {
1764+
switch (representation) {
17411765
case FunctionTypeRepresentation::Block:
17421766
case FunctionTypeRepresentation::Swift:
17431767
return false;
@@ -1749,41 +1773,47 @@ static bool isSendableFunctionType(const FunctionType *functionType) {
17491773
}
17501774

17511775
/// Whether the given function type conforms to Escapable.
1752-
static bool isEscapableFunctionType(const FunctionType *functionType) {
1753-
if (functionType->isNoEscape())
1754-
return false;
1776+
static bool isEscapableFunctionType(EitherFunctionType eitherFnTy) {
1777+
if (auto silFnTy = eitherFnTy.dyn_cast<const SILFunctionType *>()) {
1778+
return !silFnTy->isNoEscape();
1779+
}
17551780

1756-
// FIXME: do we need to also include autoclosures??
1781+
auto functionType = eitherFnTy.get<const FunctionType *>();
17571782

1758-
return true;
1783+
// TODO: what about autoclosures?
1784+
return !functionType->isNoEscape();
17591785
}
17601786

17611787
/// Synthesize a builtin function type conformance to the given protocol, if
17621788
/// appropriate.
17631789
static ProtocolConformanceRef getBuiltinFunctionTypeConformance(
1764-
Type type, const FunctionType *functionType, ProtocolDecl *protocol) {
1790+
Type type, EitherFunctionType functionType, ProtocolDecl *protocol) {
17651791
ASTContext &ctx = protocol->getASTContext();
1766-
// @Sendable function types are Sendable.
1767-
if (protocol->isSpecificProtocol(KnownProtocolKind::Sendable) &&
1768-
isSendableFunctionType(functionType)) {
1769-
return ProtocolConformanceRef(
1770-
ctx.getBuiltinConformance(type, protocol,
1771-
BuiltinConformanceKind::Synthesized));
1772-
}
17731792

1774-
// Functions cannot permanently destroy a move-only var/let
1775-
// that they capture, so it's safe to copy functions, like classes.
1776-
if (protocol->isSpecificProtocol(KnownProtocolKind::Copyable)) {
1793+
auto synthesizeConformance = [&]() -> ProtocolConformanceRef {
17771794
return ProtocolConformanceRef(
17781795
ctx.getBuiltinConformance(type, protocol,
17791796
BuiltinConformanceKind::Synthesized));
1780-
}
1797+
};
17811798

1782-
if (protocol->isSpecificProtocol(KnownProtocolKind::Escapable) &&
1783-
isEscapableFunctionType(functionType)) {
1784-
return ProtocolConformanceRef(
1785-
ctx.getBuiltinConformance(type, protocol,
1786-
BuiltinConformanceKind::Synthesized));
1799+
if (auto kp = protocol->getKnownProtocolKind()) {
1800+
switch (*kp) {
1801+
case KnownProtocolKind::Escapable:
1802+
if (isEscapableFunctionType(functionType))
1803+
return synthesizeConformance();
1804+
break;
1805+
case KnownProtocolKind::Sendable:
1806+
// @Sendable function types are Sendable.
1807+
if (isSendableFunctionType(functionType))
1808+
return synthesizeConformance();
1809+
break;
1810+
case KnownProtocolKind::Copyable:
1811+
// Functions cannot permanently destroy a move-only var/let
1812+
// that they capture, so it's safe to copy functions, like classes.
1813+
return synthesizeConformance();
1814+
default:
1815+
break;
1816+
}
17871817
}
17881818

17891819
return ProtocolConformanceRef::forMissingOrInvalid(type, protocol);
@@ -1959,6 +1989,11 @@ LookupConformanceInModuleRequest::evaluate(
19591989
return getBuiltinFunctionTypeConformance(type, functionType, protocol);
19601990
}
19611991

1992+
// SIL function types in the AST can conform to protocols
1993+
if (auto silFn = type->getAs<SILFunctionType>()) {
1994+
return getBuiltinFunctionTypeConformance(type, silFn, protocol);
1995+
}
1996+
19621997
// Metatypes can conform to protocols.
19631998
if (auto metatypeType = type->getAs<AnyMetatypeType>()) {
19641999
return getBuiltinMetaTypeTypeConformance(type, metatypeType, protocol);
@@ -1969,6 +2004,18 @@ LookupConformanceInModuleRequest::evaluate(
19692004
return getBuiltinBuiltinTypeConformance(type, builtinType, protocol);
19702005
}
19712006

2007+
#ifndef NDEBUG
2008+
// Ensure we haven't missed queries for the specialty SIL types
2009+
// in the AST in conformance to one of the invertible protocols.
2010+
if (auto kp = protocol->getKnownProtocolKind())
2011+
if (getInvertibleProtocolKind(*kp))
2012+
assert(!(type->is<SILFunctionType,
2013+
SILBoxType,
2014+
SILMoveOnlyWrappedType,
2015+
SILPackType,
2016+
SILTokenType>()));
2017+
#endif
2018+
19722019
auto nominal = type->getAnyNominal();
19732020

19742021
// If we don't have a nominal type, there are no conformances.

lib/SIL/IR/TypeLowering.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,15 +116,16 @@ CaptureKind TypeConverter::getDeclCaptureKind(CapturedValue capture,
116116
assert(var->hasStorage() &&
117117
"should not have attempted to directly capture this variable");
118118

119+
auto contextTy = var->getTypeInContext();
119120
auto &lowering = getTypeLowering(
120-
var->getTypeInContext(), TypeExpansionContext::noOpaqueTypeArchetypesSubstitution(
121+
contextTy, TypeExpansionContext::noOpaqueTypeArchetypesSubstitution(
121122
expansion.getResilienceExpansion()));
122123

123124
// If this is a noncopyable 'let' constant that is not a shared paramdecl or
124125
// used by a noescape capture, then we know it is boxed and want to pass it in
125126
// its boxed form so we can obey Swift's capture reference semantics.
126127
if (!var->supportsMutation()
127-
&& lowering.getLoweredType().getASTType()->isNoncopyable()
128+
&& contextTy->isNoncopyable()
128129
&& !capture.isNoEscape()) {
129130
auto *param = dyn_cast<ParamDecl>(var);
130131
if (!param || (param->getValueOwnership() != ValueOwnership::Shared &&

lib/Sema/TypeCheckInvertible.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,17 +159,28 @@ static void tryEmitContainmentFixits(InFlightDiagnostic &&diag,
159159
/// MARK: conformance queries
160160

161161
static bool conformsToInvertible(CanType type, InvertibleProtocolKind ip) {
162-
assert(!type->hasTypeParameter() && "forgot to mapTypeIntoContext first");
163162
auto &ctx = type->getASTContext();
164163

164+
auto *invertible = ctx.getProtocol(getKnownProtocolKind(ip));
165+
assert(invertible);
166+
165167
// Pack expansions such as `repeat T` themselves do not have conformances,
166168
// so check its pattern type for conformance.
167169
if (auto *pet = type->getAs<PackExpansionType>()) {
168170
type = pet->getPatternType()->getCanonicalType();
169171
}
170172

171-
auto *invertible = ctx.getProtocol(getKnownProtocolKind(ip));
172-
assert(invertible);
173+
// Must either not have a type parameter, or in the case of a
174+
// BoundGenericXType, have a nominal available.
175+
assert(!type->hasTypeParameter() || type.getAnyNominal()
176+
&& "caller forgot to mapTypeIntoContext!");
177+
178+
// The SIL types in the AST do not have real conformances, and should have
179+
// been handled earlier.
180+
assert(!(type->is<SILBoxType,
181+
SILMoveOnlyWrappedType,
182+
SILPackType,
183+
SILTokenType>()));
173184

174185
const bool conforms =
175186
(bool)TypeChecker::conformsToProtocol(type,

0 commit comments

Comments
 (0)