Skip to content

A bunch of fixes for variadic tuple properties in structs #64529

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Mar 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion include/swift/SIL/AbstractionPattern.h
Original file line number Diff line number Diff line change
Expand Up @@ -783,7 +783,8 @@ class AbstractionPattern {
/// Note that, for most purposes, you should lower a field's type against its
/// *unsubstituted* interface type.
AbstractionPattern
unsafeGetSubstFieldType(ValueDecl *member, CanType origMemberType) const;
unsafeGetSubstFieldType(ValueDecl *member, CanType origMemberType,
SubstitutionMap subMap) const;

private:
/// Return an abstraction pattern for the curried type of an
Expand Down
41 changes: 29 additions & 12 deletions lib/SIL/IR/AbstractionPattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1376,6 +1376,26 @@ void AbstractionPattern::dump() const {
llvm::errs() << "\n";
}

static void printGenerics(raw_ostream &out, const AbstractionPattern &pattern) {
if (auto sig = pattern.getGenericSignature()) {
sig->print(out);
}
// It'd be really nice if we could get these interleaved with the types.
if (auto subs = pattern.getGenericSubstitutions()) {
out << "@<";
bool first = false;
for (auto sub : subs.getReplacementTypes()) {
if (!first) {
out << ",";
} else {
first = true;
}
out << sub;
}
out << ">";
}
}

void AbstractionPattern::print(raw_ostream &out) const {
switch (getKind()) {
case Kind::Invalid:
Expand All @@ -1396,9 +1416,7 @@ void AbstractionPattern::print(raw_ostream &out) const {
? "AP::Type" :
getKind() == Kind::Discard
? "AP::Discard" : "<<UNHANDLED CASE>>");
if (auto sig = getGenericSignature()) {
sig->print(out);
}
printGenerics(out, *this);
out << '(';
getType().dump(out);
out << ')';
Expand All @@ -1425,9 +1443,7 @@ void AbstractionPattern::print(raw_ostream &out) const {
getKind() == Kind::ObjCCompletionHandlerArgumentsType
? "AP::ObjCCompletionHandlerArgumentsType("
: "AP::CFunctionAsMethodType(");
if (auto sig = getGenericSignature()) {
sig->print(out);
}
printGenerics(out, *this);
getType().dump(out);
out << ", ";
// [TODO: Improve-Clang-type-printing]
Expand Down Expand Up @@ -1459,9 +1475,7 @@ void AbstractionPattern::print(raw_ostream &out) const {
getKind() == Kind::CurriedCXXMethodType
? "AP::CurriedCXXMethodType("
: "AP::PartialCurriedCXXMethodType");
if (auto sig = getGenericSignature()) {
sig->print(out);
}
printGenerics(out, *this);
getType().dump(out);
out << ", ";
getCXXMethod()->dump();
Expand Down Expand Up @@ -1569,13 +1583,14 @@ bool AbstractionPattern::hasSameBasicTypeStructure(CanType l, CanType r) {

AbstractionPattern
AbstractionPattern::unsafeGetSubstFieldType(ValueDecl *member,
CanType origMemberInterfaceType)
CanType origMemberInterfaceType,
SubstitutionMap subMap)
const {
assert(origMemberInterfaceType);
if (isTypeParameterOrOpaqueArchetype()) {
// Fall back to the generic abstraction pattern for the member.
auto sig = member->getDeclContext()->getGenericSignatureOfContext();
return AbstractionPattern(sig.getCanonicalSignature(),
return AbstractionPattern(subMap, sig.getCanonicalSignature(),
origMemberInterfaceType);
}

Expand Down Expand Up @@ -1612,7 +1627,9 @@ const {
member, origMemberInterfaceType)
->getReducedType(getGenericSignature());

return AbstractionPattern(getGenericSignature(), memberTy);
return AbstractionPattern(getGenericSubstitutions(),
getGenericSignature(),
memberTy);
}
llvm_unreachable("invalid abstraction pattern kind");
}
Expand Down
12 changes: 11 additions & 1 deletion lib/SIL/IR/SILFunctionType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4748,7 +4748,17 @@ class SILTypeSubstituter :
return origType;
}

AbstractionPattern abstraction(Sig, origType);
// We've looked through all the top-level structure in the orig
// type that's affected by type lowering. If substitution has
// given us a type with top-level structure that's affected by
// type lowering, it must be because the orig type was a type
// variable of some sort, and we should lower using an opaque
// abstraction pattern. If substitution hasn't given us such a
// type, it doesn't matter what abstraction pattern we use,
// lowering will just come back with substType. So we can just
// use an opaque abstraction pattern here and not put any effort
// into computing a more "honest" abstraction pattern.
AbstractionPattern abstraction = AbstractionPattern::getOpaque();
return TC.getLoweredRValueType(typeExpansionContext, abstraction,
substType);
}
Expand Down
24 changes: 24 additions & 0 deletions lib/SIL/IR/SILType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,9 +301,30 @@ bool SILType::canRefCast(SILType operTy, SILType resultTy, SILModule &M) {
&& toTy.isHeapObjectReferenceType();
}

static bool needsFieldSubstitutions(const AbstractionPattern &origType) {
if (origType.isTypeParameter()) return false;
auto type = origType.getType();
if (!type->hasTypeParameter()) return false;
return type.findIf([](CanType type) {
return isa<PackExpansionType>(type);
});
}

static void addFieldSubstitutionsIfNeeded(TypeConverter &TC, SILType ty,
ValueDecl *field,
AbstractionPattern &origType) {
if (needsFieldSubstitutions(origType)) {
auto subMap = ty.getASTType()->getContextSubstitutionMap(
&TC.M, field->getDeclContext());
origType = origType.withSubstitutions(subMap);
}
}

SILType SILType::getFieldType(VarDecl *field, TypeConverter &TC,
TypeExpansionContext context) const {
AbstractionPattern origFieldTy = TC.getAbstractionPattern(field);
addFieldSubstitutionsIfNeeded(TC, *this, field, origFieldTy);

CanType substFieldTy;
if (field->hasClangNode()) {
substFieldTy = origFieldTy.getType();
Expand Down Expand Up @@ -372,6 +393,9 @@ SILType SILType::getEnumElementType(EnumElementDecl *elt, TypeConverter &TC,
getCategory());
}

auto origEltType = TC.getAbstractionPattern(elt);
addFieldSubstitutionsIfNeeded(TC, *this, elt, origEltType);

auto substEltTy = getASTType()->getTypeOfMember(
&TC.M, elt, elt->getArgumentInterfaceType());
auto loweredTy = TC.getLoweredRValueType(
Expand Down
34 changes: 19 additions & 15 deletions lib/SIL/IR/TypeLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -749,11 +749,12 @@ namespace {
RetTy visitTupleType(CanTupleType type, AbstractionPattern origType,
IsTypeExpansionSensitive_t isSensitive) {
RecursiveProperties props;
for (unsigned i = 0, e = type->getNumElements(); i < e; ++i) {
props.addSubobject(classifyType(origType.getTupleElementType(i),
type.getElementType(i),
TC, Expansion));
}
origType.forEachExpandedTupleElement(type,
[&](AbstractionPattern origEltType, CanType substEltType,
const TupleTypeElt &elt) {
props.addSubobject(
classifyType(origEltType, substEltType, TC, Expansion));
});
props = mergeIsTypeExpansionSensitive(isSensitive, props);
return asImpl().handleAggregateByProperties(type, props);
}
Expand Down Expand Up @@ -2250,12 +2251,12 @@ namespace {
AbstractionPattern origType,
IsTypeExpansionSensitive_t isSensitive) {
RecursiveProperties properties;
for (unsigned i = 0, e = tupleType->getNumElements(); i < e; ++i) {
auto eltType = tupleType.getElementType(i);
auto origEltType = origType.getTupleElementType(i);
auto &lowering = TC.getTypeLowering(origEltType, eltType, Expansion);
properties.addSubobject(lowering.getRecursiveProperties());
}
origType.forEachExpandedTupleElement(tupleType,
[&](AbstractionPattern origEltType, CanType substEltType,
const TupleTypeElt &elt) {
properties.addSubobject(
classifyType(origEltType, substEltType, TC, Expansion));
});
properties = mergeIsTypeExpansionSensitive(isSensitive, properties);

return handleAggregateByProperties<LoadableTupleTypeLowering>(tupleType,
Expand Down Expand Up @@ -2343,7 +2344,8 @@ namespace {
auto sig = field->getDeclContext()->getGenericSignatureOfContext();
auto interfaceTy = field->getInterfaceType()->getReducedType(sig);
auto origFieldType = origType.unsafeGetSubstFieldType(field,
interfaceTy);
interfaceTy,
subMap);

properties.addSubobject(classifyType(origFieldType, substFieldType,
TC, Expansion));
Expand Down Expand Up @@ -2422,7 +2424,8 @@ namespace {

auto origEltType = origType.unsafeGetSubstFieldType(elt,
elt->getArgumentInterfaceType()
->getReducedType(D->getGenericSignature()));
->getReducedType(D->getGenericSignature()),
subMap);
properties.addSubobject(classifyType(origEltType, substEltType,
TC, Expansion));
properties =
Expand Down Expand Up @@ -2765,7 +2768,8 @@ bool TypeConverter::visitAggregateLeaves(
auto interfaceTy =
structField->getInterfaceType()->getReducedType(sig);
auto origFieldType =
origTy.unsafeGetSubstFieldType(structField, interfaceTy);
origTy.unsafeGetSubstFieldType(structField, interfaceTy,
subMap);
insertIntoWorklist(substFieldTy, origFieldType, structField,
llvm::None);
}
Expand All @@ -2782,7 +2786,7 @@ bool TypeConverter::visitAggregateLeaves(
->getCanonicalType();
auto origElementTy = origTy.unsafeGetSubstFieldType(
element, element->getArgumentInterfaceType()->getReducedType(
decl->getGenericSignature()));
decl->getGenericSignature()), subMap);

insertIntoWorklist(substElementType, origElementTy, element,
llvm::None);
Expand Down
21 changes: 17 additions & 4 deletions lib/SILGen/SILGenApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3389,10 +3389,23 @@ class ArgEmitter {
// If the source expression is a tuple literal, we can break it
// up directly.
if (auto tuple = dyn_cast<TupleExpr>(e)) {
for (auto i : indices(tuple->getElements())) {
emit(tuple->getElement(i),
origParamType.getTupleElementType(i));
}
auto substTupleType =
cast<TupleType>(e->getType()->getCanonicalType());
origParamType.forEachTupleElement(substTupleType,
[&](unsigned origEltIndex, unsigned substEltIndex,
AbstractionPattern origEltType, CanType substEltType) {
emit(tuple->getElement(substEltIndex), origEltType);
},
[&](unsigned origEltIndex, unsigned substEltIndex,
AbstractionPattern origExpansionType,
CanTupleEltTypeArrayRef substEltTypes) {
SmallVector<ArgumentSource, 4> eltArgs;
eltArgs.reserve(substEltTypes.size());
for (auto i : range(substEltIndex, substEltTypes.size())) {
eltArgs.emplace_back(tuple->getElement(i));
}
emitPackArg(eltArgs, origExpansionType);
});
return;
}

Expand Down
49 changes: 49 additions & 0 deletions test/SILGen/variadic-generic-tuples.swift
Original file line number Diff line number Diff line change
Expand Up @@ -204,3 +204,52 @@ func projectTupleElements<each T>(_ value: repeat Wrapper<each T>) {

let tuple = (repeat (each value).value)
}

func takesVariadicTuple<each T>(tuple: (repeat each T)) {}

// CHECK-LABEL: sil{{.*}} @$s4main28testConcreteVariadicTupleArg1i1sySi_SStF :
// CHECK: [[PACK:%.*]] = alloc_pack $Pack{Int, String}
// CHECK-NEXT: [[I_COPY:%.*]] = alloc_stack $Int
// CHECK-NEXT: store %0 to [trivial] [[I_COPY]] : $*Int
// CHECK-NEXT: [[I_INDEX:%.*]] = scalar_pack_index 0 of $Pack{Int, String}
// CHECK-NEXT: pack_element_set [[I_COPY]] : $*Int into [[I_INDEX]] of [[PACK]] :
// CHECK-NEXT: [[S_COPY:%.*]] = alloc_stack $String
// CHECK-NEXT: [[T0:%.*]] = copy_value %1 : $String
// CHECK-NEXT: store [[T0]] to [init] [[S_COPY]] : $*String
// CHECK-NEXT: [[S_INDEX:%.*]] = scalar_pack_index 1 of $Pack{Int, String}
// CHECK-NEXT: pack_element_set [[S_COPY]] : $*String into [[S_INDEX]] of [[PACK]] :
// CHECK-NEXT: // function_ref
// CHECK-NEXT: [[FN:%.*]] = function_ref @$s4main18takesVariadicTuple5tupleyxxQp_t_tRvzlF : $@convention(thin) <each τ_0_0> (@pack_guaranteed Pack{repeat each τ_0_0}) -> ()
// CHECK-NEXT: apply [[FN]]<Pack{Int, String}>([[PACK]])
// CHECK-NEXT: destroy_addr [[S_COPY]] :
// CHECK-NEXT: dealloc_stack [[S_COPY]] :
// CHECK-NEXT: dealloc_stack [[I_COPY]] :
// CHECK-NEXT: dealloc_pack [[PACK]] :
func testConcreteVariadicTupleArg(i: Int, s: String) {
takesVariadicTuple(tuple: (i, s))
}

struct TupleHolder<each T> {
var content: (repeat each T)

// Suppress the memberwise initializer
init(values: repeat each T) {
content = (repeat each values)
}
}

// CHECK-LABEL: sil{{.*}} @$s4main31takesConcreteTupleHolderFactory7factoryyAA0dE0VySi_SSQPGyXE_tF :
// CHECK-SAME: $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> @owned TupleHolder<Int, String>) -> ()
// CHECK: [[T0:%.*]] = copy_value %0 :
// CHECK: [[T1:%.*]] = begin_borrow [[T0]]
// CHECK: [[RESULT:%.*]] = apply [[T1]]() :
// CHECK: destroy_value [[RESULT]]
func takesConcreteTupleHolderFactory(factory: () -> TupleHolder<Int, String>) {
let holder = factory()
}

/* We still crash with memberwise initializers
func generateConcreteMemberTuple() -> TupleHolder<Int, String> {
return HasMemberTuple(content: (0, "hello"))
}
*/