mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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 https://github.com/apple/swift/issues/71921.
This commit is contained in:
@@ -1253,13 +1253,25 @@ public:
|
||||
SILDeclRef constant,
|
||||
CanAnyFunctionType origInterfaceType);
|
||||
|
||||
/// Get the boxed interface type to use for a capture of the given decl.
|
||||
/// Get the interface type for a box that holds a mutable local 'var',
|
||||
/// substituted for a closure that captures some superset of the local
|
||||
/// environments captured by the 'var'.
|
||||
CanSILBoxType
|
||||
getInterfaceBoxTypeForCapture(ValueDecl *captured,
|
||||
CanType loweredInterfaceType,
|
||||
CanType loweredContextType,
|
||||
GenericSignature genericSig,
|
||||
ArrayRef<GenericEnvironment *> capturedEnvs,
|
||||
bool isMutable);
|
||||
/// Get the boxed contextual type to use for a capture of the given decl
|
||||
/// in the given generic environment.
|
||||
|
||||
/// Get the interface type for a box that holds a mutable local 'var',
|
||||
/// given that the interface type of the 'var' might capture local
|
||||
/// archetypes.
|
||||
CanSILBoxType
|
||||
getInterfaceBoxTypeForCapture(ValueDecl *captured,
|
||||
CanType loweredContextType,
|
||||
bool isMutable);
|
||||
|
||||
/// Get the contextual type for a box that holds a mutable local 'var'.
|
||||
CanSILBoxType
|
||||
getContextBoxTypeForCapture(ValueDecl *captured,
|
||||
CanType loweredContextType,
|
||||
|
||||
@@ -2036,13 +2036,12 @@ lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function,
|
||||
assert(!type->hasLocalArchetype() ||
|
||||
(genericSig && origGenericSig &&
|
||||
!genericSig->isEqual(origGenericSig)));
|
||||
type = mapTypeOutOfContext(type);
|
||||
|
||||
auto canType = type->getReducedType(
|
||||
auto interfaceType = mapTypeOutOfContext(type)->getReducedType(
|
||||
genericSig ? genericSig : origGenericSig);
|
||||
auto &loweredTL =
|
||||
TC.getTypeLowering(AbstractionPattern(genericSig, canType), canType,
|
||||
expansion);
|
||||
TC.getTypeLowering(AbstractionPattern(genericSig, interfaceType),
|
||||
interfaceType, expansion);
|
||||
auto loweredTy = loweredTL.getLoweredType();
|
||||
switch (TC.getDeclCaptureKind(capture, expansion)) {
|
||||
case CaptureKind::Constant: {
|
||||
@@ -2065,12 +2064,13 @@ lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function,
|
||||
|
||||
// The type in the box is lowered in the minimal context.
|
||||
auto minimalLoweredTy =
|
||||
TC.getTypeLowering(AbstractionPattern(genericSig, canType), canType,
|
||||
TC.getTypeLowering(AbstractionPattern(type), type,
|
||||
TypeExpansionContext::minimal())
|
||||
.getLoweredType();
|
||||
// Lvalues are captured as a box that owns the captured value.
|
||||
auto boxTy = TC.getInterfaceBoxTypeForCapture(
|
||||
varDecl, minimalLoweredTy.getASTType(),
|
||||
genericSig, capturedEnvs,
|
||||
/*mutable*/ true);
|
||||
auto convention = ParameterConvention::Direct_Guaranteed;
|
||||
auto param = SILParameterInfo(boxTy, convention, options);
|
||||
@@ -2084,12 +2084,13 @@ lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function,
|
||||
|
||||
// The type in the box is lowered in the minimal context.
|
||||
auto minimalLoweredTy =
|
||||
TC.getTypeLowering(AbstractionPattern(genericSig, canType), canType,
|
||||
TC.getTypeLowering(AbstractionPattern(type), type,
|
||||
TypeExpansionContext::minimal())
|
||||
.getLoweredType();
|
||||
// Lvalues are captured as a box that owns the captured value.
|
||||
auto boxTy = TC.getInterfaceBoxTypeForCapture(
|
||||
varDecl, minimalLoweredTy.getASTType(),
|
||||
genericSig, capturedEnvs,
|
||||
/*mutable*/ false);
|
||||
auto convention = ParameterConvention::Direct_Guaranteed;
|
||||
auto param = SILParameterInfo(boxTy, convention, options);
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "swift/AST/SourceFile.h"
|
||||
#include "swift/AST/TypeDifferenceVisitor.h"
|
||||
#include "swift/AST/Types.h"
|
||||
#include "swift/Basic/LLVMExtras.h"
|
||||
#include "swift/ClangImporter/ClangModule.h"
|
||||
#include "swift/SIL/AbstractionPatternGenerators.h"
|
||||
#include "swift/SIL/PrettyStackTrace.h"
|
||||
@@ -4886,14 +4887,93 @@ TypeConverter::checkFunctionForABIDifferences(SILModule &M,
|
||||
return ABIDifference::CompatibleRepresentation;
|
||||
}
|
||||
|
||||
static void findCapturedEnvironments(
|
||||
Type type,
|
||||
SmallSetVector<GenericEnvironment *, 2> &boxCapturedEnvs) {
|
||||
type.visit([&](Type t) {
|
||||
if (auto *archetypeTy = t->getAs<LocalArchetypeType>()) {
|
||||
boxCapturedEnvs.insert(archetypeTy->getGenericEnvironment());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
CanSILBoxType
|
||||
TypeConverter::getInterfaceBoxTypeForCapture(ValueDecl *captured,
|
||||
CanType loweredInterfaceType,
|
||||
CanType loweredContextType,
|
||||
GenericSignature genericSig,
|
||||
ArrayRef<GenericEnvironment *> capturedEnvs,
|
||||
bool isMutable) {
|
||||
auto boxType = getInterfaceBoxTypeForCapture(captured,
|
||||
loweredContextType,
|
||||
isMutable);
|
||||
|
||||
LLVM_DEBUG(llvm::dbgs() << "Generic signature of closure: "
|
||||
<< genericSig << "\n";);
|
||||
LLVM_DEBUG(llvm::dbgs() << "Box type: "
|
||||
<< boxType << "\n";);
|
||||
|
||||
auto &C = M.getASTContext();
|
||||
auto signature = getCanonicalSignatureOrNull(
|
||||
auto baseGenericSig = getCanonicalSignatureOrNull(
|
||||
captured->getDeclContext()->getGenericSignatureOfContext());
|
||||
|
||||
SmallSetVector<GenericEnvironment *, 2> boxCapturedEnvs;
|
||||
findCapturedEnvironments(loweredContextType, boxCapturedEnvs);
|
||||
|
||||
return cast<SILBoxType>(Type(boxType).subst(
|
||||
[&](SubstitutableType *t) -> Type {
|
||||
auto *paramTy = cast<GenericTypeParamType>(t);
|
||||
|
||||
// Depth of first captured local archetype in box generic signature.
|
||||
unsigned depth = baseGenericSig.getNextDepth();
|
||||
|
||||
// Is this a captured local archetype?
|
||||
if (paramTy->getDepth() >= depth) {
|
||||
// Get the environment.
|
||||
auto *genericEnv = boxCapturedEnvs[paramTy->getDepth() - depth];
|
||||
|
||||
// Find this environment in the captured environments of our
|
||||
// closure.
|
||||
auto found = std::find(capturedEnvs.begin(), capturedEnvs.end(),
|
||||
genericEnv);
|
||||
assert(found != capturedEnvs.end());
|
||||
unsigned capturedEnvIndex = found - capturedEnvs.begin();
|
||||
|
||||
// Remap the depth. This is necessary because the 'var' box might
|
||||
// capture a subset of the captured environments of the closure.
|
||||
return GenericTypeParamType::get(
|
||||
/*isParameterPack=*/false,
|
||||
genericSig.getNextDepth() - capturedEnvs.size() + capturedEnvIndex,
|
||||
paramTy->getIndex(),
|
||||
C);
|
||||
}
|
||||
|
||||
return paramTy;
|
||||
},
|
||||
MakeAbstractConformanceForGenericType(),
|
||||
SubstFlags::PreservePackExpansionLevel |
|
||||
SubstFlags::AllowLoweredTypes)->getCanonicalType());
|
||||
}
|
||||
|
||||
CanSILBoxType
|
||||
TypeConverter::getInterfaceBoxTypeForCapture(ValueDecl *captured,
|
||||
CanType loweredContextType,
|
||||
bool isMutable) {
|
||||
auto &C = M.getASTContext();
|
||||
auto baseGenericSig = getCanonicalSignatureOrNull(
|
||||
captured->getDeclContext()->getGenericSignatureOfContext());
|
||||
|
||||
SmallSetVector<GenericEnvironment *, 2> boxCapturedEnvs;
|
||||
findCapturedEnvironments(loweredContextType, boxCapturedEnvs);
|
||||
|
||||
MapLocalArchetypesOutOfContext mapOutOfContext(baseGenericSig,
|
||||
boxCapturedEnvs.getArrayRef());
|
||||
|
||||
auto loweredInterfaceType = loweredContextType.subst(
|
||||
mapOutOfContext,
|
||||
MakeAbstractConformanceForGenericType(),
|
||||
SubstFlags::PreservePackExpansionLevel |
|
||||
SubstFlags::AllowLoweredTypes)->getCanonicalType();
|
||||
|
||||
// If the type is not dependent at all, we can form a concrete box layout.
|
||||
// We don't need to capture the generic environment.
|
||||
if (!loweredInterfaceType->hasTypeParameter()) {
|
||||
@@ -4902,39 +4982,23 @@ TypeConverter::getInterfaceBoxTypeForCapture(ValueDecl *captured,
|
||||
/*captures generics*/ false);
|
||||
return SILBoxType::get(C, layout, {});
|
||||
}
|
||||
|
||||
auto boxGenericSig = buildGenericSignatureWithCapturedEnvironments(
|
||||
M.getASTContext(), baseGenericSig,
|
||||
boxCapturedEnvs.getArrayRef()).getCanonicalSignature();
|
||||
|
||||
// Otherwise, the layout needs to capture the generic environment of its
|
||||
// originating scope.
|
||||
// TODO: We could conceivably minimize the captured generic environment to
|
||||
// only the parts used by the captured variable.
|
||||
|
||||
auto layout = SILLayout::get(C, signature,
|
||||
auto layout = SILLayout::get(C, boxGenericSig,
|
||||
SILField(loweredInterfaceType, isMutable),
|
||||
/*captures generics*/ false);
|
||||
|
||||
|
||||
// Instantiate the layout with identity substitutions.
|
||||
auto subMap = signature->getIdentitySubstitutionMap();
|
||||
auto subMap = boxGenericSig->getIdentitySubstitutionMap();
|
||||
|
||||
auto boxTy = SILBoxType::get(C, layout, subMap);
|
||||
#ifndef NDEBUG
|
||||
auto loweredContextType = loweredInterfaceType;
|
||||
auto contextBoxTy = boxTy;
|
||||
if (signature) {
|
||||
auto env = signature.getGenericEnvironment();
|
||||
loweredContextType = env->mapTypeIntoContext(loweredContextType)
|
||||
->getCanonicalType();
|
||||
contextBoxTy = cast<SILBoxType>(
|
||||
env->mapTypeIntoContext(contextBoxTy)
|
||||
->getCanonicalType());
|
||||
}
|
||||
|
||||
auto ty = getSILBoxFieldType(TypeExpansionContext::minimal(), contextBoxTy,
|
||||
*this, 0);
|
||||
assert(contextBoxTy->getLayout()->getFields().size() == 1 &&
|
||||
ty.getRawASTType() == loweredContextType &&
|
||||
"box field type doesn't match capture!");
|
||||
#endif
|
||||
return boxTy;
|
||||
return SILBoxType::get(C, layout, subMap);
|
||||
}
|
||||
|
||||
CanSILBoxType
|
||||
@@ -4942,24 +5006,20 @@ TypeConverter::getContextBoxTypeForCapture(ValueDecl *captured,
|
||||
CanType loweredContextType,
|
||||
GenericEnvironment *env,
|
||||
bool isMutable) {
|
||||
CanType loweredInterfaceType = loweredContextType;
|
||||
if (env) {
|
||||
auto homeSig = captured->getDeclContext()
|
||||
->getGenericSignatureOfContext();
|
||||
loweredInterfaceType =
|
||||
loweredInterfaceType->mapTypeOutOfContext()
|
||||
->getReducedType(homeSig);
|
||||
}
|
||||
|
||||
SmallSetVector<GenericEnvironment *, 2> boxCapturedEnvs;
|
||||
findCapturedEnvironments(loweredContextType, boxCapturedEnvs);
|
||||
|
||||
auto boxType = getInterfaceBoxTypeForCapture(captured,
|
||||
loweredInterfaceType,
|
||||
loweredContextType,
|
||||
isMutable);
|
||||
if (env)
|
||||
boxType = cast<SILBoxType>(
|
||||
env->mapTypeIntoContext(boxType)
|
||||
->getCanonicalType());
|
||||
|
||||
return boxType;
|
||||
|
||||
MapIntoLocalArchetypeContext mapIntoContext(env, boxCapturedEnvs.getArrayRef());
|
||||
|
||||
return cast<SILBoxType>(
|
||||
Type(boxType).subst(mapIntoContext,
|
||||
LookUpConformanceInModule(&M),
|
||||
SubstFlags::PreservePackExpansionLevel |
|
||||
SubstFlags::AllowLoweredTypes)->getCanonicalType());
|
||||
}
|
||||
|
||||
CanSILBoxType TypeConverter::getBoxTypeForEnumElement(
|
||||
|
||||
@@ -41,3 +41,25 @@ public func anotherPackFunction<each T>(_ ts: repeat each T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func varCaptures<each T, each U>(ts: repeat each T, us: repeat each U) {
|
||||
for t in repeat each ts {
|
||||
for u in repeat each us {
|
||||
var both = (t, u)
|
||||
both = (t, u)
|
||||
let capture_both = { both = (t, u) }
|
||||
capture_both()
|
||||
|
||||
var just_u = u
|
||||
just_u = u
|
||||
let capture_u = { _ = t; just_u = u }
|
||||
capture_u()
|
||||
|
||||
var just_t = t
|
||||
just_t = t
|
||||
let capture_t = { just_t = t; _ = u }
|
||||
capture_t()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
21
validation-test/compiler_crashers_2_fixed/issue-71921.swift
Normal file
21
validation-test/compiler_crashers_2_fixed/issue-71921.swift
Normal file
@@ -0,0 +1,21 @@
|
||||
// RUN: %target-swift-frontend -emit-ir %s -disable-availability-checking
|
||||
|
||||
public protocol Signal {
|
||||
mutating func process() -> Float
|
||||
}
|
||||
|
||||
public struct Mixer<each Source: Signal> {
|
||||
public var sources: (repeat each Source)
|
||||
|
||||
public mutating func process() -> Float {
|
||||
var result: Float = 0
|
||||
|
||||
self.sources = (repeat ({
|
||||
var signal = $0
|
||||
result += signal.process()
|
||||
return signal
|
||||
}(each sources)))
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user