Skip to content

Commit e9595ab

Browse files
committed
[TypeLowering] Verify lexical property.
Check that if a type is non-trivial then either (1) it is lexical or (2) its non-trivial leaves are @_eagerMove.
1 parent 496c1d2 commit e9595ab

File tree

4 files changed

+185
-0
lines changed

4 files changed

+185
-0
lines changed

include/swift/SIL/SILType.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,25 @@ class SILType {
753753
void dump() const;
754754
void print(raw_ostream &OS,
755755
const PrintOptions &PO = PrintOptions::printSIL()) const;
756+
757+
#ifndef NDEBUG
758+
/// Visit the distinct types of the fields out of which a type is aggregated.
759+
///
760+
/// As we walk into the field types, if an aggregate is encountered, it may
761+
/// still be a leaf. It is a leaf if the \p isLeafAggregate predicate
762+
/// returns true.
763+
///
764+
/// Returns false if the leaves cannot be visited or if any invocation of the
765+
/// visitor returns false.
766+
///
767+
/// NOTE: This function is meant for use in verification. For real use-cases,
768+
/// recursive walks of type leaves should be done via
769+
/// TypeLowering::RecursiveProperties.
770+
bool visitAggregateLeaves(
771+
Lowering::TypeConverter &TC, TypeExpansionContext context,
772+
std::function<bool(SILType, SILType, VarDecl *)> isLeafAggregate,
773+
std::function<bool(SILType, SILType, VarDecl *)> visit) const;
774+
#endif
756775
};
757776

758777
// Statically prevent SILTypes from being directly cast to a type

include/swift/SIL/TypeLowering.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,6 +1245,12 @@ class TypeConverter {
12451245
CanType result,
12461246
Bridgeability bridging,
12471247
bool suppressOptional);
1248+
#ifndef NDEBUG
1249+
/// Check the result of
1250+
/// getTypeLowering(AbstractionPattern,Type,TypeExpansionContext).
1251+
void verifyLowering(const TypeLowering &, AbstractionPattern origType,
1252+
Type origSubstType, TypeExpansionContext forExpansion);
1253+
#endif
12481254
};
12491255

12501256
} // namespace Lowering

lib/SIL/IR/SILType.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "swift/SIL/SILFunctionConventions.h"
2323
#include "swift/SIL/SILModule.h"
2424
#include "swift/SIL/TypeLowering.h"
25+
#include <tuple>
2526

2627
using namespace swift;
2728
using namespace swift::Lowering;
@@ -941,3 +942,66 @@ bool SILType::isMoveOnly() const {
941942
return true;
942943
return isMoveOnlyWrapped();
943944
}
945+
946+
#ifndef NDEBUG
947+
bool SILType::visitAggregateLeaves(
948+
Lowering::TypeConverter &TC, TypeExpansionContext context,
949+
std::function<bool(SILType, SILType, VarDecl *)> isLeaf,
950+
std::function<bool(SILType, SILType, VarDecl *)> visit) const {
951+
952+
llvm::SmallSet<std::tuple<SILType::ValueType, SILType::ValueType, VarDecl *>,
953+
16>
954+
visited;
955+
llvm::SmallVector<
956+
std::tuple<SILType::ValueType, SILType::ValueType, VarDecl *>, 16>
957+
worklist;
958+
auto insertIntoWorklist = [&visited, &worklist](SILType parent, SILType type,
959+
VarDecl *decl) -> bool {
960+
if (!visited.insert({parent.value, type.value, decl}).second) {
961+
return false;
962+
}
963+
worklist.push_back({parent.value, type.value, decl});
964+
return true;
965+
};
966+
auto popFromWorklist =
967+
[&worklist]() -> std::tuple<SILType, SILType, VarDecl *> {
968+
SILType::ValueType parentOpaqueType;
969+
SILType::ValueType opaqueType;
970+
VarDecl *decl;
971+
std::tie(parentOpaqueType, opaqueType, decl) = worklist.pop_back_val();
972+
return {parentOpaqueType, opaqueType, decl};
973+
};
974+
insertIntoWorklist(SILType(), *this, nullptr);
975+
while (!worklist.empty()) {
976+
SILType parent;
977+
SILType ty;
978+
VarDecl *decl;
979+
std::tie(parent, ty, decl) = popFromWorklist();
980+
if (ty.isAggregate() && !isLeaf(parent, ty, decl)) {
981+
if (auto tupleTy = ty.getAs<TupleType>()) {
982+
for (unsigned index = 0, num = tupleTy->getNumElements(); index < num;
983+
++index) {
984+
insertIntoWorklist(ty, ty.getTupleElementType(index), nullptr);
985+
}
986+
} else if (auto *decl = ty.getStructOrBoundGenericStruct()) {
987+
for (auto *field : decl->getStoredProperties()) {
988+
insertIntoWorklist(ty, ty.getFieldType(field, TC, context), field);
989+
}
990+
} else if (auto *decl = ty.getEnumOrBoundGenericEnum()) {
991+
for (auto *field : decl->getStoredProperties()) {
992+
insertIntoWorklist(ty, ty.getFieldType(field, TC, context), field);
993+
}
994+
} else {
995+
llvm_unreachable("unknown aggregate kind!");
996+
}
997+
continue;
998+
}
999+
1000+
// This type is a leaf. Visit it.
1001+
auto success = visit(parent, ty, decl);
1002+
if (!success)
1003+
return false;
1004+
}
1005+
return true;
1006+
}
1007+
#endif

