Skip to content

Commit 1cb8236

Browse files
authored
Merge pull request #34255 from slavapestov/reabstract-stored-property-constrained-extension-mess
SILGen: Fix crash when a stored property with an initial value has a reabstractable type
2 parents 9a0c43d + 7fd4615 commit 1cb8236

14 files changed

+283
-162
lines changed

lib/SILGen/Initialization.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,39 @@ class TupleInitialization : public Initialization {
307307
void finishUninitialized(SILGenFunction &SGF) override;
308308
};
309309

310+
/// A "null" initialization that indicates that any value being initialized
311+
/// into this initialization should be discarded. This represents AnyPatterns
312+
/// (that is, 'var (_)') that bind to values without storing them.
313+
class BlackHoleInitialization : public Initialization {
314+
public:
315+
BlackHoleInitialization() {}
316+
317+
bool canSplitIntoTupleElements() const override {
318+
return true;
319+
}
320+
321+
MutableArrayRef<InitializationPtr>
322+
splitIntoTupleElements(SILGenFunction &SGF, SILLocation loc,
323+
CanType type,
324+
SmallVectorImpl<InitializationPtr> &buf) override {
325+
// "Destructure" an ignored binding into multiple ignored bindings.
326+
for (auto fieldType : cast<TupleType>(type)->getElementTypes()) {
327+
(void) fieldType;
328+
buf.push_back(InitializationPtr(new BlackHoleInitialization()));
329+
}
330+
return buf;
331+
}
332+
333+
void copyOrInitValueInto(SILGenFunction &SGF, SILLocation loc,
334+
ManagedValue value, bool isInit) override {
335+
/// This just ignores the provided value.
336+
}
337+
338+
void finishUninitialized(SILGenFunction &SGF) override {
339+
// do nothing
340+
}
341+
};
342+
310343
} // end namespace Lowering
311344
} // end namespace swift
312345

lib/SILGen/SILGenConstructor.cpp

Lines changed: 123 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "ArgumentSource.h"
14+
#include "Conversion.h"
1415
#include "Initialization.h"
1516
#include "LValue.h"
1617
#include "RValue.h"
@@ -901,72 +902,71 @@ static ManagedValue emitSelfForMemberInit(SILGenFunction &SGF, SILLocation loc,
901902
SGFAccessKind::Write);
902903
}
903904

