Skip to content

Commit 5e9bf1f

Browse files
[SIL] Store ClangTypeInfo in SILFunctionType.
This patch includes a large number of changes to make sure that: 1. When ExtInfo values are created, we store a ClangTypeInfo if applicable. 2. We reduce dependence on storing SIL representations in ASTExtInfo values. 3. Reduce places where we sloppily create ASTExtInfo values which should store a Clang type but don't. In certain places, this is unavoidable; see [NOTE: ExtInfo-Clang-type-invariant]. Ideally, we would check that the appropriate SILExtInfo does always store a ClangTypeInfo. However, the presence of the HasClangFunctionTypes option means that we would need to condition that assertion based on a dynamic check. Plumbing the setting down to SILExtInfoBuilder's checkInvariants would be too much work. So we weaken the check for now; we should strengthen it once we "turn on" HasClangFunctionTypes and remove the dynamic feature switch.
1 parent e48469d commit 5e9bf1f

22 files changed

+580
-273
lines changed

include/swift/AST/ExtInfo.h

Lines changed: 94 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class FunctionType;
4141
class SILExtInfo;
4242
class SILExtInfoBuilder;
4343
class SILFunctionType;
44+
enum class SILFunctionTypeRepresentation : uint8_t;
4445
} // namespace swift
4546

