Skip to content

Commit df7326d

Browse files
committed
Fix SILType::isEscapable for box types.
SILBoxTypes have their own generic signature and substitution map. This means that every time we query isEscapable or mayEscape, we need to extract the type of the box's field and perform type substitution so that the AST query only sees types from the function's generic environment. Fixes rdar://124179106 (Assertion failed in SIL: (!type->hasTypeParameter() && "caller forgot to mapTypeIntoContext!"))
1 parent 1a84094 commit df7326d

File tree

9 files changed

+59
-22
lines changed

9 files changed

+59
-22
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/AllocVectorLowering.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ private struct ComputeNonEscapingLiferange : EscapeVisitorWithResult {
414414
if dominates {
415415
liferange.insert(user)
416416
}
417-
if !apply.type.isEscapable {
417+
if !apply.isEscapable {
418418
return .abort
419419
}
420420
return .ignore

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceDiagnostics.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ let lifetimeDependenceDiagnosticsPass = FunctionPass(
3535
log(" --- Diagnosing lifetime dependence in \(function.name)")
3636
log("\(function)")
3737

38-
for argument in function.arguments where !argument.type.isEscapable {
38+
for argument in function.arguments
39+
where !argument.type.isEscapable(in: function)
40+
{
3941
// Indirect results are not checked here. Type checking ensures
4042
// that they have a lifetime dependence.
4143
if let lifetimeDep = LifetimeDependence(argument, context) {

SwiftCompilerSources/Sources/Optimizer/Utilities/LifetimeDependenceUtils.swift

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ extension LifetimeDependence {
219219
//
220220
// TODO: handle indirect results
221221
init?(unsafeApplyResult value: Value, _ context: some Context) {
222-
if value.type.isEscapable {
222+
if value.isEscapable {
223223
return nil
224224
}
225225
if (value.definingInstruction as! FullApplySite).hasResultDependence {
@@ -832,7 +832,7 @@ extension LifetimeDependenceDefUseWalker {
832832
mutating func walkDownUses(of value: Value, using operand: Operand?)
833833
-> WalkResult {
834834
// Only track ~Escapable and @noescape types.
835-
if value.type.mayEscape {
835+
if value.mayEscape {
836836
return .continueWalk
837837
}
838838
return walkDownUsesDefault(forwarding: value, using: operand)
@@ -857,10 +857,10 @@ extension LifetimeDependenceDefUseWalker {
857857
if let apply = operand.instruction as? FullApplySite {
858858
return visitAppliedUse(of: operand, by: apply)
859859
}
860-
if operand.instruction is ReturnInst, !operand.value.type.isEscapable {
860+
if operand.instruction is ReturnInst, !operand.value.isEscapable {
861861
return returnedDependence(result: operand)
862862
}
863-
if operand.instruction is YieldInst, !operand.value.type.isEscapable {
863+
if operand.instruction is YieldInst, !operand.value.isEscapable {
864864
return yieldedDependence(result: operand)
865865
}
866866
return escapingDependence(on: operand)
@@ -1025,10 +1025,10 @@ extension LifetimeDependenceDefUseWalker {
10251025
assert(!mdi.isUnresolved && !mdi.isNonEscaping,
10261026
"should be handled as a dependence by AddressUseVisitor")
10271027
}
1028-
if operand.instruction is ReturnInst, !operand.value.type.isEscapable {
1028+
if operand.instruction is ReturnInst, !operand.value.isEscapable {
10291029
return returnedDependence(result: operand)
10301030
}
1031-
if operand.instruction is YieldInst, !operand.value.type.isEscapable {
1031+
if operand.instruction is YieldInst, !operand.value.isEscapable {
10321032
return yieldedDependence(result: operand)
10331033
}
10341034
return escapingDependence(on: operand)
@@ -1088,19 +1088,19 @@ extension LifetimeDependenceDefUseWalker {
10881088
case let .argument(arg):
10891089
if arg.convention.isIndirectIn || arg.convention.isInout {
10901090
allocation = arg
1091-
} else if arg.convention.isIndirectOut, !arg.type.isEscapable {
1091+
} else if arg.convention.isIndirectOut, !arg.isEscapable {
10921092
return returnedDependence(address: arg, using: operand)
10931093
}
10941094
break
10951095
case .global, .class, .tail, .yield, .pointer, .unidentified:
10961096
break
10971097
}
10981098
if let allocation = allocation {
1099-
if !allocation.type.objectType.isEscapable {
1099+
if !allocation.isEscapable {
11001100
return visitLocalStore(allocation: allocation, storedOperand: operand, storeAddress: address)
11011101
}
11021102
}
1103-
if address.type.objectType.isEscapable {
1103+
if address.isEscapable {
11041104
return .continueWalk
11051105
}
11061106
return escapingDependence(on: operand)
@@ -1179,13 +1179,13 @@ extension LifetimeDependenceDefUseWalker {
11791179
// If the lifetime dependence is scoped, then we can ignore it
11801180
// because a mark_dependence [nonescaping] represents the
11811181
// dependence.
1182-
if let result = apply.singleDirectResult, !result.type.isEscapable {
1182+
if let result = apply.singleDirectResult, !result.isEscapable {
11831183
if dependentUse(of: operand, into: result) == .abortWalk {
11841184
return .abortWalk
11851185
}
11861186
}
11871187
for resultAddr in apply.indirectResultOperands
1188-
where !resultAddr.value.type.isEscapable {
1188+
where !resultAddr.value.isEscapable {
11891189
if visitStoredUses(of: operand, into: resultAddr.value) == .abortWalk {
11901190
return .abortWalk
11911191
}

SwiftCompilerSources/Sources/SIL/Type.swift

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,12 @@ public struct Type : CustomStringConvertible, NoReflectionChildren {
6363

6464
public var isMoveOnly: Bool { bridged.isMoveOnly() }
6565

66-
public var isEscapable: Bool { bridged.isEscapable() }
67-
public var mayEscape: Bool { !isNoEscapeFunction && isEscapable }
66+
public func isEscapable(in function: Function) -> Bool {
67+
bridged.isEscapable(function.bridged)
68+
}
69+
public func mayEscape(in function: Function) -> Bool {
70+
!isNoEscapeFunction && isEscapable(in: function)
71+
}
6872

6973
/// Can only be used if the type is in fact a nominal type (`isNominal` is true).
7074
public var nominal: NominalTypeDecl {
@@ -146,6 +150,16 @@ public struct Type : CustomStringConvertible, NoReflectionChildren {
146150
}
147151
}
148152

153+
extension Value {
154+
public var isEscapable: Bool {
155+
type.objectType.isEscapable(in: parentFunction)
156+
}
157+
158+
public var mayEscape: Bool {
159+
type.objectType.mayEscape(in: parentFunction)
160+
}
161+
}
162+
149163
extension Type: Equatable {
150164
public static func ==(lhs: Type, rhs: Type) -> Bool {
151165
lhs.bridged.opaqueValue == rhs.bridged.opaqueValue

include/swift/SIL/SILBridging.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ struct BridgedType {
350350
BRIDGED_INLINE bool isEmpty(BridgedFunction f) const;
351351
BRIDGED_INLINE TraitResult canBeClass() const;
352352
BRIDGED_INLINE bool isMoveOnly() const;
353-
BRIDGED_INLINE bool isEscapable() const;
353+
BRIDGED_INLINE bool isEscapable(BridgedFunction f) const;
354354
BRIDGED_INLINE bool isOrContainsObjectiveCClass() const;
355355
BRIDGED_INLINE bool isBuiltinInteger() const;
356356
BRIDGED_INLINE bool isBuiltinFloat() const;

include/swift/SIL/SILBridgingImpl.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,8 +274,8 @@ bool BridgedType::isMoveOnly() const {
274274
return unbridged().isMoveOnly();
275275
}
276276

277-
bool BridgedType::isEscapable() const {
278-
return unbridged().isEscapable();
277+
bool BridgedType::isEscapable(BridgedFunction f) const {
278+
return unbridged().isEscapable(*f.getFunction());
279279
}
280280

281281
bool BridgedType::isOrContainsObjectiveCClass() const {

include/swift/SIL/SILType.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -897,13 +897,15 @@ class SILType {
897897

898898
/// False if SILValues of this type cannot be used outside the scope of their
899899
/// lifetime dependence.
900-
bool isEscapable() const;
900+
bool isEscapable(const SILFunction &function) const;
901901

902902
/// True for (isEscapable && !isNoEscapeFunction)
903903
///
904904
/// Equivalent to getASTType()->mayEscape(), but handles SIL-specific types,
905905
/// namely SILFunctionType.
906-
bool mayEscape() const { return !isNoEscapeFunction() && isEscapable(); }
906+
bool mayEscape(const SILFunction &function) const {
907+
return !isNoEscapeFunction() && isEscapable(function);
908+
}
907909

908910
//
909911
// Accessors for types used in SIL instructions:

lib/SIL/IR/SILType.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,7 +1051,7 @@ SILType::getSingletonAggregateFieldType(SILModule &M,
10511051
return SILType();
10521052
}
10531053

1054-
bool SILType::isEscapable() const {
1054+
bool SILType::isEscapable(const SILFunction &function) const {
10551055
CanType ty = getASTType();
10561056

10571057
// For storage with reference ownership, check the referent.
@@ -1065,7 +1065,8 @@ bool SILType::isEscapable() const {
10651065
if (auto boxTy = getAs<SILBoxType>()) {
10661066
auto fields = boxTy->getLayout()->getFields();
10671067
assert(fields.size() == 1);
1068-
ty = fields[0].getLoweredType();
1068+
ty = ::getSILBoxFieldLoweredType(function.getTypeExpansionContext(), boxTy,
1069+
function.getModule().Types, 0);
10691070
}
10701071

10711072
// TODO: Support ~Escapable in parameter packs.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: %target-sil-opt %s \
2+
// RUN: -o /dev/null \
3+
// RUN: -sil-verify-all \
4+
// RUN: -enable-experimental-feature NonescapableTypes \
5+
// RUN: -enable-experimental-feature NoncopyableGenerics \
6+
// RUN: -lifetime-dependence-diagnostics
7+
8+
// REQUIRES: asserts
9+
// REQUIRES: swift_in_compiler
10+
11+
sil_stage raw
12+
13+
// Test that SILType.isEscpable does not crash on a generic box when NoncopyableGenerics is enabled.
14+
sil shared [serialized] [ossa] @testLocalFunc : $@convention(thin) <T, U> (@guaranteed <τ_0_0> { var τ_0_0 } <U>) -> () {
15+
bb0(%1 : @closureCapture @guaranteed $<τ_0_0> { var τ_0_0 } <U>):
16+
%33 = tuple ()
17+
return %33 : $()
18+
}

0 commit comments

Comments
 (0)