904-
static LValue emitLValueForMemberInit(SILGenFunction &SGF, SILLocation loc,
905-
VarDecl *selfDecl,
906-
VarDecl *property) {
907-
CanType selfFormalType = selfDecl->getType()->getCanonicalType();
908-
auto self = emitSelfForMemberInit(SGF, loc, selfDecl);
909-
return SGF.emitPropertyLValue(loc, self, selfFormalType, property,
910-
LValueOptions(), SGFAccessKind::Write,
911-
AccessSemantics::DirectToStorage);
912-
}
913-
914-
/// Emit a member initialization for the members described in the
915-
/// given pattern from the given source value.
916-
static void emitMemberInit(SILGenFunction &SGF, VarDecl *selfDecl,
917-
Pattern *pattern, RValue &&src) {
905+
// FIXME: Can emitMemberInit() share code with InitializationForPattern in
906+
// SILGenDecl.cpp? Note that this version operates on stored properties of
907+
// types, whereas the former only knows how to handle local bindings, but
908+
// we could generalize it.
909+
static InitializationPtr
910+
emitMemberInit(SILGenFunction &SGF, VarDecl *selfDecl, Pattern *pattern) {
918911
switch (pattern->getKind()) {
919912
case PatternKind::Paren:
920913
return emitMemberInit(SGF, selfDecl,
921-
cast<ParenPattern>(pattern)->getSubPattern(),
922-
std::move(src));
914+
cast<ParenPattern>(pattern)->getSubPattern());
923915

924916
case PatternKind::Tuple: {
917+
TupleInitialization *init = new TupleInitialization();
925918
auto tuple = cast<TuplePattern>(pattern);
926-
auto fields = tuple->getElements();
927-
928-
SmallVector<RValue, 4> elements;
929-
std::move(src).extractElements(elements);
930-
for (unsigned i = 0, n = fields.size(); i != n; ++i) {
931-
emitMemberInit(SGF, selfDecl, fields[i].getPattern(),
932-
std::move(elements[i]));
919+
for (auto &elt : tuple->getElements()) {
920+
init->SubInitializations.push_back(
921+
emitMemberInit(SGF, selfDecl, elt.getPattern()));
933922
}
934-
break;
923+
return InitializationPtr(init);
935924
}
936925

937926
case PatternKind::Named: {
938927
auto named = cast<NamedPattern>(pattern);
939-
// Form the lvalue referencing this member.
940-
FormalEvaluationScope scope(SGF);
941-
LValue memberRef = emitLValueForMemberInit(SGF, pattern, selfDecl,
942-
named->getDecl());
943928

944-
// Assign to it.
945-
SGF.emitAssignToLValue(pattern, std::move(src), std::move(memberRef));
946-
return;
929+
auto self = emitSelfForMemberInit(SGF, pattern, selfDecl);
930+
931+
auto *field = named->getDecl();
932+
933+
auto selfTy = self.getType();
934+
auto fieldTy =
935+
selfTy.getFieldType(field, SGF.SGM.M, SGF.getTypeExpansionContext());
936+
SILValue slot;
937+
938+
if (auto *structDecl = dyn_cast<StructDecl>(field->getDeclContext())) {
939+
slot = SGF.B.createStructElementAddr(pattern, self.forward(SGF), field,
940+
fieldTy.getAddressType());
941+
} else {
942+
assert(isa<ClassDecl>(field->getDeclContext()));
943+
slot = SGF.B.createRefElementAddr(pattern, self.forward(SGF), field,
944+
fieldTy.getAddressType());
945+
}
946+
947+
return InitializationPtr(new KnownAddressInitialization(slot));
947948
}
948949

949950
case PatternKind::Any:
950-
return;
951+
return InitializationPtr(new BlackHoleInitialization());;
951952

952953
case PatternKind::Typed:
953954
return emitMemberInit(SGF, selfDecl,
954-
cast<TypedPattern>(pattern)->getSubPattern(),
955-
std::move(src));
955+
cast<TypedPattern>(pattern)->getSubPattern());
956956

957957
case PatternKind::Binding:
958958
return emitMemberInit(SGF, selfDecl,
959-
cast<BindingPattern>(pattern)->getSubPattern(),
960-
std::move(src));
959+
cast<BindingPattern>(pattern)->getSubPattern());
961960

962961
#define PATTERN(Name, Parent)
963962
#define REFUTABLE_PATTERN(Name, Parent) case PatternKind::Name:
964963
#include "swift/AST/PatternNodes.def"
965-
llvm_unreachable("Refutable pattern in pattern binding");
964+
llvm_unreachable("Refutable pattern in stored property pattern binding");
966965
}
967966
}
968967

