Skip to content

Commit a3b195b

Browse files
authored
Merge pull request #64529 from rjmccall/variadic-tuples-in-structs
A bunch of fixes for variadic tuple properties in structs
2 parents 3ce8eb5 + c032cc5 commit a3b195b

File tree

7 files changed

+151
-33
lines changed

7 files changed

+151
-33
lines changed

include/swift/SIL/AbstractionPattern.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -783,7 +783,8 @@ class AbstractionPattern {
783783
/// Note that, for most purposes, you should lower a field's type against its
784784
/// *unsubstituted* interface type.
785785
AbstractionPattern
786-
unsafeGetSubstFieldType(ValueDecl *member, CanType origMemberType) const;
786+
unsafeGetSubstFieldType(ValueDecl *member, CanType origMemberType,
787+
SubstitutionMap subMap) const;
787788

788789
private:
789790
/// Return an abstraction pattern for the curried type of an

lib/SIL/IR/AbstractionPattern.cpp

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1376,6 +1376,26 @@ void AbstractionPattern::dump() const {
13761376
llvm::errs() << "\n";
13771377
}
13781378

1379+
static void printGenerics(raw_ostream &out, const AbstractionPattern &pattern) {
1380+
if (auto sig = pattern.getGenericSignature()) {
1381+
sig->print(out);
1382+
}
1383+
// It'd be really nice if we could get these interleaved with the types.
1384+
if (auto subs = pattern.getGenericSubstitutions()) {
1385+
out << "@<";
1386+
bool first = false;
1387+
for (auto sub : subs.getReplacementTypes()) {
1388+
if (!first) {
1389+
out << ",";
1390+
} else {
1391+
first = true;
1392+
}
1393+
out << sub;
1394+
}
1395+
out << ">";
1396+
}
1397+
}
1398+
13791399
void AbstractionPattern::print(raw_ostream &out) const {
13801400
switch (getKind()) {
13811401
case Kind::Invalid:
@@ -1396,9 +1416,7 @@ void AbstractionPattern::print(raw_ostream &out) const {
13961416
? "AP::Type" :
13971417
getKind() == Kind::Discard
13981418
? "AP::Discard" : "<<UNHANDLED CASE>>");
1399-
if (auto sig = getGenericSignature()) {
1400-
sig->print(out);
1401-
}
1419+
printGenerics(out, *this);
14021420
out << '(';
14031421
getType().dump(out);
14041422
out << ')';
@@ -1425,9 +1443,7 @@ void AbstractionPattern::print(raw_ostream &out) const {
14251443
getKind() == Kind::ObjCCompletionHandlerArgumentsType
14261444
? "AP::ObjCCompletionHandlerArgumentsType("
14271445
: "AP::CFunctionAsMethodType(");
1428-
if (auto sig = getGenericSignature()) {
1429-
sig->print(out);
1430-
}
1446+
printGenerics(out, *this);
14311447
getType().dump(out);
14321448
out << ", ";
14331449
// [TODO: Improve-Clang-type-printing]
@@ -1459,9 +1475,7 @@ void AbstractionPattern::print(raw_ostream &out) const {
14591475
getKind() == Kind::CurriedCXXMethodType
14601476
? "AP::CurriedCXXMethodType("
14611477
: "AP::PartialCurriedCXXMethodType");
1462-
if (auto sig = getGenericSignature()) {
1463-
sig->print(out);
1464-
}
1478+
printGenerics(out, *this);
14651479
getType().dump(out);
14661480
out << ", ";
14671481
getCXXMethod()->dump();
@@ -1569,13 +1583,14 @@ bool AbstractionPattern::hasSameBasicTypeStructure(CanType l, CanType r) {
15691583

15701584
AbstractionPattern
15711585
AbstractionPattern::unsafeGetSubstFieldType(ValueDecl *member,
1572-
CanType origMemberInterfaceType)
1586+
CanType origMemberInterfaceType,
1587+
SubstitutionMap subMap)
15731588
const {
15741589
assert(origMemberInterfaceType);
15751590
if (isTypeParameterOrOpaqueArchetype()) {
15761591
// Fall back to the generic abstraction pattern for the member.
15771592
auto sig = member->getDeclContext()->getGenericSignatureOfContext();
1578-
return AbstractionPattern(sig.getCanonicalSignature(),
1593+
return AbstractionPattern(subMap, sig.getCanonicalSignature(),
15791594
origMemberInterfaceType);
15801595
}
15811596

@@ -1612,7 +1627,9 @@ const {
16121627
member, origMemberInterfaceType)
16131628
->getReducedType(getGenericSignature());
16141629

1615-
return AbstractionPattern(getGenericSignature(), memberTy);
1630+
return AbstractionPattern(getGenericSubstitutions(),
1631+
getGenericSignature(),
1632+
memberTy);
16161633
}
16171634
llvm_unreachable("invalid abstraction pattern kind");
16181635
}

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4748,7 +4748,17 @@ class SILTypeSubstituter :
47484748
return origType;
47494749
}
47504750

4751-
AbstractionPattern abstraction(Sig, origType);
4751+
// We've looked through all the top-level structure in the orig
4752+
// type that's affected by type lowering. If substitution has
4753+
// given us a type with top-level structure that's affected by
4754+
// type lowering, it must be because the orig type was a type
4755+
// variable of some sort, and we should lower using an opaque
4756+
// abstraction pattern. If substitution hasn't given us such a
4757+
// type, it doesn't matter what abstraction pattern we use,
4758+
// lowering will just come back with substType. So we can just
4759+
// use an opaque abstraction pattern here and not put any effort
4760+
// into computing a more "honest" abstraction pattern.
4761+
AbstractionPattern abstraction = AbstractionPattern::getOpaque();
47524762
return TC.getLoweredRValueType(typeExpansionContext, abstraction,
47534763
substType);
47544764
}

lib/SIL/IR/SILType.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,9 +301,30 @@ bool SILType::canRefCast(SILType operTy, SILType resultTy, SILModule &M) {
301301
&& toTy.isHeapObjectReferenceType();
302302
}
303303

304+
static bool needsFieldSubstitutions(const AbstractionPattern &origType) {
305+
if (origType.isTypeParameter()) return false;
306+
auto type = origType.getType();
307+
if (!type->hasTypeParameter()) return false;
308+
return type.findIf([](CanType type) {
309+
return isa<PackExpansionType>(type);
310+
});
311+
}
312+
313+
static void addFieldSubstitutionsIfNeeded(TypeConverter &TC, SILType ty,
314+
ValueDecl *field,
315+
AbstractionPattern &origType) {
316+
if (needsFieldSubstitutions(origType)) {
317+
auto subMap = ty.getASTType()->getContextSubstitutionMap(
318+
&TC.M, field->getDeclContext());
319+
origType = origType.withSubstitutions(subMap);
320+
}
321+
}
322+
304323
SILType SILType::getFieldType(VarDecl *field, TypeConverter &TC,
305324
TypeExpansionContext context) const {
306325
AbstractionPattern origFieldTy = TC.getAbstractionPattern(field);
326+
addFieldSubstitutionsIfNeeded(TC, *this, field, origFieldTy);
327+
307328
CanType substFieldTy;
308329
if (field->hasClangNode()) {
309330
substFieldTy = origFieldTy.getType();
@@ -372,6 +393,9 @@ SILType SILType::getEnumElementType(EnumElementDecl *elt, TypeConverter &TC,
372393
getCategory());
373394
}
374395

396+
auto origEltType = TC.getAbstractionPattern(elt);
397+
addFieldSubstitutionsIfNeeded(TC, *this, elt, origEltType);
398+
375399
auto substEltTy = getASTType()->getTypeOfMember(
376400
&TC.M, elt, elt->getArgumentInterfaceType());
377401
auto loweredTy = TC.getLoweredRValueType(

lib/SIL/IR/TypeLowering.cpp

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -749,11 +749,12 @@ namespace {
749749
RetTy visitTupleType(CanTupleType type, AbstractionPattern origType,
750750
IsTypeExpansionSensitive_t isSensitive) {
751751
RecursiveProperties props;
752-
for (unsigned i = 0, e = type->getNumElements(); i < e; ++i) {
753-
props.addSubobject(classifyType(origType.getTupleElementType(i),
754-
type.getElementType(i),
755-
TC, Expansion));
756-
}
752+
origType.forEachExpandedTupleElement(type,
753+
[&](AbstractionPattern origEltType, CanType substEltType,
754+
const TupleTypeElt &elt) {
755+
props.addSubobject(
756+
classifyType(origEltType, substEltType, TC, Expansion));
757+
});
757758
props = mergeIsTypeExpansionSensitive(isSensitive, props);
758759
return asImpl().handleAggregateByProperties(type, props);
759760
}
@@ -2250,12 +2251,12 @@ namespace {
22502251
AbstractionPattern origType,
22512252
IsTypeExpansionSensitive_t isSensitive) {
22522253
RecursiveProperties properties;
2253-
for (unsigned i = 0, e = tupleType->getNumElements(); i < e; ++i) {
2254-
auto eltType = tupleType.getElementType(i);
2255-
auto origEltType = origType.getTupleElementType(i);
2256-
auto &lowering = TC.getTypeLowering(origEltType, eltType, Expansion);
2257-
properties.addSubobject(lowering.getRecursiveProperties());
2258-
}
2254+
origType.forEachExpandedTupleElement(tupleType,
2255+
[&](AbstractionPattern origEltType, CanType substEltType,
2256+
const TupleTypeElt &elt) {
2257+
properties.addSubobject(
2258+
classifyType(origEltType, substEltType, TC, Expansion));
2259+
});
22592260
properties = mergeIsTypeExpansionSensitive(isSensitive, properties);
22602261

22612262
return handleAggregateByProperties<LoadableTupleTypeLowering>(tupleType,
@@ -2343,7 +2344,8 @@ namespace {
23432344
auto sig = field->getDeclContext()->getGenericSignatureOfContext();
23442345
auto interfaceTy = field->getInterfaceType()->getReducedType(sig);
23452346
auto origFieldType = origType.unsafeGetSubstFieldType(field,
2346-
interfaceTy);
2347+
interfaceTy,
2348+
subMap);
23472349

23482350
properties.addSubobject(classifyType(origFieldType, substFieldType,
23492351
TC, Expansion));
@@ -2422,7 +2424,8 @@ namespace {
24222424

24232425
auto origEltType = origType.unsafeGetSubstFieldType(elt,
24242426
elt->getArgumentInterfaceType()
2425-
->getReducedType(D->getGenericSignature()));
2427+
->getReducedType(D->getGenericSignature()),
2428+
subMap);
24262429
properties.addSubobject(classifyType(origEltType, substEltType,
24272430
TC, Expansion));
24282431
properties =
@@ -2765,7 +2768,8 @@ bool TypeConverter::visitAggregateLeaves(
27652768
auto interfaceTy =
27662769
structField->getInterfaceType()->getReducedType(sig);
27672770
auto origFieldType =
2768-
origTy.unsafeGetSubstFieldType(structField, interfaceTy);
2771+
origTy.unsafeGetSubstFieldType(structField, interfaceTy,
2772+
subMap);
27692773
insertIntoWorklist(substFieldTy, origFieldType, structField,
27702774
llvm::None);
27712775
}
@@ -2782,7 +2786,7 @@ bool TypeConverter::visitAggregateLeaves(
27822786
->getCanonicalType();
27832787
auto origElementTy = origTy.unsafeGetSubstFieldType(
27842788
element, element->getArgumentInterfaceType()->getReducedType(
2785-
decl->getGenericSignature()));
2789+
decl->getGenericSignature()), subMap);
27862790

27872791
insertIntoWorklist(substElementType, origElementTy, element,
27882792
llvm::None);

lib/SILGen/SILGenApply.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3389,10 +3389,23 @@ class ArgEmitter {
33893389
// If the source expression is a tuple literal, we can break it
33903390
// up directly.
33913391
if (auto tuple = dyn_cast<TupleExpr>(e)) {
3392-
for (auto i : indices(tuple->getElements())) {
3393-
emit(tuple->getElement(i),
3394-
origParamType.getTupleElementType(i));
3395-
}
3392+
auto substTupleType =
3393+
cast<TupleType>(e->getType()->getCanonicalType());
3394+
origParamType.forEachTupleElement(substTupleType,
3395+
[&](unsigned origEltIndex, unsigned substEltIndex,
3396+
AbstractionPattern origEltType, CanType substEltType) {
3397+
emit(tuple->getElement(substEltIndex), origEltType);
3398+
},
3399+
[&](unsigned origEltIndex, unsigned substEltIndex,
3400+
AbstractionPattern origExpansionType,
3401+
CanTupleEltTypeArrayRef substEltTypes) {
3402+
SmallVector<ArgumentSource, 4> eltArgs;
3403+
eltArgs.reserve(substEltTypes.size());
3404+
for (auto i : range(substEltIndex, substEltTypes.size())) {
3405+
eltArgs.emplace_back(tuple->getElement(i));
3406+
}
3407+
emitPackArg(eltArgs, origExpansionType);
3408+
});
33963409
return;
33973410
}
33983411

test/SILGen/variadic-generic-tuples.swift

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,3 +204,52 @@ func projectTupleElements<each T>(_ value: repeat Wrapper<each T>) {
204204

205205
let tuple = (repeat (each value).value)
206206
}
207+
208+
func takesVariadicTuple<each T>(tuple: (repeat each T)) {}
209+
210+
// CHECK-LABEL: sil{{.*}} @$s4main28testConcreteVariadicTupleArg1i1sySi_SStF :
211+
// CHECK: [[PACK:%.*]] = alloc_pack $Pack{Int, String}
212+
// CHECK-NEXT: [[I_COPY:%.*]] = alloc_stack $Int
213+
// CHECK-NEXT: store %0 to [trivial] [[I_COPY]] : $*Int
214+
// CHECK-NEXT: [[I_INDEX:%.*]] = scalar_pack_index 0 of $Pack{Int, String}
215+
// CHECK-NEXT: pack_element_set [[I_COPY]] : $*Int into [[I_INDEX]] of [[PACK]] :
216+
// CHECK-NEXT: [[S_COPY:%.*]] = alloc_stack $String
217+
// CHECK-NEXT: [[T0:%.*]] = copy_value %1 : $String
218+
// CHECK-NEXT: store [[T0]] to [init] [[S_COPY]] : $*String
219+
// CHECK-NEXT: [[S_INDEX:%.*]] = scalar_pack_index 1 of $Pack{Int, String}
220+
// CHECK-NEXT: pack_element_set [[S_COPY]] : $*String into [[S_INDEX]] of [[PACK]] :
221+
// CHECK-NEXT: // function_ref
222+
// CHECK-NEXT: [[FN:%.*]] = function_ref @$s4main18takesVariadicTuple5tupleyxxQp_t_tRvzlF : $@convention(thin) <each τ_0_0> (@pack_guaranteed Pack{repeat each τ_0_0}) -> ()
223+
// CHECK-NEXT: apply [[FN]]<Pack{Int, String}>([[PACK]])
224+
// CHECK-NEXT: destroy_addr [[S_COPY]] :
225+
// CHECK-NEXT: dealloc_stack [[S_COPY]] :
226+
// CHECK-NEXT: dealloc_stack [[I_COPY]] :
227+
// CHECK-NEXT: dealloc_pack [[PACK]] :
228+
func testConcreteVariadicTupleArg(i: Int, s: String) {
229+
takesVariadicTuple(tuple: (i, s))
230+
}
231+
232+
struct TupleHolder<each T> {
233+
var content: (repeat each T)
234+
235+
// Suppress the memberwise initializer
236+
init(values: repeat each T) {
237+
content = (repeat each values)
238+
}
239+
}
240+
241+
// CHECK-LABEL: sil{{.*}} @$s4main31takesConcreteTupleHolderFactory7factoryyAA0dE0VySi_SSQPGyXE_tF :
242+
// CHECK-SAME: $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> @owned TupleHolder<Int, String>) -> ()
243+
// CHECK: [[T0:%.*]] = copy_value %0 :
244+
// CHECK: [[T1:%.*]] = begin_borrow [[T0]]
245+
// CHECK: [[RESULT:%.*]] = apply [[T1]]() :
246+
// CHECK: destroy_value [[RESULT]]
247+
func takesConcreteTupleHolderFactory(factory: () -> TupleHolder<Int, String>) {
248+
let holder = factory()
249+
}
250+
251+
/* We still crash with memberwise initializers
252+
func generateConcreteMemberTuple() -> TupleHolder<Int, String> {
253+
return HasMemberTuple(content: (0, "hello"))
254+
}
255+
*/

0 commit comments

Comments
 (0)