Skip to content

Commit 38e89df

Browse files
slavapestovmeg-gupta
authored andcommitted
SIL: Fix lowering for 'var's whose types contain local archetypes
A mutable 'var' becomes a SILBoxType, and we need to plumb the correct generic signature through here too. Fixes swiftlang#71921.
1 parent 2c29fac commit 38e89df

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
@@ -2036,13 +2036,12 @@ lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function,
20362036
assert(!type->hasLocalArchetype() ||
20372037
(genericSig && origGenericSig &&
20382038
!genericSig->isEqual(origGenericSig)));
2039-
type = mapTypeOutOfContext(type);
20402039

2041-
auto canType = type->getReducedType(
2040+
auto interfaceType = mapTypeOutOfContext(type)->getReducedType(
20422041
genericSig ? genericSig : origGenericSig);
20432042
auto &loweredTL =
2044-
TC.getTypeLowering(AbstractionPattern(genericSig, canType), canType,
2045-
expansion);
2043+
TC.getTypeLowering(AbstractionPattern(genericSig, interfaceType),
2044+
interfaceType, expansion);
20462045
auto loweredTy = loweredTL.getLoweredType();
20472046
switch (TC.getDeclCaptureKind(capture, expansion)) {
20482047
case CaptureKind::Constant: {
@@ -2065,12 +2064,13 @@ lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function,
20652064

20662065
// The type in the box is lowered in the minimal context.
20672066
auto minimalLoweredTy =
2068-
TC.getTypeLowering(AbstractionPattern(genericSig, canType), canType,
2067+
TC.getTypeLowering(AbstractionPattern(type), type,
20692068
TypeExpansionContext::minimal())
20702069
.getLoweredType();
20712070
// Lvalues are captured as a box that owns the captured value.
20722071
auto boxTy = TC.getInterfaceBoxTypeForCapture(
20732072
varDecl, minimalLoweredTy.getASTType(),
2073+
genericSig, capturedEnvs,
20742074
/*mutable*/ true);
20752075
auto convention = ParameterConvention::Direct_Guaranteed;
20762076
auto param = SILParameterInfo(boxTy, convention, options);
@@ -2084,12 +2084,13 @@ lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function,
20842084

20852085
// The type in the box is lowered in the minimal context.
20862086
auto minimalLoweredTy =
2087-
TC.getTypeLowering(AbstractionPattern(genericSig, canType), canType,
2087+
TC.getTypeLowering(AbstractionPattern(type), type,
20882088
TypeExpansionContext::minimal())
20892089
.getLoweredType();
20902090
// Lvalues are captured as a box that owns the captured value.
20912091
auto boxTy = TC.getInterfaceBoxTypeForCapture(
20922092
varDecl, minimalLoweredTy.getASTType(),
2093+
genericSig, capturedEnvs,
20932094
/*mutable*/ false);
20942095
auto convention = ParameterConvention::Direct_Guaranteed;
20952096
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"
@@ -4886,14 +4887,93 @@ TypeConverter::checkFunctionForABIDifferences(SILModule &M,
48864887
return ABIDifference::CompatibleRepresentation;
48874888
}
48884889

4890+
static void findCapturedEnvironments(
4891+
Type type,
4892+
SmallSetVector<GenericEnvironment *, 2> &boxCapturedEnvs) {
4893+
type.visit([&](Type t) {
4894+
if (auto *archetypeTy = t->getAs<LocalArchetypeType>()) {
4895+
boxCapturedEnvs.insert(archetypeTy->getGenericEnvironment());
4896+
}
4897+
});
4898+
}
4899+
48894900
CanSILBoxType
48904901
TypeConverter::getInterfaceBoxTypeForCapture(ValueDecl *captured,
4891-
CanType loweredInterfaceType,
4902+
CanType loweredContextType,
4903+
GenericSignature genericSig,
4904+
ArrayRef<GenericEnvironment *> capturedEnvs,
48924905
bool isMutable) {
4906+
auto boxType = getInterfaceBoxTypeForCapture(captured,
4907+
loweredContextType,
4908+
isMutable);
4909+
4910+
LLVM_DEBUG(llvm::dbgs() << "Generic signature of closure: "
4911+
<< genericSig << "\n";);
4912+
LLVM_DEBUG(llvm::dbgs() << "Box type: "
4913+
<< boxType << "\n";);
4914+
48934915
auto &C = M.getASTContext();
4894-
auto signature = getCanonicalSignatureOrNull(
4916+
auto baseGenericSig = getCanonicalSignatureOrNull(
48954917
captured->getDeclContext()->getGenericSignatureOfContext());
48964918

4919+
SmallSetVector<GenericEnvironment *, 2> boxCapturedEnvs;
4920+
findCapturedEnvironments(loweredContextType, boxCapturedEnvs);
4921+
4922+
return cast<SILBoxType>(Type(boxType).subst(
4923+
[&](SubstitutableType *t) -> Type {
4924+
auto *paramTy = cast<GenericTypeParamType>(t);
4925+
4926+
// Depth of first captured local archetype in box generic signature.
4927+
unsigned depth = baseGenericSig.getNextDepth();
4928+
4929+
// Is this a captured local archetype?
4930+
if (paramTy->getDepth() >= depth) {
4931+
// Get the environment.
4932+
auto *genericEnv = boxCapturedEnvs[paramTy->getDepth() - depth];
4933+
4934+
// Find this environment in the captured environments of our
4935+
// closure.
4936+
auto found = std::find(capturedEnvs.begin(), capturedEnvs.end(),
4937+
genericEnv);
4938+
assert(found != capturedEnvs.end());
4939+
unsigned capturedEnvIndex = found - capturedEnvs.begin();
4940+
4941+
// Remap the depth. This is necessary because the 'var' box might
4942+
// capture a subset of the captured environments of the closure.
4943+
return GenericTypeParamType::get(
4944+
/*isParameterPack=*/false,
4945+
genericSig.getNextDepth() - capturedEnvs.size() + capturedEnvIndex,
4946+
paramTy->getIndex(),
4947+
C);
4948+
}
4949+
4950+
return paramTy;
4951+
},
4952+
MakeAbstractConformanceForGenericType(),
4953+
SubstFlags::PreservePackExpansionLevel |
4954+
SubstFlags::AllowLoweredTypes)->getCanonicalType());
4955+
}
4956+
4957+
CanSILBoxType
4958+
TypeConverter::getInterfaceBoxTypeForCapture(ValueDecl *captured,
4959+
CanType loweredContextType,
4960+
bool isMutable) {
4961+
auto &C = M.getASTContext();
4962+
auto baseGenericSig = getCanonicalSignatureOrNull(
4963+
captured->getDeclContext()->getGenericSignatureOfContext());
4964+
4965+
SmallSetVector<GenericEnvironment *, 2> boxCapturedEnvs;
4966+
findCapturedEnvironments(loweredContextType, boxCapturedEnvs);
4967+
4968+
MapLocalArchetypesOutOfContext mapOutOfContext(baseGenericSig,
4969+
boxCapturedEnvs.getArrayRef());
4970+
4971+
auto loweredInterfaceType = loweredContextType.subst(
4972+
mapOutOfContext,
4973+
MakeAbstractConformanceForGenericType(),
4974+
SubstFlags::PreservePackExpansionLevel |
4975+
SubstFlags::AllowLoweredTypes)->getCanonicalType();
4976+
48974977
// If the type is not dependent at all, we can form a concrete box layout.
48984978
// We don't need to capture the generic environment.
48994979
if (!loweredInterfaceType->hasTypeParameter()) {
@@ -4902,64 +4982,44 @@ TypeConverter::getInterfaceBoxTypeForCapture(ValueDecl *captured,
49024982
/*captures generics*/ false);
49034983
return SILBoxType::get(C, layout, {});
49044984
}
4985+
4986+
auto boxGenericSig = buildGenericSignatureWithCapturedEnvironments(
4987+
M.getASTContext(), baseGenericSig,
4988+
boxCapturedEnvs.getArrayRef()).getCanonicalSignature();
49054989

49064990
// Otherwise, the layout needs to capture the generic environment of its
49074991
// originating scope.
49084992
// TODO: We could conceivably minimize the captured generic environment to
49094993
// only the parts used by the captured variable.
4910-
4911-
auto layout = SILLayout::get(C, signature,
4994+
auto layout = SILLayout::get(C, boxGenericSig,
49124995
SILField(loweredInterfaceType, isMutable),
49134996
/*captures generics*/ false);
4914-
4915-
// Instantiate the layout with identity substitutions.
4916-
auto subMap = signature->getIdentitySubstitutionMap();
49174997

4918-
auto boxTy = SILBoxType::get(C, layout, subMap);
4919-
#ifndef NDEBUG
4920-
auto loweredContextType = loweredInterfaceType;
4921-
auto contextBoxTy = boxTy;
4922-
if (signature) {
4923-
auto env = signature.getGenericEnvironment();
4924-
loweredContextType = env->mapTypeIntoContext(loweredContextType)
4925-
->getCanonicalType();
4926-
contextBoxTy = cast<SILBoxType>(
4927-
env->mapTypeIntoContext(contextBoxTy)
4928-
->getCanonicalType());
4929-
}
4998+
// Instantiate the layout with identity substitutions.
4999+
auto subMap = boxGenericSig->getIdentitySubstitutionMap();
49305000

4931-
auto ty = getSILBoxFieldType(TypeExpansionContext::minimal(), contextBoxTy,
4932-
*this, 0);
4933-
assert(contextBoxTy->getLayout()->getFields().size() == 1 &&
4934-
ty.getRawASTType() == loweredContextType &&
4935-
"box field type doesn't match capture!");
4936-
#endif
4937-
return boxTy;
5001+
return SILBoxType::get(C, layout, subMap);
49385002
}
49395003

49405004
CanSILBoxType
49415005
TypeConverter::getContextBoxTypeForCapture(ValueDecl *captured,
49425006
CanType loweredContextType,
49435007
GenericEnvironment *env,
49445008
bool isMutable) {
4945-
CanType loweredInterfaceType = loweredContextType;
4946-
if (env) {
4947-
auto homeSig = captured->getDeclContext()
4948-
->getGenericSignatureOfContext();
4949-
loweredInterfaceType =
4950-
loweredInterfaceType->mapTypeOutOfContext()
4951-
->getReducedType(homeSig);
4952-
}
4953-
5009+
SmallSetVector<GenericEnvironment *, 2> boxCapturedEnvs;
5010+
findCapturedEnvironments(loweredContextType, boxCapturedEnvs);
5011+
49545012
auto boxType = getInterfaceBoxTypeForCapture(captured,
4955-
loweredInterfaceType,
5013+
loweredContextType,
49565014
isMutable);
4957-
if (env)
4958-
boxType = cast<SILBoxType>(
4959-
env->mapTypeIntoContext(boxType)
4960-
->getCanonicalType());
4961-
4962-
return boxType;
5015+
5016+
MapIntoLocalArchetypeContext mapIntoContext(env, boxCapturedEnvs.getArrayRef());
5017+
5018+
return cast<SILBoxType>(
5019+
Type(boxType).subst(mapIntoContext,
5020+
LookUpConformanceInModule(&M),
5021+
SubstFlags::PreservePackExpansionLevel |
5022+
SubstFlags::AllowLoweredTypes)->getCanonicalType());
49635023
}
49645024

49655025
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)