969-
static Type getInitializationTypeInContext(
968+
static std::pair<AbstractionPattern, CanType>
969+
getInitializationTypeInContext(
970970
DeclContext *fromDC, DeclContext *toDC,
971971
Pattern *pattern) {
972972
auto interfaceType = pattern->getType()->mapTypeOutOfContext();
@@ -981,9 +981,53 @@ static Type getInitializationTypeInContext(
981981
}
982982
}
983983

984-
auto resultType = toDC->mapTypeIntoContext(interfaceType);
984+
AbstractionPattern origType(
985+
fromDC->getGenericSignatureOfContext().getCanonicalSignature(),
986+
interfaceType->getCanonicalType());
987+
988+
auto substType = toDC->mapTypeIntoContext(interfaceType)->getCanonicalType();
985989

986-
return resultType;
990+
return std::make_pair(origType, substType);
991+
}
992+
993+
static void
994+
emitAndStoreInitialValueInto(SILGenFunction &SGF,
995+
SILLocation loc,
996+
PatternBindingDecl *pbd, unsigned i,
997+
SubstitutionMap subs,
998+
AbstractionPattern origType,
999+
CanType substType,
1000+
Initialization *init) {
1001+
bool injectIntoWrapper = false;
1002+
if (auto singleVar = pbd->getSingleVar()) {
1003+
auto originalVar = singleVar->getOriginalWrappedProperty();
1004+
if (originalVar &&
1005+
originalVar->isPropertyMemberwiseInitializedWithWrappedType()) {
1006+
injectIntoWrapper = true;
1007+
}
1008+
}
1009+
1010+
SGFContext C = (injectIntoWrapper ? SGFContext() : SGFContext(init));
1011+
1012+
RValue result = SGF.emitApplyOfStoredPropertyInitializer(
1013+
pbd->getExecutableInit(i),
1014+
pbd->getAnchoringVarDecl(i),
1015+
subs, substType, origType, C);
1016+
1017+
// need to store result into the init if its in context
1018+
1019+
// If we have the backing storage for a property with an attached
1020+
// property wrapper initialized with `=`, inject the value into an
1021+
// instance of the wrapper.
1022+
if (injectIntoWrapper) {
1023+
auto *singleVar = pbd->getSingleVar();
1024+
result = maybeEmitPropertyWrapperInitFromValue(
1025+
SGF, pbd->getExecutableInit(i),
1026+
singleVar, subs, std::move(result));
1027+
}
1028+
1029+
if (!result.isInContext())
1030+
std::move(result).forwardInto(SGF, loc, init);
9871031
}
9881032

9891033
void SILGenFunction::emitMemberInitializers(DeclContext *dc,
@@ -1001,35 +1045,51 @@ void SILGenFunction::emitMemberInitializers(DeclContext *dc,
10011045
if (!init) continue;
10021046

10031047
auto *varPattern = pbd->getPattern(i);
1048+
10041049
// Cleanup after this initialization.
10051050
FullExpr scope(Cleanups, varPattern);
10061051

10071052
// Get the type of the initialization result, in terms
10081053
// of the constructor context's archetypes.
1009-
CanType resultType = getInitializationTypeInContext(
1010-
pbd->getDeclContext(), dc, varPattern)->getCanonicalType();
1011-
AbstractionPattern origResultType(resultType);
1012-
1013-
// FIXME: Can emitMemberInit() share code with
1014-
// InitializationForPattern in SILGenDecl.cpp?
1015-
RValue result = emitApplyOfStoredPropertyInitializer(
1016-
init, pbd->getAnchoringVarDecl(i), subs,
1017-
resultType, origResultType,
1018-
SGFContext());
1019-
1020-
// If we have the backing storage for a property with an attached
1021-
// property wrapper initialized with `=`, inject the value into an
1022-
// instance of the wrapper.
1023-
if (auto singleVar = pbd->getSingleVar()) {
1024-
auto originalVar = singleVar->getOriginalWrappedProperty();
1025-
if (originalVar &&
1026-
originalVar->isPropertyMemberwiseInitializedWithWrappedType()) {
1027-
result = maybeEmitPropertyWrapperInitFromValue(
1028-
*this, init, singleVar, subs, std::move(result));
1029-
}
1054+
auto resultType = getInitializationTypeInContext(
1055+
pbd->getDeclContext(), dc, varPattern);
1056+
AbstractionPattern origType = resultType.first;
1057+
CanType substType = resultType.second;
1058+
1059+
// Figure out what we're initializing.
1060+
auto memberInit = emitMemberInit(*this, selfDecl, varPattern);
1061+
1062+
// This whole conversion thing is about eliminating the
1063+
// paired orig-to-subst subst-to-orig conversions that
1064+
// will happen if the storage is at a different abstraction
1065+
// level than the constructor. When emitApply() is used
1066+
// to call the stored property initializer, it naturally
1067+
// wants to convert the result back to the most substituted
1068+
// abstraction level. To undo this, we use a converting
1069+
// initialization and rely on the peephole that optimizes
1070+
// out the redundant conversion.
1071+
auto loweredResultTy = getLoweredType(origType, substType);
1072+
auto loweredSubstTy = getLoweredType(substType);
1073+
1074+
if (loweredResultTy != loweredSubstTy) {
1075+
Conversion conversion = Conversion::getSubstToOrig(
1076+
origType, substType,
1077+
loweredResultTy);
1078+
1079+
ConvertingInitialization convertingInit(conversion,
1080+
SGFContext(memberInit.get()));
1081+
1082+
emitAndStoreInitialValueInto(*this, varPattern, pbd, i, subs,
1083+
origType, substType, &convertingInit);
1084+
1085+
auto finalValue = convertingInit.finishEmission(
1086+
*this, varPattern, ManagedValue::forInContext());
1087+
if (!finalValue.isInContext())
1088+
finalValue.forwardInto(*this, varPattern, memberInit.get());
1089+
} else {
1090+
emitAndStoreInitialValueInto(*this, varPattern, pbd, i, subs,
1091+
origType, substType, memberInit.get());
10301092
}
1031-
1032-
emitMemberInit(*this, selfDecl, varPattern, std::move(result));
10331093
}
10341094
}
10351095
}

