Skip to content

Commit 5372177

Browse files
Merge pull request #61042 from nate-chandler/fix-lexical-recursive-properties-bug
Fix bug with lexical recursive property.
2 parents 21adff9 + f53e88b commit 5372177

File tree

5 files changed

+150
-130
lines changed

5 files changed

+150
-130
lines changed

include/swift/SIL/SILType.h

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#include "swift/AST/SILLayout.h"
2222
#include "swift/AST/Types.h"
23+
#include "swift/SIL/AbstractionPattern.h"
2324
#include "swift/SIL/Lifetime.h"
2425
#include "llvm/ADT/Hashing.h"
2526
#include "llvm/ADT/PointerIntPair.h"
@@ -753,25 +754,6 @@ class SILType {
753754
void dump() const;
754755
void print(raw_ostream &OS,
755756
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
775757
};
776758

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

include/swift/SIL/TypeLowering.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,6 +1250,15 @@ class TypeConverter {
12501250
/// getTypeLowering(AbstractionPattern,Type,TypeExpansionContext).
12511251
void verifyLowering(const TypeLowering &, AbstractionPattern origType,
12521252
Type origSubstType, TypeExpansionContext forExpansion);
1253+
bool
1254+
visitAggregateLeaves(Lowering::AbstractionPattern origType, Type substType,
1255+
TypeExpansionContext context,
1256+
std::function<bool(Type, Lowering::AbstractionPattern,
1257+
ValueDecl *, Optional<unsigned>)>
1258+
isLeafAggregate,
1259+
std::function<bool(Type, Lowering::AbstractionPattern,
1260+
ValueDecl *, Optional<unsigned>)>
1261+
visit);
12531262
#endif
12541263
};
12551264

lib/SIL/IR/SILType.cpp

Lines changed: 0 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -942,66 +942,3 @@ bool SILType::isMoveOnly() const {
942942
return true;
943943
return isMoveOnlyWrapped();
944944
}
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: 133 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2110,6 +2110,7 @@ namespace {
21102110
if (D->isCxxNonTrivial()) {
21112111
properties.setAddressOnly();
21122112
properties.setNonTrivial();
2113+
properties.setLexical(IsLexical);
21132114
}
21142115

21152116
auto subMap = structType->getContextSubstitutionMap(&TC.M, D);
@@ -2169,6 +2170,9 @@ namespace {
21692170
// may be added resiliently later.
21702171
if (D->isIndirect()) {
21712172
properties.setNonTrivial();
2173+
properties.setLexical(IsLexical);
2174+
properties =
2175+
applyLifetimeAnnotation(D->getLifetimeAnnotation(), properties);
21722176
return new (TC) LoadableEnumTypeLowering(enumType, properties,
21732177
Expansion);
21742178
}
@@ -2184,6 +2188,9 @@ namespace {
21842188
// Indirect elements only make the type nontrivial.
21852189
if (elt->isIndirect()) {
21862190
properties.setNonTrivial();
2191+
properties.setLexical(IsLexical);
2192+
properties =
2193+
applyLifetimeAnnotation(elt->getLifetimeAnnotation(), properties);
21872194
continue;
21882195
}
21892196

@@ -2433,74 +2440,160 @@ TypeConverter::getTypeLowering(AbstractionPattern origType,
24332440
}
24342441

24352442
#ifndef NDEBUG
2436-
verifyLowering(*lowering, origType, origSubstType, forExpansion);
2443+
verifyLowering(*lowering, origType, loweredSubstType, forExpansion);
24372444
#endif
24382445

24392446
return *lowering;
24402447
}
24412448

24422449
#ifndef NDEBUG
2450+
bool TypeConverter::visitAggregateLeaves(
2451+
Lowering::AbstractionPattern origType, Type substType,
2452+
TypeExpansionContext context,
2453+
std::function<bool(Type, Lowering::AbstractionPattern, ValueDecl *,
2454+
Optional<unsigned>)>
2455+
isLeafAggregate,
2456+
std::function<bool(Type, Lowering::AbstractionPattern, ValueDecl *,
2457+
Optional<unsigned>)>
2458+
visit) {
2459+
llvm::SmallSet<std::tuple<TypeBase *, ValueDecl *, unsigned>, 16> visited;
2460+
llvm::SmallVector<
2461+
std::tuple<TypeBase *, AbstractionPattern, ValueDecl *, unsigned>, 16>
2462+
worklist;
2463+
auto insertIntoWorklist = [&visited,
2464+
&worklist](Type substTy, AbstractionPattern origTy,
2465+
ValueDecl *field,
2466+
Optional<unsigned> maybeIndex) -> bool {
2467+
unsigned index = maybeIndex.getValueOr(UINT_MAX);
2468+
if (!visited.insert({substTy.getPointer(), field, index}).second)
2469+
return false;
2470+
worklist.push_back({substTy.getPointer(), origTy, field, index});
2471+
return true;
2472+
};
2473+
auto popFromWorklist = [&worklist]()
2474+
-> std::tuple<Type, AbstractionPattern, ValueDecl *, Optional<unsigned>> {
2475+
TypeBase *ty;
2476+
AbstractionPattern origTy = AbstractionPattern::getOpaque();
2477+
ValueDecl *field;
2478+
unsigned index;
2479+
std::tie(ty, origTy, field, index) = worklist.pop_back_val();
2480+
Optional<unsigned> maybeIndex;
2481+
if (index != UINT_MAX)
2482+
maybeIndex = {index};
2483+
return {ty->getCanonicalType(), origTy, field, index};
2484+
};
2485+
auto isAggregate = [](Type ty) {
2486+
return ty->is<TupleType>() || ty->getEnumOrBoundGenericEnum() ||
2487+
ty->getStructOrBoundGenericStruct();
2488+
};
2489+
insertIntoWorklist(substType, origType, nullptr, llvm::None);
2490+
while (!worklist.empty()) {
2491+
Type ty;
2492+
AbstractionPattern origTy = AbstractionPattern::getOpaque();
2493+
ValueDecl *field;
2494+
Optional<unsigned> index;
2495+
std::tie(ty, origTy, field, index) = popFromWorklist();
2496+
if (isAggregate(ty) && !isLeafAggregate(ty, origTy, field, index)) {
2497+
if (auto tupleTy = ty->getAs<TupleType>()) {
2498+
for (unsigned tupleIndex = 0, num = tupleTy->getNumElements();
2499+
tupleIndex < num; ++tupleIndex) {
2500+
auto origElementTy = origTy.getTupleElementType(tupleIndex);
2501+
auto substElementTy =
2502+
tupleTy->getElementType(tupleIndex)->getCanonicalType();
2503+
substElementTy =
2504+
computeLoweredRValueType(context, origElementTy, substElementTy);
2505+
insertIntoWorklist(substElementTy, origElementTy, nullptr,
2506+
tupleIndex);
2507+
}
2508+
} else if (auto *decl = ty->getStructOrBoundGenericStruct()) {
2509+
for (auto *structField : decl->getStoredProperties()) {
2510+
auto subMap = ty->getContextSubstitutionMap(&M, decl);
2511+
auto substFieldTy =
2512+
structField->getInterfaceType().subst(subMap)->getCanonicalType();
2513+
auto sig =
2514+
structField->getDeclContext()->getGenericSignatureOfContext();
2515+
auto interfaceTy =
2516+
structField->getInterfaceType()->getReducedType(sig);
2517+
auto origFieldType =
2518+
origTy.unsafeGetSubstFieldType(structField, interfaceTy);
2519+
insertIntoWorklist(substFieldTy, origFieldType, structField,
2520+
llvm::None);
2521+
}
2522+
} else if (auto *decl = ty->getEnumOrBoundGenericEnum()) {
2523+
auto subMap = ty->getContextSubstitutionMap(&M, decl);
2524+
for (auto *element : decl->getAllElements()) {
2525+
if (!element->hasAssociatedValues())
2526+
continue;
2527+
// TODO: Callback for indirect elements.
2528+
if (element->isIndirect())
2529+
continue;
2530+
auto substElementType = element->getArgumentInterfaceType()
2531+
.subst(subMap)
2532+
->getCanonicalType();
2533+
auto origElementTy = origTy.unsafeGetSubstFieldType(
2534+
element, element->getArgumentInterfaceType()->getReducedType(
2535+
decl->getGenericSignature()));
2536+
2537+
insertIntoWorklist(substElementType, origElementTy, element,
2538+
llvm::None);
2539+
}
2540+
} else {
2541+
llvm_unreachable("unknown aggregate kind!");
2542+
}
2543+
continue;
2544+
}
2545+
2546+
// This type is a leaf. Visit it.
2547+
auto success = visit(ty, origTy, field, index);
2548+
if (!success)
2549+
return false;
2550+
}
2551+
return true;
2552+
}
2553+
24432554
void TypeConverter::verifyLowering(const TypeLowering &lowering,
2444-
AbstractionPattern origType,
2445-
Type origSubstType,
2555+
AbstractionPattern origType, Type substType,
24462556
TypeExpansionContext forExpansion) {
24472557
// Non-trivial lowerings should always be lexical unless all non-trivial
24482558
// fields are eager move.
24492559
if (!lowering.isTrivial() && !lowering.isLexical()) {
2450-
auto getLifetimeAnnotation = [](SILType ty) -> LifetimeAnnotation {
2560+
if (lowering.getRecursiveProperties().isInfinite())
2561+
return;
2562+
auto getLifetimeAnnotation = [](Type ty) -> LifetimeAnnotation {
24512563
NominalTypeDecl *nominal;
2452-
if (!(nominal = ty.getASTType().getAnyNominal()))
2564+
if (!(nominal = ty->getAnyNominal()))
24532565
return LifetimeAnnotation::None;
24542566
return nominal->getLifetimeAnnotation();
24552567
};
2456-
auto loweredType = lowering.getLoweredType();
2457-
bool hasNoNontrivialLexicalLeaf = loweredType.visitAggregateLeaves(
2458-
*this, forExpansion,
2568+
bool hasNoNontrivialLexicalLeaf = visitAggregateLeaves(
2569+
origType, substType, forExpansion,
24592570
/*isLeaf=*/
2460-
[&](auto parent, auto ty, auto *fieldDecl) -> bool {
2571+
[&](auto ty, auto origTy, auto *field, auto index) -> bool {
24612572
// The field's type is an aggregate. Treat it as a leaf if it
24622573
// has a lifetime annotation.
24632574

2464-
// If we don't have a field decl, it's either a field of a tuple
2465-
// or the top-level type. Either way, there's no var decl on
2466-
// which to look for an attribute.
2467-
//
2468-
// It's a leaf if the type has a lifetime annotation.
2469-
if (!fieldDecl)
2575+
// If it's a field of a tuple or the top-level type, there's no value
2576+
// decl on which to look for an attribute. It's a leaf iff the type
2577+
// has a lifetime annotation.
2578+
if (index || !field)
24702579
return getLifetimeAnnotation(ty).isSome();
24712580

24722581
// It's a field of a struct or an enum. It's a leaf if the type
24732582
// or the var decl has a lifetime annotation.
2474-
return fieldDecl->getLifetimeAnnotation().isSome() ||
2583+
return field->getLifetimeAnnotation().isSome() ||
24752584
getLifetimeAnnotation(ty);
24762585
},
24772586
/*visit=*/
2478-
[&](auto parent, auto ty, auto *fieldDecl) -> bool {
2587+
[&](auto ty, auto origTy, auto *field, auto index) -> bool {
24792588
// Look at each leaf: if it is non-trivial, verify that it is
24802589
// attributed @_eagerMove.
24812590

24822591
// If the leaf is the whole type, verify that it is annotated
24832592
// @_eagerMove.
2484-
if (ty == loweredType)
2593+
if (ty->getCanonicalType() == substType->getCanonicalType())
24852594
return getLifetimeAnnotation(ty) == LifetimeAnnotation::EagerMove;
24862595

2487-
// Get ty's lowering.
2488-
CanGenericSignature sig;
2489-
if (fieldDecl) {
2490-
AbstractionPattern origFieldTy = getAbstractionPattern(fieldDecl);
2491-
CanType substFieldTy;
2492-
if (fieldDecl->hasClangNode()) {
2493-
substFieldTy = origFieldTy.getType();
2494-
} else {
2495-
substFieldTy = parent.getASTType()
2496-
->getTypeOfMember(&M, fieldDecl)
2497-
->getCanonicalType();
2498-
}
2499-
sig = getAbstractionPattern(fieldDecl).getGenericSignatureOrNull();
2500-
} else {
2501-
sig = CanGenericSignature();
2502-
}
2503-
auto &tyLowering = getTypeLowering(ty, forExpansion, sig);
2596+
auto &tyLowering = getTypeLowering(origTy, ty, forExpansion);
25042597

25052598
// Leaves which are trivial aren't of interest.
25062599
if (tyLowering.isTrivial())
@@ -2510,17 +2603,16 @@ void TypeConverter::verifyLowering(const TypeLowering &lowering,
25102603
// not lexical. The leaf must be annotated @_eagerMove.
25112604
// Otherwise, the whole type would be lexical.
25122605

2513-
if (!fieldDecl) {
2514-
// The field is non-trivial and the whole type is non-lexical.
2515-
// If there's no field decl which might be annotated
2516-
// @_eagerMove, we have a problem.
2517-
return false;
2606+
if (index || !field) {
2607+
// There is no field decl that might be annotated @_eagerMove. The
2608+
// field is @_eagerMove iff its type is annotated @_eagerMove.
2609+
return getLifetimeAnnotation(ty) == LifetimeAnnotation::EagerMove;
25182610
}
25192611

25202612
// The field is non-trivial and the whole type is non-lexical.
25212613
// That's fine as long as the field or its type is annotated
25222614
// @_eagerMove.
2523-
return fieldDecl->getLifetimeAnnotation() ==
2615+
return field->getLifetimeAnnotation() ==
25242616
LifetimeAnnotation::EagerMove ||
25252617
getLifetimeAnnotation(ty) == LifetimeAnnotation::EagerMove;
25262618
});

0 commit comments

Comments
 (0)