lib/SIL/IR/TypeLowering.cpp

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2420,9 +2420,105 @@ TypeConverter::getTypeLowering(AbstractionPattern origType,
24202420
removeNullEntry(key.getKeyForMinimalExpansion());
24212421
#endif
24222422
}
2423+
2424+
#ifndef NDEBUG
2425+
verifyLowering(*lowering, origType, origSubstType, forExpansion);
2426+
#endif
2427+
24232428
return *lowering;
24242429
}
24252430

2431+
#ifndef NDEBUG
2432+
void TypeConverter::verifyLowering(const TypeLowering &lowering,
2433+
AbstractionPattern origType,
2434+
Type origSubstType,
2435+
TypeExpansionContext forExpansion) {
2436+
// Non-trivial lowerings should always be lexical unless all non-trivial
2437+
// fields are eager move.
2438+
if (!lowering.isTrivial() && !lowering.isLexical()) {
2439+
auto getLifetimeAnnotation = [](SILType ty) -> LifetimeAnnotation {
2440+
NominalTypeDecl *nominal;
2441+
if (!(nominal = ty.getASTType().getAnyNominal()))
2442+
return LifetimeAnnotation::None;
2443+
return nominal->getLifetimeAnnotation();
2444+
};
2445+
auto loweredType = lowering.getLoweredType();
2446+
bool hasNoNontrivialLexicalLeaf = loweredType.visitAggregateLeaves(
2447+
*this, forExpansion,
2448+
/*isLeaf=*/
2449+
[&](auto parent, auto ty, auto *fieldDecl) -> bool {
2450+
// The field's type is an aggregate. Treat it as a leaf if it
2451+
// has a lifetime annotation.
2452+
2453+
// If we don't have a field decl, it's either a field of a tuple
2454+
// or the top-level type. Either way, there's no var decl on
2455+
// which to look for an attribute.
2456+
//
2457+
// It's a leaf if the type has a lifetime annotation.
2458+
if (!fieldDecl)
2459+
return getLifetimeAnnotation(ty).isSome();
2460+
2461+
// It's a field of a struct or an enum. It's a leaf if the type
2462+
// or the var decl has a lifetime annotation.
2463+
return fieldDecl->getLifetimeAnnotation().isSome() ||
2464+
getLifetimeAnnotation(ty);
2465+
},
2466+
/*visit=*/
2467+
[&](auto parent, auto ty, auto *fieldDecl) -> bool {
2468+
// Look at each leaf: if it is non-trivial, verify that it is
2469+
// attributed @_eagerMove.
2470+
2471+
// If the leaf is the whole type, verify that it is annotated
2472+
// @_eagerMove.
2473+
if (ty == loweredType)
2474+
return getLifetimeAnnotation(ty) == LifetimeAnnotation::EagerMove;
2475+
2476+
// Get ty's lowering.
2477+
CanGenericSignature sig;
2478+
if (fieldDecl) {
2479+
AbstractionPattern origFieldTy = getAbstractionPattern(fieldDecl);
2480+
CanType substFieldTy;
2481+
if (fieldDecl->hasClangNode()) {
2482+
substFieldTy = origFieldTy.getType();
2483+
} else {
2484+
substFieldTy = parent.getASTType()
2485+
->getTypeOfMember(&M, fieldDecl)
2486+
->getCanonicalType();
2487+
}
2488+
sig = getAbstractionPattern(fieldDecl).getGenericSignatureOrNull();
2489+
} else {
2490+
sig = CanGenericSignature();
2491+
}
2492+
auto &tyLowering = getTypeLowering(ty, forExpansion, sig);
2493+
2494+
// Leaves which are trivial aren't of interest.
2495+
if (tyLowering.isTrivial())
2496+
return true;
2497+
2498+
// We're visiting a non-trival leaf of a type whose lowering is
2499+
// not lexical. The leaf must be annotated @_eagerMove.
2500+
// Otherwise, the whole type would be lexical.
2501+
2502+
if (!fieldDecl) {
2503+
// The field is non-trivial and the whole type is non-lexical.
2504+
// If there's no field decl which might be annotated
2505+
// @_eagerMove, we have a problem.
2506+
return false;
2507+
}
2508+
2509+
// The field is non-trivial and the whole type is non-lexical.
2510+
// That's fine as long as the field or its type is annotated
2511+
// @_eagerMove.
2512+
return fieldDecl->getLifetimeAnnotation() ==
2513+
LifetimeAnnotation::EagerMove ||
2514+
getLifetimeAnnotation(ty) == LifetimeAnnotation::EagerMove;
2515+
});
2516+
assert(hasNoNontrivialLexicalLeaf &&
2517+
"Found non-trivial lexical leaf in non-trivial non-lexical type?!");
2518+
}
2519+
}
2520+
#endif
2521+
24262522
CanType
24272523
TypeConverter::computeLoweredRValueType(TypeExpansionContext forExpansion,
24282524
AbstractionPattern origType,

0 commit comments

Comments
 (0)