lib/SILGen/SILGenConvert.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1354,7 +1354,25 @@ Lowering::canPeepholeConversions(SILGenFunction &SGF,
13541354
switch (outerConversion.getKind()) {
13551355
case Conversion::OrigToSubst:
13561356
case Conversion::SubstToOrig:
1357-
// TODO: peephole these when the abstraction patterns are the same!
1357+
switch (innerConversion.getKind()) {
1358+
case Conversion::OrigToSubst:
1359+
case Conversion::SubstToOrig:
1360+
if (innerConversion.getKind() == outerConversion.getKind())
1361+
break;
1362+
1363+
if (innerConversion.getReabstractionOrigType().getCachingKey() !=
1364+
outerConversion.getReabstractionOrigType().getCachingKey() ||
1365+
innerConversion.getReabstractionSubstType() !=
1366+
outerConversion.getReabstractionSubstType()) {
1367+
break;
1368+
}
1369+
1370+
return ConversionPeepholeHint(ConversionPeepholeHint::Identity, false);
1371+
1372+
default:
1373+
break;
1374+
}
1375+
13581376
return None;
13591377

13601378
case Conversion::AnyErasure:

lib/SILGen/SILGenDecl.cpp

Lines changed: 1 addition & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -39,41 +39,6 @@ using namespace Lowering;
3939
void Initialization::_anchor() {}
4040
void SILDebuggerClient::anchor() {}
4141

42-
namespace {
43-
/// A "null" initialization that indicates that any value being initialized
44-
/// into this initialization should be discarded. This represents AnyPatterns
45-
/// (that is, 'var (_)') that bind to values without storing them.
46-
class BlackHoleInitialization : public Initialization {
47-
public:
48-
BlackHoleInitialization() {}
49-
50-
bool canSplitIntoTupleElements() const override {
51-
return true;
52-
}
53-
54-
MutableArrayRef<InitializationPtr>
55-
splitIntoTupleElements(SILGenFunction &SGF, SILLocation loc,
56-
CanType type,
57-
SmallVectorImpl<InitializationPtr> &buf) override {
58-
// "Destructure" an ignored binding into multiple ignored bindings.
59-
for (auto fieldType : cast<TupleType>(type)->getElementTypes()) {
60-
(void) fieldType;
61-
buf.push_back(InitializationPtr(new BlackHoleInitialization()));
62-
}
63-
return buf;
64-
}
65-
66-
void copyOrInitValueInto(SILGenFunction &SGF, SILLocation loc,
67-
ManagedValue value, bool isInit) override {
68-
/// This just ignores the provided value.
69-
}
70-
71-
void finishUninitialized(SILGenFunction &SGF) override {
72-
// do nothing
73-
}
74-
};
75-
} // end anonymous namespace
76-
7742
static void copyOrInitValueIntoHelper(
7843
SILGenFunction &SGF, SILLocation loc, ManagedValue value, bool isInit,
7944
ArrayRef<InitializationPtr> subInitializations,
@@ -1290,7 +1255,7 @@ void SILGenFunction::emitStmtCondition(StmtCondition Cond, JumpDest FalseDest,
12901255
switch (elt.getKind()) {
12911256
case StmtConditionElement::CK_PatternBinding: {
12921257
InitializationPtr initialization =
1293-
InitializationForPattern(*this, FalseDest).visit(elt.getPattern());
1258+
emitPatternBindingInitialization(elt.getPattern(), FalseDest);
12941259

12951260
// Emit the initial value into the initialization.
12961261
FullExpr Scope(Cleanups, CleanupLocation(elt.getInitializer()));

test/IRGen/generic_structs.swift

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -disable-type-layout -primary-file %s -emit-ir | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize -DINT=i%target-ptrsize -DINT_32=i32
1+
// RUN: %target-swift-frontend -disable-type-layout -primary-file %s -emit-ir
22

33
struct A<T1, T2>
44
{
@@ -37,13 +37,3 @@ public struct GenericStruct<T : Proto> {
3737

3838
public init() {}
3939
}
40-
41-
// CHECK-LABEL: define{{.*}} swiftcc void @"$s15generic_structs13GenericStructVACyxGycfC"
42-
// CHECK: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s15generic_structs13GenericStructVMa"([[INT]] 0, %swift.type* %T, i8** %T.Proto)
43-
// CHECK: [[TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
44-
// CHECK: [[PTR:%.*]] = bitcast %swift.type* [[TYPE]] to [[INT_32]]*
45-
// CHECK: [[FIELDOFFSET:%.*]] = getelementptr inbounds [[INT_32]], [[INT_32]]* [[PTR]], [[INT]] [[IDX:6|10]]
46-
// CHECK: [[OFFSET:%.*]] = load [[INT_32]], [[INT_32]]* [[FIELDOFFSET]]
47-
// CHECK: [[ADDROFOPT:%.*]] = getelementptr inbounds i8, i8* {{.*}}, [[INT_32]] [[OFFSET]]
48-
// CHECK: [[OPTPTR:%.*]] = bitcast i8* [[ADDROFOPT]] to %TSq*
49-
// CHECK: call %TSq* @"$sxSg15generic_structs5ProtoRzlWOb"(%TSq* {{.*}}, %TSq* [[OPTPTR]]

test/SILGen/constrained_extensions.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,8 @@ struct AnythingGoes<T> {
177177
extension AnythingGoes where T : VeryConstrained {
178178
// CHECK-LABEL: sil hidden [ossa] @$s22constrained_extensions12AnythingGoesVA2A15VeryConstrainedRzlE13fromExtensionACyxGyt_tcfC : $@convention(method) <T where T : VeryConstrained> (@thin AnythingGoes<T>.Type) -> @out AnythingGoes<T> {
179179

180+
// CHECK: [[RESULT:%.*]] = struct_element_addr {{%.*}} : $*AnythingGoes<T>, #AnythingGoes.meaningOfLife
180181
// CHECK: [[INIT:%.*]] = function_ref @$s22constrained_extensions12AnythingGoesV13meaningOfLifexSgvpfi : $@convention(thin) <τ_0_0> () -> @out Optional<τ_0_0>
181-
// CHECK: [[RESULT:%.*]] = alloc_stack $Optional<T>
182182
// CHECK: apply [[INIT]]<T>([[RESULT]]) : $@convention(thin) <τ_0_0> () -> @out Optional<τ_0_0>
183183
// CHECK: return
184184
init(fromExtension: ()) {}

0 commit comments

Comments
 (0)