Skip to content

Commit c4c0153

Browse files
authored
Merge pull request #72946 from atrick/60-fix-nonescapable-lowering
[6.0] Fix type lowering of ~Copyable and ~Escapable generics.
2 parents 4ed6ffe + f53d1b8 commit c4c0153

File tree

6 files changed

+334
-36
lines changed

6 files changed

+334
-36
lines changed

include/swift/SIL/AbstractionPattern.h

Lines changed: 3 additions & 0 deletions
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

Lines changed: 28 additions & 18 deletions
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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2441,7 +2441,9 @@ namespace {
24412441
return new (TC) MoveOnlyLoadableStructTypeLowering(
24422442
structType, properties, Expansion);
24432443
}
2444-
if (D->canBeEscapable() != TypeDecl::CanBeInvertible::Always) {
2444+
// Regardless of their member types, Nonescapable values have ownership
2445+
// for lifetime diagnostics.
2446+
if (!origType.isEscapable(structType)) {
24452447
properties.setNonTrivial();
24462448
}
24472449
return handleAggregateByProperties<LoadableStructTypeLowering>(structType,
@@ -2538,10 +2540,11 @@ namespace {
25382540
return new (TC)
25392541
MoveOnlyLoadableEnumTypeLowering(enumType, properties, Expansion);
25402542
}
2541-
2542-
assert(D->canBeEscapable() == TypeDecl::CanBeInvertible::Always
2543-
&& "missing typelowering case here!");
2544-
2543+
// Regardless of their member types, Nonescapable values have ownership
2544+
// for lifetime diagnostics.
2545+
if (!origType.isEscapable(enumType)) {
2546+
properties.setNonTrivial();
2547+
}
25452548
return handleAggregateByProperties<LoadableEnumTypeLowering>(enumType,
25462549
properties);
25472550
}

test/SIL/type_lowering_unit.sil

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

0 commit comments

Comments
 (0)