Skip to content

Commit 43d0b83

Browse files
authored
Merge pull request #74521 from slavapestov/pack-element-var-6.0
[6.0] SIL: Fix lowering for 'var's whose types contain local archetypes
2 parents e50bffc + d985356 commit 43d0b83

File tree

5 files changed

+168
-52
lines changed

5 files changed

+168
-52
lines changed

include/swift/SIL/TypeLowering.h

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1253,13 +1253,25 @@ class TypeConverter {
12531253
SILDeclRef constant,
12541254
CanAnyFunctionType origInterfaceType);
12551255

1256-
/// Get the boxed interface type to use for a capture of the given decl.
1256+
/// Get the interface type for a box that holds a mutable local 'var',
1257+
/// substituted for a closure that captures some superset of the local
1258+
/// environments captured by the 'var'.
12571259
CanSILBoxType
12581260
getInterfaceBoxTypeForCapture(ValueDecl *captured,
1259-
CanType loweredInterfaceType,
1261+
CanType loweredContextType,
1262+
GenericSignature genericSig,
1263+
ArrayRef<GenericEnvironment *> capturedEnvs,
12601264
bool isMutable);
1261-
/// Get the boxed contextual type to use for a capture of the given decl
1262-
/// in the given generic environment.
1265+
1266+
/// Get the interface type for a box that holds a mutable local 'var',
1267+
/// given that the interface type of the 'var' might capture local
1268+
/// archetypes.
1269+
CanSILBoxType
1270+
getInterfaceBoxTypeForCapture(ValueDecl *captured,
1271+
CanType loweredContextType,
1272+
bool isMutable);
1273+
1274+
/// Get the contextual type for a box that holds a mutable local 'var'.
12631275
CanSILBoxType
12641276
getContextBoxTypeForCapture(ValueDecl *captured,
12651277
CanType loweredContextType,

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1999,13 +1999,12 @@ lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function,
19991999
assert(!type->hasLocalArchetype() ||
20002000
(genericSig && origGenericSig &&
20012001
!genericSig->isEqual(origGenericSig)));
2002-
type = mapTypeOutOfContext(type);
20032002

2004-
auto canType = type->getReducedType(
2003+
auto interfaceType = mapTypeOutOfContext(type)->getReducedType(
20052004
genericSig ? genericSig : origGenericSig);
20062005
auto &loweredTL =
2007-
TC.getTypeLowering(AbstractionPattern(genericSig, canType), canType,
2008-
expansion);
2006+
TC.getTypeLowering(AbstractionPattern(genericSig, interfaceType),
2007+
interfaceType, expansion);
20092008
auto loweredTy = loweredTL.getLoweredType();
20102009
switch (TC.getDeclCaptureKind(capture, expansion)) {
20112010
case CaptureKind::Constant: {
@@ -2028,12 +2027,13 @@ lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function,
20282027

20292028
// The type in the box is lowered in the minimal context.
20302029
auto minimalLoweredTy =
2031-
TC.getTypeLowering(AbstractionPattern(genericSig, canType), canType,
2030+
TC.getTypeLowering(AbstractionPattern(type), type,
20322031
TypeExpansionContext::minimal())
20332032
.getLoweredType();
20342033
// Lvalues are captured as a box that owns the captured value.
20352034
auto boxTy = TC.getInterfaceBoxTypeForCapture(
20362035
varDecl, minimalLoweredTy.getASTType(),
2036+
genericSig, capturedEnvs,
20372037
/*mutable*/ true);
20382038
auto convention = ParameterConvention::Direct_Guaranteed;
20392039
auto param = SILParameterInfo(boxTy, convention, options);
@@ -2047,12 +2047,13 @@ lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function,
20472047

20482048
// The type in the box is lowered in the minimal context.
20492049
auto minimalLoweredTy =
2050-
TC.getTypeLowering(AbstractionPattern(genericSig, canType), canType,
2050+
TC.getTypeLowering(AbstractionPattern(type), type,
20512051
TypeExpansionContext::minimal())
20522052
.getLoweredType();
20532053
// Lvalues are captured as a box that owns the captured value.
20542054
auto boxTy = TC.getInterfaceBoxTypeForCapture(
20552055
varDecl, minimalLoweredTy.getASTType(),
2056+
genericSig, capturedEnvs,
20562057
/*mutable*/ false);
20572058
auto convention = ParameterConvention::Direct_Guaranteed;
20582059
auto param = SILParameterInfo(boxTy, convention, options);

lib/SIL/IR/TypeLowering.cpp

Lines changed: 102 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "swift/AST/SourceFile.h"
3333
#include "swift/AST/TypeDifferenceVisitor.h"
3434
#include "swift/AST/Types.h"
35+
#include "swift/Basic/LLVMExtras.h"
3536
#include "swift/ClangImporter/ClangModule.h"
3637
#include "swift/SIL/AbstractionPatternGenerators.h"
3738
#include "swift/SIL/PrettyStackTrace.h"
@@ -4848,14 +4849,93 @@ TypeConverter::checkFunctionForABIDifferences(SILModule &M,
48484849
return ABIDifference::CompatibleRepresentation;
48494850
}
48504851

4852+
static void findCapturedEnvironments(
4853+
Type type,
4854+
SmallSetVector<GenericEnvironment *, 2> &boxCapturedEnvs) {
4855+
type.visit([&](Type t) {
4856+
if (auto *archetypeTy = t->getAs<LocalArchetypeType>()) {
4857+
boxCapturedEnvs.insert(archetypeTy->getGenericEnvironment());
4858+
}
4859+
});
4860+
}
4861+
48514862
CanSILBoxType
48524863
TypeConverter::getInterfaceBoxTypeForCapture(ValueDecl *captured,
4853-
CanType loweredInterfaceType,
4864+
CanType loweredContextType,
4865+
GenericSignature genericSig,
4866+
ArrayRef<GenericEnvironment *> capturedEnvs,
48544867
bool isMutable) {
4868+
auto boxType = getInterfaceBoxTypeForCapture(captured,
4869+
loweredContextType,
4870+
isMutable);
4871+
4872+
LLVM_DEBUG(llvm::dbgs() << "Generic signature of closure: "
4873+
<< genericSig << "\n";);
4874+
LLVM_DEBUG(llvm::dbgs() << "Box type: "
4875+
<< boxType << "\n";);
4876+
48554877
auto &C = M.getASTContext();
4856-
auto signature = getCanonicalSignatureOrNull(
4878+
auto baseGenericSig = getCanonicalSignatureOrNull(
48574879
captured->getDeclContext()->getGenericSignatureOfContext());
48584880

4881+
SmallSetVector<GenericEnvironment *, 2> boxCapturedEnvs;
4882+
findCapturedEnvironments(loweredContextType, boxCapturedEnvs);
4883+
4884+
return cast<SILBoxType>(Type(boxType).subst(
4885+
[&](SubstitutableType *t) -> Type {
4886+
auto *paramTy = cast<GenericTypeParamType>(t);
4887+
4888+
// Depth of first captured local archetype in box generic signature.
4889+
unsigned depth = baseGenericSig.getNextDepth();
4890+
4891+
// Is this a captured local archetype?
4892+
if (paramTy->getDepth() >= depth) {
4893+
// Get the environment.
4894+
auto *genericEnv = boxCapturedEnvs[paramTy->getDepth() - depth];
4895+
4896+
// Find this environment in the captured environments of our
4897+
// closure.
4898+
auto found = std::find(capturedEnvs.begin(), capturedEnvs.end(),
4899+
genericEnv);
4900+
assert(found != capturedEnvs.end());
4901+
unsigned capturedEnvIndex = found - capturedEnvs.begin();
4902+
4903+
// Remap the depth. This is necessary because the 'var' box might
4904+
// capture a subset of the captured environments of the closure.
4905+
return GenericTypeParamType::get(
4906+
/*isParameterPack=*/false,
4907+
genericSig.getNextDepth() - capturedEnvs.size() + capturedEnvIndex,
4908+
paramTy->getIndex(),
4909+
C);
4910+
}
4911+
4912+
return paramTy;
4913+
},
4914+
MakeAbstractConformanceForGenericType(),
4915+
SubstFlags::PreservePackExpansionLevel |
4916+
SubstFlags::AllowLoweredTypes)->getCanonicalType());
4917+
}
4918+
4919+
CanSILBoxType
4920+
TypeConverter::getInterfaceBoxTypeForCapture(ValueDecl *captured,
4921+
CanType loweredContextType,
4922+
bool isMutable) {
4923+
auto &C = M.getASTContext();
4924+
auto baseGenericSig = getCanonicalSignatureOrNull(
4925+
captured->getDeclContext()->getGenericSignatureOfContext());
4926+
4927+
SmallSetVector<GenericEnvironment *, 2> boxCapturedEnvs;
4928+
findCapturedEnvironments(loweredContextType, boxCapturedEnvs);
4929+
4930+
MapLocalArchetypesOutOfContext mapOutOfContext(baseGenericSig,
4931+
boxCapturedEnvs.getArrayRef());
4932+
4933+
auto loweredInterfaceType = loweredContextType.subst(
4934+
mapOutOfContext,
4935+
MakeAbstractConformanceForGenericType(),
4936+
SubstFlags::PreservePackExpansionLevel |
4937+
SubstFlags::AllowLoweredTypes)->getCanonicalType();
4938+
48594939
// If the type is not dependent at all, we can form a concrete box layout.
48604940
// We don't need to capture the generic environment.
48614941
if (!loweredInterfaceType->hasTypeParameter()) {
@@ -4864,64 +4944,44 @@ TypeConverter::getInterfaceBoxTypeForCapture(ValueDecl *captured,
48644944
/*captures generics*/ false);
48654945
return SILBoxType::get(C, layout, {});
48664946
}
4947+
4948+
auto boxGenericSig = buildGenericSignatureWithCapturedEnvironments(
4949+
M.getASTContext(), baseGenericSig,
4950+
boxCapturedEnvs.getArrayRef()).getCanonicalSignature();
48674951

48684952
// Otherwise, the layout needs to capture the generic environment of its
48694953
// originating scope.
48704954
// TODO: We could conceivably minimize the captured generic environment to
48714955
// only the parts used by the captured variable.
4872-
4873-
auto layout = SILLayout::get(C, signature,
4956+
auto layout = SILLayout::get(C, boxGenericSig,
48744957
SILField(loweredInterfaceType, isMutable),
48754958
/*captures generics*/ false);
4876-
4877-
// Instantiate the layout with identity substitutions.
4878-
auto subMap = signature->getIdentitySubstitutionMap();
48794959

4880-
auto boxTy = SILBoxType::get(C, layout, subMap);
4881-
#ifndef NDEBUG
4882-
auto loweredContextType = loweredInterfaceType;
4883-
auto contextBoxTy = boxTy;
4884-
if (signature) {
4885-
auto env = signature.getGenericEnvironment();
4886-
loweredContextType = env->mapTypeIntoContext(loweredContextType)
4887-
->getCanonicalType();
4888-
contextBoxTy = cast<SILBoxType>(
4889-
env->mapTypeIntoContext(contextBoxTy)
4890-
->getCanonicalType());
4891-
}
4960+
// Instantiate the layout with identity substitutions.
4961+
auto subMap = boxGenericSig->getIdentitySubstitutionMap();
48924962

4893-
auto ty = getSILBoxFieldType(TypeExpansionContext::minimal(), contextBoxTy,
4894-
*this, 0);
4895-
assert(contextBoxTy->getLayout()->getFields().size() == 1 &&
4896-
ty.getRawASTType() == loweredContextType &&
4897-
"box field type doesn't match capture!");
4898-
#endif
4899-
return boxTy;
4963+
return SILBoxType::get(C, layout, subMap);
49004964
}
49014965

49024966
CanSILBoxType
49034967
TypeConverter::getContextBoxTypeForCapture(ValueDecl *captured,
49044968
CanType loweredContextType,
49054969
GenericEnvironment *env,
49064970
bool isMutable) {
4907-
CanType loweredInterfaceType = loweredContextType;
4908-
if (env) {
4909-
auto homeSig = captured->getDeclContext()
4910-
->getGenericSignatureOfContext();
4911-
loweredInterfaceType =
4912-
loweredInterfaceType->mapTypeOutOfContext()
4913-
->getReducedType(homeSig);
4914-
}
4915-
4971+
SmallSetVector<GenericEnvironment *, 2> boxCapturedEnvs;
4972+
findCapturedEnvironments(loweredContextType, boxCapturedEnvs);
4973+
49164974
auto boxType = getInterfaceBoxTypeForCapture(captured,
4917-
loweredInterfaceType,
4975+
loweredContextType,
49184976
isMutable);
4919-
if (env)
4920-
boxType = cast<SILBoxType>(
4921-
env->mapTypeIntoContext(boxType)
4922-
->getCanonicalType());
4923-
4924-
return boxType;
4977+
4978+
MapIntoLocalArchetypeContext mapIntoContext(env, boxCapturedEnvs.getArrayRef());
4979+
4980+
return cast<SILBoxType>(
4981+
Type(boxType).subst(mapIntoContext,
4982+
LookUpConformanceInModule(&M),
4983+
SubstFlags::PreservePackExpansionLevel |
4984+
SubstFlags::AllowLoweredTypes)->getCanonicalType());
49254985
}
49264986

49274987
CanSILBoxType TypeConverter::getBoxTypeForEnumElement(

test/SILGen/element_archetype_captures.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,25 @@ public func anotherPackFunction<each T>(_ ts: repeat each T) {
4141
}
4242
}
4343
}
44+
45+
public func varCaptures<each T, each U>(ts: repeat each T, us: repeat each U) {
46+
for t in repeat each ts {
47+
for u in repeat each us {
48+
var both = (t, u)
49+
both = (t, u)
50+
let capture_both = { both = (t, u) }
51+
capture_both()
52+
53+
var just_u = u
54+
just_u = u
55+
let capture_u = { _ = t; just_u = u }
56+
capture_u()
57+
58+
var just_t = t
59+
just_t = t
60+
let capture_t = { just_t = t; _ = u }
61+
capture_t()
62+
}
63+
}
64+
}
65+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %target-swift-frontend -emit-ir %s -disable-availability-checking
2+
3+
public protocol Signal {
4+
mutating func process() -> Float
5+
}
6+
7+
public struct Mixer<each Source: Signal> {
8+
public var sources: (repeat each Source)
9+
10+
public mutating func process() -> Float {
11+
var result: Float = 0
12+
13+
self.sources = (repeat ({
14+
var signal = $0
15+
result += signal.process()
16+
return signal
17+
}(each sources)))
18+
19+
return result
20+
}
21+
}

0 commit comments

Comments
 (0)