4647
namespace swift {
@@ -54,6 +55,7 @@ class ClangTypeInfo {
5455
friend ASTExtInfoBuilder;
5556
friend SILExtInfoBuilder;
5657

58+
// [NOTE: ClangTypeInfo-contents]
5759
// We preserve a full clang::Type *, not a clang::FunctionType * as:
5860
// 1. We need to keep sugar in case we need to present an error to the user
5961
// (for AnyFunctionType).
@@ -81,6 +83,26 @@ class ClangTypeInfo {
8183
void dump(llvm::raw_ostream &os, const clang::ASTContext &ctx) const;
8284
};
8385

86+
// MARK: - UnexpectedClangTypeError
87+
/// Potential errors when trying to store a Clang type in an ExtInfo.
88+
struct UnexpectedClangTypeError {
89+
enum class Kind {
90+
NullForCOrBlock,
91+
NonnullForNonCOrBlock,
92+
NotBlockPointer,
93+
NotFunctionPointerOrReference,
94+
NonCanonical,
95+
};
96+
const Kind errorKind;
97+
const clang::Type *type;
98+
99+
static Optional<UnexpectedClangTypeError> checkClangType(
100+
SILFunctionTypeRepresentation fnRep, const clang::Type *type,
101+
bool expectNonnullForCOrBlock, bool expectCanonical);
102+
103+
void dump();
104+
};
105+
84106
// MARK: - FunctionTypeRepresentation
85107
/// The representation form of a function.
86108
enum class FunctionTypeRepresentation : uint8_t {
@@ -146,6 +168,41 @@ enum class SILFunctionTypeRepresentation : uint8_t {
146168
Closure,
147169
};
148170

171+
constexpr SILFunctionTypeRepresentation
172+
convertRepresentation(FunctionTypeRepresentation rep) {
173+
switch (rep) {
174+
case FunctionTypeRepresentation::Swift:
175+
return SILFunctionTypeRepresentation::Thick;
176+
case FunctionTypeRepresentation::Block:
177+
return SILFunctionTypeRepresentation::Block;
178+
case FunctionTypeRepresentation::Thin:
179+
return SILFunctionTypeRepresentation::Thin;
180+
case FunctionTypeRepresentation::CFunctionPointer:
181+
return SILFunctionTypeRepresentation::CFunctionPointer;
182+
}
183+
llvm_unreachable("Unhandled FunctionTypeRepresentation!");
184+
};
185+
186+
inline Optional<FunctionTypeRepresentation>
187+
convertRepresentation(SILFunctionTypeRepresentation rep) {
188+
switch (rep) {
189+
case SILFunctionTypeRepresentation::Thick:
190+
return {FunctionTypeRepresentation::Swift};
191+
case SILFunctionTypeRepresentation::Block:
192+
return {FunctionTypeRepresentation::Block};
193+
case SILFunctionTypeRepresentation::Thin:
194+
return {FunctionTypeRepresentation::Thin};
195+
case SILFunctionTypeRepresentation::CFunctionPointer:
196+
return {FunctionTypeRepresentation::CFunctionPointer};
197+
case SILFunctionTypeRepresentation::Method:
198+
case SILFunctionTypeRepresentation::ObjCMethod:
199+
case SILFunctionTypeRepresentation::WitnessMethod:
200+
case SILFunctionTypeRepresentation::Closure:
201+
return None;
202+
}
203+
llvm_unreachable("Unhandled SILFunctionTypeRepresentation!");
204+
};
205+
149206
/// Can this calling convention result in a function being called indirectly
150207
/// through the runtime.
151208
constexpr bool canBeCalledIndirectly(SILFunctionTypeRepresentation rep) {
@@ -165,6 +222,25 @@ constexpr bool canBeCalledIndirectly(SILFunctionTypeRepresentation rep) {
165222
llvm_unreachable("Unhandled SILFunctionTypeRepresentation in switch.");
166223
}
167224

225+
template <typename Repr> constexpr bool shouldStoreClangType(Repr repr) {
226+
static_assert(std::is_same<Repr, FunctionTypeRepresentation>::value ||
227+
std::is_same<Repr, SILFunctionTypeRepresentation>::value,
228+
"Expected a Representation type as the argument type.");
229+
switch (static_cast<SILFunctionTypeRepresentation>(repr)) {
230+
case SILFunctionTypeRepresentation::CFunctionPointer:
231+
case SILFunctionTypeRepresentation::Block:
232+
return true;
233+
case SILFunctionTypeRepresentation::ObjCMethod:
234+
case SILFunctionTypeRepresentation::Thick:
235+
case SILFunctionTypeRepresentation::Thin:
236+
case SILFunctionTypeRepresentation::Method:
237+
case SILFunctionTypeRepresentation::WitnessMethod:
238+
case SILFunctionTypeRepresentation::Closure:
239+
return false;
240+
}
241+
llvm_unreachable("Unhandled SILFunctionTypeRepresentation.");
242+
}
243+
168244
// MARK: - ASTExtInfoBuilder
169245
/// A builder type for creating an \c ASTExtInfo.
170246
///
@@ -292,7 +368,8 @@ class ASTExtInfoBuilder {
292368
LLVM_NODISCARD
293369
ASTExtInfoBuilder withRepresentation(Representation rep) const {
294370
return ASTExtInfoBuilder((bits & ~RepresentationMask) | (unsigned)rep,
295-
clangTypeInfo);
371+
shouldStoreClangType(rep) ? clangTypeInfo
372+
: ClangTypeInfo());
296373
}
297374
LLVM_NODISCARD
298375
ASTExtInfoBuilder withNoEscape(bool noEscape = true) const {
@@ -333,7 +410,8 @@ class ASTExtInfoBuilder {
333410
ASTExtInfoBuilder
334411
withSILRepresentation(SILFunctionTypeRepresentation rep) const {
335412
return ASTExtInfoBuilder((bits & ~RepresentationMask) | (unsigned)rep,
336-
clangTypeInfo);
413+
shouldStoreClangType(rep) ? clangTypeInfo
414+
: ClangTypeInfo());
337415
}
338416

339417
bool isEqualTo(ASTExtInfoBuilder other, bool useClangTypes) const {
@@ -508,7 +586,7 @@ class SILExtInfoBuilder {
508586
using Representation = SILFunctionTypeRepresentation;
509587

510588
SILExtInfoBuilder(unsigned bits, ClangTypeInfo clangTypeInfo)
511-
: bits(bits), clangTypeInfo(clangTypeInfo) {}
589+
: bits(bits), clangTypeInfo(clangTypeInfo.getCanonical()) {}
512590

513591
static constexpr unsigned makeBits(Representation rep, bool isPseudogeneric,
514592
bool isNoEscape, bool isAsync,
@@ -610,7 +688,8 @@ class SILExtInfoBuilder {
610688
// the following with methods instead of mutating these objects.
611689
SILExtInfoBuilder withRepresentation(Representation rep) const {
612690
return SILExtInfoBuilder((bits & ~RepresentationMask) | (unsigned)rep,
613-
clangTypeInfo);
691+
shouldStoreClangType(rep) ? clangTypeInfo
692+
: ClangTypeInfo());
614693
}
615694
SILExtInfoBuilder withIsPseudogeneric(bool isPseudogeneric = true) const {
616695
return SILExtInfoBuilder(isPseudogeneric ? (bits | PseudogenericMask)
@@ -633,6 +712,10 @@ class SILExtInfoBuilder {
633712
((unsigned)differentiability << DifferentiabilityMaskOffset),
634713
clangTypeInfo);
635714
}
715+
LLVM_NODISCARD
716+
SILExtInfoBuilder withClangFunctionType(const clang::Type *type) const {
717+
return SILExtInfoBuilder(bits, ClangTypeInfo(type).getCanonical());
718+
}
636719

637720
bool isEqualTo(SILExtInfoBuilder other, bool useClangTypes) const {
638721
return bits == other.bits &&
@@ -669,6 +752,11 @@ class SILExtInfo {
669752
public:
670753
SILExtInfo() : builder() { builder.checkInvariants(); };
671754

755+
SILExtInfo(ASTExtInfo info, bool isPseudogeneric)
756+
: builder(info.intoBuilder(), isPseudogeneric) {
757+
builder.checkInvariants();
758+
}
759+
672760
static SILExtInfo getThin() {
673761
return SILExtInfoBuilder(SILExtInfoBuilder::Representation::Thin, false,
674762
false, false,
@@ -730,6 +818,8 @@ class SILExtInfo {
730818
constexpr std::pair<unsigned, const void *> getFuncAttrKey() const {
731819
return builder.getFuncAttrKey();
732820
}
821+
822+
Optional<UnexpectedClangTypeError> checkClangType() const;
733823
};
734824

735825
/// Helper function to obtain the useClangTypes parameter for checking equality

include/swift/AST/Types.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3888,7 +3888,7 @@ class SILFunctionType final
38883888
public llvm::FoldingSetNode,
38893889
private llvm::TrailingObjects<SILFunctionType, SILParameterInfo,
38903890
SILResultInfo, SILYieldInfo,
3891-
SubstitutionMap, CanType> {
3891+
SubstitutionMap, CanType, ClangTypeInfo> {
38923892
friend TrailingObjects;
38933893

38943894
size_t numTrailingObjects(OverloadToken<SILParameterInfo>) const {
@@ -3912,6 +3912,10 @@ class SILFunctionType final
39123912
size_t(hasInvocationSubstitutions());
39133913
}
39143914

3915+
size_t numTrailingObjects(OverloadToken<ClangTypeInfo>) const {
3916+
return Bits.SILFunctionType.HasClangTypeInfo ? 1 : 0;
3917+
}
3918+
39153919
public:
39163920
using ExtInfo = SILExtInfo;
39173921
using ExtInfoBuilder = SILExtInfoBuilder;

include/swift/SIL/TypeLowering.h

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -55,20 +55,17 @@ CanAnyFunctionType adjustFunctionType(CanAnyFunctionType type,
5555
AnyFunctionType::ExtInfo extInfo);
5656

5757
/// Change the given function type's representation.
58-
inline CanAnyFunctionType adjustFunctionType(CanAnyFunctionType t,
59-
SILFunctionType::Representation rep) {
60-
auto extInfo =
61-
t->getExtInfo().intoBuilder().withSILRepresentation(rep).build();
62-
return adjustFunctionType(t, extInfo);
58+
inline CanAnyFunctionType
59+
adjustFunctionType(CanAnyFunctionType t, AnyFunctionType::Representation rep,
60+
ClangTypeInfo clangTypeInfo) {
61+
auto extInfo = t->getExtInfo()
62+
.intoBuilder()
63+
.withRepresentation(rep)
64+
.withClangFunctionType(clangTypeInfo.getType())
65+
.build();
66+
return adjustFunctionType(t, extInfo);
6367
}
6468

65-
/// Change the given function type's representation.
66-
inline CanAnyFunctionType adjustFunctionType(CanAnyFunctionType t,
67-
AnyFunctionType::Representation rep) {
68-
auto extInfo = t->getExtInfo().withRepresentation(rep);
69-
return adjustFunctionType(t, extInfo);
70-
}
71-
7269
/// Given a SIL function type, return a type that is identical except
7370
/// for using the given ExtInfo.
7471
CanSILFunctionType
@@ -992,7 +989,8 @@ class TypeConverter {
992989
/// Given a function type, yield its bridged formal type.
993990
CanAnyFunctionType getBridgedFunctionType(AbstractionPattern fnPattern,
994991
CanAnyFunctionType fnType,
995-
Bridgeability bridging);
992+
Bridgeability bridging,
993+
SILFunctionTypeRepresentation rep);
996994

997995
/// Given a referenced value and the substituted formal type of a
998996
/// resulting l-value expression, produce the substituted formal
@@ -1121,7 +1119,7 @@ class TypeConverter {
11211119
CanSILFunctionType getNativeSILFunctionType(
11221120
Lowering::TypeConverter &TC, TypeExpansionContext context,
11231121
Lowering::AbstractionPattern origType, CanAnyFunctionType substType,
1124-
Optional<SILDeclRef> origConstant = None,
1122+
SILExtInfo silExtInfo, Optional<SILDeclRef> origConstant = None,
11251123
Optional<SILDeclRef> constant = None,
11261124
Optional<SubstitutionMap> reqtSubs = None,
11271125
ProtocolConformanceRef witnessMethodConformance = ProtocolConformanceRef());

lib/AST/ASTContext.cpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3246,6 +3246,9 @@ GenericFunctionType *GenericFunctionType::get(GenericSignature sig,
32463246
// point.
32473247
bool isCanonical = isGenericFunctionTypeCanonical(sig, params, result);
32483248

3249+
assert(info.getClangTypeInfo().empty() &&
3250+
"Generic functions do not have Clang types at the moment.");
3251+
32493252
if (auto funcTy
32503253
= ctx.getImpl().GenericFunctionTypes.FindNodeOrInsertPos(id, insertPos)) {
32513254
return funcTy;
@@ -3365,6 +3368,7 @@ SILFunctionType::SILFunctionType(
33653368
"Bits were dropped!");
33663369
static_assert(SILExtInfoBuilder::NumMaskBits == NumSILExtInfoBits,
33673370
"ExtInfo and SILFunctionTypeBitfields must agree on bit size");
3371+
Bits.SILFunctionType.HasClangTypeInfo = !ext.getClangTypeInfo().empty();
33683372
Bits.SILFunctionType.CoroutineKind = unsigned(coroutineKind);
33693373
NumParameters = params.size();
33703374
if (coroutineKind == SILCoroutineKind::None) {
@@ -3402,6 +3406,9 @@ SILFunctionType::SILFunctionType(
34023406
getMutableFormalResultsCache() = CanType();
34033407
getMutableAllResultsCache() = CanType();
34043408
}
3409+
if (!ext.getClangTypeInfo().empty())
3410+
*getTrailingObjects<ClangTypeInfo>() = ext.getClangTypeInfo();
3411+
34053412
#ifndef NDEBUG
34063413
if (ext.getRepresentation() == Representation::WitnessMethod)
34073414
assert(!WitnessMethodConformance.isInvalid() &&
@@ -3524,6 +3531,21 @@ CanSILFunctionType SILFunctionType::get(
35243531

35253532
patternSubs = patternSubs.getCanonical();
35263533
invocationSubs = invocationSubs.getCanonical();
3534+
3535+
// [FIXME: Clang-type-plumbing]
3536+
if (ctx.LangOpts.UseClangFunctionTypes) {
3537+
if (auto error = ext.checkClangType()) {
3538+
error.getValue().dump();
3539+
llvm_unreachable("Unexpected Clang type in SILExtInfo.");
3540+
}
3541+
} else if (!ext.getClangTypeInfo().empty()) {
3542+
// Unlike AnyFunctionType, SILFunctionType is always canonical. Hence,
3543+
// conditionalizing canonical type computation based on
3544+
// UseClangFunctionTypes like AnyFunctionType is not feasible. It is simpler
3545+
// to drop the Clang type altogether.
3546+
ext = ext.intoBuilder().withClangFunctionType(nullptr).build();
3547+
}
3548+
35273549

35283550
llvm::FoldingSetNodeID id;
35293551
SILFunctionType::Profile(id, genericSig, ext, coroutineKind, callee, params,
@@ -3541,12 +3563,11 @@ CanSILFunctionType SILFunctionType::get(
35413563

35423564
// See [NOTE: SILFunctionType-layout]
35433565
bool hasResultCache = normalResults.size() > 1;
3544-
size_t bytes =
3545-
totalSizeToAlloc<SILParameterInfo, SILResultInfo, SILYieldInfo,
3546-
SubstitutionMap, CanType>(
3566+
size_t bytes = totalSizeToAlloc<SILParameterInfo, SILResultInfo, SILYieldInfo,
3567+
SubstitutionMap, CanType, ClangTypeInfo>(
35473568
params.size(), normalResults.size() + (errorResult ? 1 : 0),
35483569
yields.size(), (patternSubs ? 1 : 0) + (invocationSubs ? 1 : 0),
3549-
hasResultCache ? 2 : 0);
3570+
hasResultCache ? 2 : 0, ext.getClangTypeInfo().empty() ? 0 : 1);
35503571

35513572
void *mem = ctx.Allocate(bytes, alignof(SILFunctionType));
35523573

lib/AST/ASTDemangler.cpp

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ Type ASTBuilder::createFunctionType(
396396
&& !flags.isEscaping();
397397

398398
const clang::Type *clangFunctionType = nullptr;
399-
if (representation == FunctionTypeRepresentation::CFunctionPointer)
399+
if (shouldStoreClangType(representation))
400400
clangFunctionType = Ctx.getClangFunctionType(funcParams, output,
401401
representation);
402402

@@ -523,12 +523,6 @@ Type ASTBuilder::createImplFunctionType(
523523
break;
524524
}
525525

526-
// [TODO: Store-SIL-Clang-type]
527-
auto einfo = SILExtInfoBuilder(representation, flags.isPseudogeneric(),
528-
!flags.isEscaping(), flags.isAsync(), diffKind,
529-
/*clangFunctionType*/ nullptr)
530-
.build();
531-
532526
llvm::SmallVector<SILParameterInfo, 8> funcParams;
533527
llvm::SmallVector<SILYieldInfo, 8> funcYields;
534528
llvm::SmallVector<SILResultInfo, 8> funcResults;
@@ -553,6 +547,21 @@ Type ASTBuilder::createImplFunctionType(
553547
auto conv = getResultConvention(errorResult->getConvention());
554548
funcErrorResult.emplace(type, conv);
555549
}
550+
551+
const clang::Type *clangFnType = nullptr;
552+
if (shouldStoreClangType(representation)) {
553+
assert(funcResults.size() <= 1 && funcYields.size() == 0 &&
554+
"C functions and blocks have at most 1 result and 0 yields.");
555+
auto result =
556+
funcResults.empty() ? Optional<SILResultInfo>() : funcResults[0];
557+
clangFnType = getASTContext().getCanonicalClangFunctionType(
558+
funcParams, result, representation);
559+
}
560+
auto einfo = SILFunctionType::ExtInfoBuilder(
561+
representation, flags.isPseudogeneric(), !flags.isEscaping(),
562+
flags.isAsync(), diffKind, clangFnType)
563+
.build();
564+
556565
return SILFunctionType::get(genericSig, einfo, funcCoroutineKind,
557566
funcCalleeConvention, funcParams, funcYields,
558567
funcResults, funcErrorResult,

lib/AST/ASTDumper.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3831,6 +3831,14 @@ namespace {
38313831
OS << '\n';
38323832
T->getInvocationSubstitutions().dump(OS, SubstitutionMap::DumpStyle::Full,
38333833
Indent+2);
3834+
if (!T->getClangTypeInfo().empty()) {
3835+
std::string s;
3836+
llvm::raw_string_ostream os(s);
3837+
auto &ctx =
3838+
T->getASTContext().getClangModuleLoader()->getClangASTContext();
3839+
T->getClangTypeInfo().dump(os, ctx);
3840+
printField("clang_type", os.str());
3841+
}
38343842
PrintWithColorRAII(OS, ParenthesisColor) << ')';
38353843
}
38363844

0 commit comments

Comments
 (0)