Skip to content

Commit 38b78ed

Browse files
authored
Merge pull request #72866 from atrick/fix-nonescapable-lowering
Fix type lowering of ~Copyable and ~Escapable generics.
2 parents f0d3ca8 + 4f0680c commit 38b78ed

File tree

6 files changed

+327
-35
lines changed

6 files changed

+327
-35
lines changed

include/swift/SIL/AbstractionPattern.h

+3
Original file line numberDiff line numberDiff line change
@@ -1014,7 +1014,10 @@ class AbstractionPattern {
10141014

10151015
bool requiresClass() const;
10161016
LayoutConstraint getLayoutConstraint() const;
1017+
bool conformsToKnownProtocol(
1018+
CanType substTy, KnownProtocolKind protocolKind) const;
10171019
bool isNoncopyable(CanType substTy) const;
1020+
bool isEscapable(CanType substTy) const;
10181021

10191022
/// Return the Swift type which provides structure for this
10201023
/// abstraction pattern.

lib/SIL/IR/AbstractionPattern.cpp

+28-18
Original file line numberDiff line numberDiff line change
@@ -284,62 +284,64 @@ LayoutConstraint AbstractionPattern::getLayoutConstraint() const {
284284
}
285285
}
286286

287-
bool AbstractionPattern::isNoncopyable(CanType substTy) const {
288-
auto copyable
289-
= substTy->getASTContext().getProtocol(KnownProtocolKind::Copyable);
287+
bool AbstractionPattern::conformsToKnownProtocol(
288+
CanType substTy, KnownProtocolKind protocolKind) const {
289+
auto suppressible
290+
= substTy->getASTContext().getProtocol(protocolKind);
290291

291-
auto isDefinitelyCopyable = [&](CanType t) -> bool {
292-
auto result = copyable->getParentModule()
293-
->checkConformanceWithoutContext(substTy, copyable,
292+
auto definitelyConforms = [&](CanType t) -> bool {
293+
auto result = suppressible->getParentModule()
294+
->checkConformanceWithoutContext(t, suppressible,
294295
/*allowMissing=*/false);
295296
return result.has_value() && !result.value().isInvalid();
296297
};
297298

298299
// If the substituted type definitely conforms, that's authoritative.
299-
if (isDefinitelyCopyable(substTy)) {
300-
return false;
300+
if (definitelyConforms(substTy)) {
301+
return true;
301302
}
302303

303304
// If the substituted type is fully concrete, that's it. If there are unbound
304305
// type variables in the type, then we may have to account for the upper
305306
// abstraction bound from the abstraction pattern.
306307
if (!substTy->hasTypeParameter()) {
307-
return true;
308+
return false;
308309
}
309310

310311
switch (getKind()) {
311312
case Kind::Opaque: {
312313
// The abstraction pattern doesn't provide any more specific bounds.
313-
return true;
314+
return false;
314315
}
315316
case Kind::Type:
316317
case Kind::Discard:
317318
case Kind::ClangType: {
318319
// See whether the abstraction pattern's context gives us an upper bound
319-
// that ensures the type is copyable.
320+
// that ensures the type conforms.
320321
auto type = getType();
321322
if (hasGenericSignature() && getType()->hasTypeParameter()) {
322323
type = GenericEnvironment::mapTypeIntoContext(
323324
getGenericSignature().getGenericEnvironment(), getType())
324325
->getReducedType(getGenericSignature());
325326
}
326327

327-
return !isDefinitelyCopyable(type);
328+
return definitelyConforms(type);
328329
}
329330
case Kind::Tuple: {
330-
// A tuple is noncopyable if any element is.
331+
// A tuple conforms if all elements do.
331332
if (doesTupleVanish()) {
332333
return getVanishingTupleElementPatternType().value()
333-
.isNoncopyable(substTy);
334+
.conformsToKnownProtocol(substTy, protocolKind);
334335
}
335336
auto substTupleTy = cast<TupleType>(substTy);
336337

337338
for (unsigned i = 0, e = getNumTupleElements(); i < e; ++i) {
338-
if (getTupleElementType(i).isNoncopyable(substTupleTy.getElementType(i))){
339-
return true;
339+
if (!getTupleElementType(i).conformsToKnownProtocol(
340+
substTupleTy.getElementType(i), protocolKind)) {
341+
return false;
340342
}
341343
}
342-
return false;
344+
return true;
343345
}
344346
// Functions are, at least for now, always copyable.
345347
case Kind::CurriedObjCMethodType:
@@ -354,13 +356,21 @@ bool AbstractionPattern::isNoncopyable(CanType substTy) const {
354356
case Kind::PartialCurriedCXXMethodType:
355357
case Kind::OpaqueFunction:
356358
case Kind::OpaqueDerivativeFunction:
357-
return false;
359+
return true;
358360

359361
case Kind::Invalid:
360362
llvm_unreachable("asking invalid abstraction pattern");
361363
}
362364
}
363365

366+
bool AbstractionPattern::isNoncopyable(CanType substTy) const {
367+
return !conformsToKnownProtocol(substTy, KnownProtocolKind::Copyable);
368+
}
369+
370+
bool AbstractionPattern::isEscapable(CanType substTy) const {
371+
return conformsToKnownProtocol(substTy, KnownProtocolKind::Escapable);
372+
}
373+
364374
bool AbstractionPattern::matchesTuple(CanType substType) const {
365375
switch (getKind()) {
366376
case Kind::Invalid:

lib/SIL/IR/TypeLowering.cpp

+8-5
Original file line numberDiff line numberDiff line change
@@ -2448,7 +2448,9 @@ namespace {
24482448
return new (TC) MoveOnlyLoadableStructTypeLowering(
24492449
structType, properties, Expansion);
24502450
}
2451-
if (D->canBeEscapable() != TypeDecl::CanBeInvertible::Always) {
2451+
// Regardless of their member types, Nonescapable values have ownership
2452+
// for lifetime diagnostics.
2453+
if (!origType.isEscapable(structType)) {
24522454
properties.setNonTrivial();
24532455
}
24542456
return handleAggregateByProperties<LoadableStructTypeLowering>(structType,
@@ -2545,10 +2547,11 @@ namespace {
25452547
return new (TC)
25462548
MoveOnlyLoadableEnumTypeLowering(enumType, properties, Expansion);
25472549
}
2548-
2549-
assert(D->canBeEscapable() == TypeDecl::CanBeInvertible::Always
2550-
&& "missing typelowering case here!");
2551-
2550+
// Regardless of their member types, Nonescapable values have ownership
2551+
// for lifetime diagnostics.
2552+
if (!origType.isEscapable(enumType)) {
2553+
properties.setNonTrivial();
2554+
}
25522555
return handleAggregateByProperties<LoadableEnumTypeLowering>(enumType,
25532556
properties);
25542557
}

test/SIL/type_lowering_unit.sil

+203-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
// RUN: %target-sil-opt -test-runner %s -o /dev/null 2>&1 | %FileCheck %s
1+
// RUN: %target-sil-opt -test-runner \
2+
// RUN: -enable-experimental-feature NoncopyableGenerics -enable-experimental-feature NonescapableTypes \
3+
// RUN: -enable-experimental-feature BitwiseCopyable \
4+
// RUN: %s -o /dev/null 2>&1 | %FileCheck %s
25

36
sil_stage raw
47

@@ -7,6 +10,8 @@ import Swift
710

811
struct S : ~Copyable {}
912

13+
struct SCopyable {}
14+
1015
// CHECK-LABEL: begin {{.*}} print-type-lowering with: @argument[0]
1116
// CHECK: isLexical: true
1217
// CHECK-LABEL: end {{.*}} print-type-lowering with: @argument[0]
@@ -106,3 +111,200 @@ entry(%addr : $*Builtin.RawPointer):
106111
specify_test "print_ast_type_lowering %instance"
107112
return undef : $()
108113
}
114+
115+
struct GSNC<T: ~Copyable>: ~Copyable {
116+
var x: T
117+
}
118+
119+
extension GSNC: Copyable where T: Copyable {}
120+
121+
struct GSNE<T: ~Escapable>: ~Escapable {
122+
var x: T
123+
}
124+
125+
extension GSNE: Escapable where T: Escapable {}
126+
127+
enum GENC<T: ~Copyable>: ~Copyable {
128+
case x(T)
129+
case knoll
130+
}
131+
132+
enum GENE<T: ~Escapable>: ~Escapable {
133+
case x(T)
134+
case knoll
135+
}
136+
137+
extension GENC: Copyable where T: Copyable {}
138+
139+
extension GENE: Escapable where T: Escapable {}
140+
141+
// TODO: We should have 'isTrivial: true' for the following four tests: gsnc_argument, gsne_argument, genc_argument,
142+
// gene_argument. This requires fixing Typelowering visitAnyStructType and visitAnyEnumType to apply the current
143+
// abstraction pattern for each stored property that refers to an archetype. Similar how TypeLowering handles the
144+
// aggregate type by calling AbstractionPattern::conformsToKnownProtocol.
145+
//
146+
// CHECK-LABEL: begin running test 1 of 1 on gsnc_argument: print-type-lowering with: @argument[0]
147+
// CHECK: Type Lowering for lowered type: $*GSNC<T>.
148+
// CHECK: isTrivial: false.
149+
// CHECK-LABEL: end running test 1 of 1 on gsnc_argument: print-type-lowering with: @argument[0]
150+
sil [ossa] @gsnc_argument : $@convention(thin) <T: _BitwiseCopyable> (@in_guaranteed GSNC<T>) -> () {
151+
bb0(%0 : $*GSNC<T>):
152+
specify_test "print-type-lowering @argument[0]"
153+
%retval = tuple ()
154+
return %retval : $()
155+
}
156+
157+
// CHECK-LABEL: begin running test 1 of 1 on gsne_argument: print-type-lowering with: @argument[0]
158+
// CHECK: isTrivial: false.
159+
// CHECK-LABEL: end running test 1 of 1 on gsne_argument: print-type-lowering with: @argument[0]
160+
sil [ossa] @gsne_argument : $@convention(thin) <T: _BitwiseCopyable> (@in_guaranteed GSNE<T>) -> () {
161+
bb0(%0 : $*GSNE<T>):
162+
specify_test "print-type-lowering @argument[0]"
163+
%retval = tuple ()
164+
return %retval : $()
165+
}
166+
167+
// CHECK-LABEL: begin running test 1 of 1 on genc_argument: print-type-lowering with: @argument[0]
168+
// CHECK: isTrivial: false.
169+
// CHECK-LABEL: end running test 1 of 1 on genc_argument: print-type-lowering with: @argument[0]
170+
sil [ossa] @genc_argument : $@convention(thin) <T: _BitwiseCopyable> (@in_guaranteed GENC<T>) -> () {
171+
bb0(%0 : $*GENC<T>):
172+
specify_test "print-type-lowering @argument[0]"
173+
%retval = tuple ()
174+
return %retval : $()
175+
}
176+
177+
// CHECK-LABEL: begin running test 1 of 1 on gene_argument: print-type-lowering with: @argument[0]
178+
// CHECK: isTrivial: false.
179+
// CHECK-LABEL: end running test 1 of 1 on gene_argument: print-type-lowering with: @argument[0]
180+
sil [ossa] @gene_argument : $@convention(thin) <T: _BitwiseCopyable> (@in_guaranteed GENE<T>) -> () {
181+
bb0(%0 : $*GENE<T>):
182+
specify_test "print-type-lowering @argument[0]"
183+
%retval = tuple ()
184+
return %retval : $()
185+
}
186+
187+
struct Bitwise<T: _BitwiseCopyable>: _BitwiseCopyable {
188+
var x: T
189+
}
190+
191+
// TODO: This should return 'isTrivial: true'. This is particularly inexcusable because the 'Bitwise' cannot be
192+
// nontrivial over any 'T', *and* the declaration itself is declared BitwiseCopyable.
193+
//
194+
// CHECK-LABEL: begin running test 1 of 1 on bitwise_argument: print-type-lowering with: @argument[0]
195+
// CHECK: isTrivial: false.
196+
// CHECK-LABEL: end running test 1 of 1 on bitwise_argument: print-type-lowering with: @argument[0]
197+
sil [ossa] @bitwise_argument : $@convention(thin) <T: _BitwiseCopyable> (@in_guaranteed Bitwise<T>) -> () {
198+
bb0(%0 : $*Bitwise<T>):
199+
specify_test "print-type-lowering @argument[0]"
200+
%retval = tuple ()
201+
return %retval : $()
202+
}
203+
204+
// CHECK-LABEL: begin running test 1 of 1 on gsnc_specialized_argument: print-type-lowering with: @argument[0]
205+
// CHECK: isTrivial: true.
206+
// CHECK-LABEL: end running test 1 of 1 on gsnc_specialized_argument: print-type-lowering with: @argument[0]
207+
sil [ossa] @gsnc_specialized_argument : $@convention(thin) (@in_guaranteed GSNC<SCopyable>) -> () {
208+
bb0(%0 : $*GSNC<SCopyable>):
209+
specify_test "print-type-lowering @argument[0]"
210+
%retval = tuple ()
211+
return %retval : $()
212+
}
213+
214+
// CHECK-LABEL: begin running test 1 of 1 on gsne_specialized_argument: print-type-lowering with: @argument[0]
215+
// CHECK: isTrivial: true.
216+
// CHECK-LABEL: end running test 1 of 1 on gsne_specialized_argument: print-type-lowering with: @argument[0]
217+
sil [ossa] @gsne_specialized_argument : $@convention(thin) (@in_guaranteed GSNE<SCopyable>) -> () {
218+
bb0(%0 : $*GSNE<SCopyable>):
219+
specify_test "print-type-lowering @argument[0]"
220+
%retval = tuple ()
221+
return %retval : $()
222+
}
223+
224+
// CHECK-LABEL: begin running test 1 of 1 on genc_specialized_argument: print-type-lowering with: @argument[0]
225+
// CHECK: isTrivial: true.
226+
// CHECK-LABEL: end running test 1 of 1 on genc_specialized_argument: print-type-lowering with: @argument[0]
227+
sil [ossa] @genc_specialized_argument : $@convention(thin) (@in_guaranteed GENC<SCopyable>) -> () {
228+
bb0(%0 : $*GENC<SCopyable>):
229+
specify_test "print-type-lowering @argument[0]"
230+
%retval = tuple ()
231+
return %retval : $()
232+
}
233+
234+
// CHECK-LABEL: begin running test 1 of 1 on gene_specialized_argument: print-type-lowering with: @argument[0]
235+
// CHECK: isTrivial: true.
236+
// CHECK-LABEL: end running test 1 of 1 on gene_specialized_argument: print-type-lowering with: @argument[0]
237+
sil [ossa] @gene_specialized_argument : $@convention(thin) (@in_guaranteed GENE<SCopyable>) -> () {
238+
bb0(%0 : $*GENE<SCopyable>):
239+
specify_test "print-type-lowering @argument[0]"
240+
%retval = tuple ()
241+
return %retval : $()
242+
}
243+
244+
struct GSNCInt<T: ~Copyable>: ~Copyable {
245+
var x: Int
246+
}
247+
248+
extension GSNCInt: Copyable where T: Copyable {}
249+
250+
struct GSNEInt<T: ~Escapable>: ~Escapable {
251+
var x: Int
252+
@_unsafeNonescapableResult
253+
init() { x = 0 }
254+
}
255+
256+
extension GSNEInt: Escapable where T: Escapable {}
257+
258+
enum GENCInt<T: ~Copyable>: ~Copyable {
259+
case x(Int)
260+
case knoll
261+
}
262+
263+
enum GENEInt<T: ~Escapable>: ~Escapable {
264+
case x(Int)
265+
case knoll
266+
}
267+
268+
extension GENCInt: Copyable where T: Copyable {}
269+
270+
extension GENEInt: Escapable where T: Escapable {}
271+
272+
// CHECK-LABEL: begin running test 1 of 1 on gsncint_argument: print-type-lowering with: @argument[0]
273+
// CHECK: isTrivial: true.
274+
// CHECK-LABEL: end running test 1 of 1 on gsncint_argument: print-type-lowering with: @argument[0]
275+
sil [ossa] @gsncint_argument : $@convention(thin) <T: _BitwiseCopyable> (@in_guaranteed GSNCInt<T>) -> () {
276+
bb0(%0 : $*GSNCInt<T>):
277+
specify_test "print-type-lowering @argument[0]"
278+
%retval = tuple ()
279+
return %retval : $()
280+
}
281+
282+
// CHECK-LABEL: begin running test 1 of 1 on gsneint_argument: print-type-lowering with: @argument[0]
283+
// CHECK: isTrivial: true.
284+
// CHECK-LABEL: end running test 1 of 1 on gsneint_argument: print-type-lowering with: @argument[0]
285+
sil [ossa] @gsneint_argument : $@convention(thin) <T: _BitwiseCopyable> (@in_guaranteed GSNEInt<T>) -> () {
286+
bb0(%0 : $*GSNEInt<T>):
287+
specify_test "print-type-lowering @argument[0]"
288+
%retval = tuple ()
289+
return %retval : $()
290+
}
291+
292+
// CHECK-LABEL: begin running test 1 of 1 on gencint_argument: print-type-lowering with: @argument[0]
293+
// CHECK: isTrivial: true.
294+
// CHECK-LABEL: end running test 1 of 1 on gencint_argument: print-type-lowering with: @argument[0]
295+
sil [ossa] @gencint_argument : $@convention(thin) <T: _BitwiseCopyable> (@in_guaranteed GENCInt<T>) -> () {
296+
bb0(%0 : $*GENCInt<T>):
297+
specify_test "print-type-lowering @argument[0]"
298+
%retval = tuple ()
299+
return %retval : $()
300+
}
301+
302+
// CHECK-LABEL: begin running test 1 of 1 on geneint_argument: print-type-lowering with: @argument[0]
303+
// CHECK: isTrivial: true.
304+
// CHECK-LABEL: end running test 1 of 1 on geneint_argument: print-type-lowering with: @argument[0]
305+
sil [ossa] @geneint_argument : $@convention(thin) <T: _BitwiseCopyable> (@in_guaranteed GENEInt<T>) -> () {
306+
bb0(%0 : $*GENEInt<T>):
307+
specify_test "print-type-lowering @argument[0]"
308+
%retval = tuple ()
309+
return %retval : $()
310+
}

0 commit comments

Comments
 (0)