Skip to content

Commit 4d8c842

Browse files
Merge pull request #71613 from nate-chandler/bitwise-copyable/no-infer-public
[BitwiseCopyable] Don't ever infer for public.
2 parents 633051e + 427d9cb commit 4d8c842

8 files changed

+171
-16
lines changed

lib/SIL/IR/TypeLowering.cpp

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ llvm::cl::opt<bool> TypeLoweringForceOpaqueValueLowering(
5454
llvm::cl::desc("Force TypeLowering to behave as if building with opaque "
5555
"values enabled"));
5656

57+
llvm::cl::opt<bool> TypeLoweringDisableVerification(
58+
"type-lowering-disable-verification", llvm::cl::init(false),
59+
llvm::cl::desc("Disable the asserts-only verification of lowerings"));
60+
5761
namespace {
5862
/// A CRTP type visitor for deciding whether the metatype for a type
5963
/// is a singleton type, i.e. whether there can only ever be one
@@ -2945,6 +2949,9 @@ void TypeConverter::verifyLowering(const TypeLowering &lowering,
29452949
AbstractionPattern origType,
29462950
CanType substType,
29472951
TypeExpansionContext forExpansion) {
2952+
if (TypeLoweringDisableVerification) {
2953+
return;
2954+
}
29482955
verifyLexicalLowering(lowering, origType, substType, forExpansion);
29492956
verifyTrivialLowering(lowering, origType, substType, forExpansion);
29502957
}
@@ -3049,7 +3056,7 @@ void TypeConverter::verifyTrivialLowering(const TypeLowering &lowering,
30493056

30503057
if (lowering.isTrivial() && !conformance) {
30513058
// A trivial type can lack a conformance in a few cases:
3052-
// (1) containing or being a resilient type
3059+
// (1) containing or being a public, non-frozen type
30533060
// (2) containing or being a generic type which doesn't conform
30543061
// unconditionally but in this particular instantiation is trivial
30553062
// (3) being a special type that's not worth forming a conformance for
@@ -3064,6 +3071,7 @@ void TypeConverter::verifyTrivialLowering(const TypeLowering &lowering,
30643071
// unowned(unsafe) var o: AnyObject
30653072
// }
30663073
// (5) being defined in a different module
3074+
// (6) being defined in a module built from interface
30673075
bool hasNoNonconformingNode = visitAggregateLeaves(
30683076
origType, substType, forExpansion,
30693077
/*isLeafAggregate=*/
@@ -3081,12 +3089,22 @@ void TypeConverter::verifyTrivialLowering(const TypeLowering &lowering,
30813089
return true;
30823090
}
30833091

3084-
// Resilient trivial types may not conform (case (1)).
3085-
if (nominal->isResilient())
3092+
// Public, non-frozen trivial types may not conform (case (1)).
3093+
if (nominal
3094+
->getFormalAccessScope(/*useDC=*/nullptr,
3095+
/*treatUsableFromInlineAsPublic=*/true)
3096+
.isPublic())
30863097
return true;
30873098

3099+
auto *module = nominal->getModuleContext();
3100+
3101+
// Types in modules built from interfaces may not conform (case (6)).
3102+
if (module && module->isBuiltFromInterface()) {
3103+
return false;
3104+
}
3105+
30883106
// Trivial types from other modules may not conform (case (5)).
3089-
return nominal->getModuleContext() != &M;
3107+
return module != &M;
30903108
},
30913109
/*visit=*/
30923110
[&](auto ty, auto origTy, auto *field, auto index) -> bool {
@@ -3141,12 +3159,22 @@ void TypeConverter::verifyTrivialLowering(const TypeLowering &lowering,
31413159
return false;
31423160
}
31433161

3144-
// Resilient trivial types may not conform (case (1)).
3145-
if (nominal->isResilient())
3162+
// Public, non-frozen trivial types may not conform (case (1)).
3163+
if (nominal
3164+
->getFormalAccessScope(/*useDC=*/nullptr,
3165+
/*treatUsableFromInlineAsPublic=*/true)
3166+
.isPublic())
3167+
return false;
3168+
3169+
auto *module = nominal->getModuleContext();
3170+
3171+
// Types in modules built from interfaces may not conform (case (6)).
3172+
if (module && module->isBuiltFromInterface()) {
31463173
return false;
3174+
}
31473175

31483176
// Trivial types from other modules may not conform (case (5)).
3149-
return nominal->getModuleContext() == &M;
3177+
return module == &M;
31503178
});
31513179
if (hasNoNonconformingNode) {
31523180
llvm::errs() << "Trivial type without a BitwiseCopyable conformance!?:\n"
@@ -3159,10 +3187,19 @@ void TypeConverter::verifyTrivialLowering(const TypeLowering &lowering,
31593187
if (!lowering.isTrivial() && conformance) {
31603188
// A non-trivial type can have a conformance in one case:
31613189
// (1) contains a conforming archetype
3190+
// (2) is resilient with minimal expansion
31623191
bool hasNoConformingArchetypeNode = visitAggregateLeaves(
31633192
origType, substType, forExpansion,
31643193
/*isLeaf=*/
31653194
[&](auto ty, auto origTy, auto *field, auto index) -> bool {
3195+
// A resilient type that's with minimal expansion may be non-trivial
3196+
// but still conform (case (2)).
3197+
auto *nominal = ty.getAnyNominal();
3198+
if (nominal && nominal->isResilient() &&
3199+
forExpansion.getResilienceExpansion() ==
3200+
ResilienceExpansion::Minimal) {
3201+
return true;
3202+
}
31663203
// Walk into every aggregate.
31673204
return false;
31683205
},
@@ -3173,7 +3210,16 @@ void TypeConverter::verifyTrivialLowering(const TypeLowering &lowering,
31733210
"leaf of non-trivial BitwiseCopyable type that doesn't "
31743211
"conform to BitwiseCopyable!?");
31753212

3176-
// An archetype may conform but be non-trivial (case (2)).
3213+
// A resilient type that's with minimal expansion may be non-trivial
3214+
// but still conform (case (2)).
3215+
auto *nominal = ty.getAnyNominal();
3216+
if (nominal && nominal->isResilient() &&
3217+
forExpansion.getResilienceExpansion() ==
3218+
ResilienceExpansion::Minimal) {
3219+
return false;
3220+
}
3221+
3222+
// An archetype may conform but be non-trivial (case (1)).
31773223
if (origTy.isTypeParameter())
31783224
return false;
31793225

lib/Sema/TypeCheckBitwise.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,7 @@ getImplicitCheckForNominal(NominalTypeDecl *nominal) {
5757
if (!nominal
5858
->getFormalAccessScope(
5959
/*useDC=*/nullptr, /*treatUsableFromInlineAsPublic=*/true)
60-
.isPublic() ||
61-
!nominal->isResilient())
60+
.isPublic())
6261
return {BitwiseCopyableCheck::Implicit};
6362

6463
if (nominal->hasClangNode() ||
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
// RUN: %target-swift-frontend \
5+
// RUN: %t/Library.swift \
6+
// RUN: -emit-module \
7+
// RUN: -enable-library-evolution \
8+
// RUN: -enable-experimental-feature BitwiseCopyable \
9+
// RUN: -module-name Library \
10+
// RUN: -emit-module-path %t/Library.swiftmodule
11+
12+
// RUN: %target-swift-frontend \
13+
// RUN: %t/Downstream.swift \
14+
// RUN: -typecheck -verify \
15+
// RUN: -debug-diagnostic-names \
16+
// RUN: -enable-experimental-feature BitwiseCopyable \
17+
// RUN: -I %t
18+
19+
//--- Library.swift
20+
public enum Oopsional<T> {
21+
case someone(T)
22+
case nobody
23+
}
24+
25+
@frozen public enum Woopsional<T> {
26+
case somebody(T)
27+
case noone
28+
}
29+
30+
public struct Integer {
31+
var value: Int
32+
}
33+
34+
//--- Downstream.swift
35+
import Library
36+
37+
func take<T: _BitwiseCopyable>(_ t: T) {}
38+
39+
struct S_Explicit_With_Oopsional<T> : _BitwiseCopyable {
40+
var o: Oopsional<T> // expected-error{{non_bitwise_copyable_type_member}}
41+
}
42+
43+
func passOopsional<T>(_ t: Oopsional<T>) { take(t) } // expected-error {{type_does_not_conform_decl_owner}}
44+
// expected-note@-7 {{where_requirement_failure_one_subst}}
45+
46+
47+
struct S_Explicit_With_Woopsional<T> : _BitwiseCopyable {
48+
var o: Woopsional<T> // expected-error{{non_bitwise_copyable_type_member}}
49+
}
50+
51+
func passWoopsional<T>(_ t: Woopsional<T>) { take(t) } // expected-error {{type_does_not_conform_decl_owner}}
52+
// expected-note@-15 {{where_requirement_failure_one_subst}}
53+
54+
extension Integer : @retroactive _BitwiseCopyable {} // expected-error {{bitwise_copyable_outside_module}}
55+

test/SILGen/bitwise_copyable.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ enum Context<T> {
4040

4141
func doit() -> Context<Int>.Here { .init(t: 0) }
4242

43-
public enum E {
43+
public enum E : _BitwiseCopyable {
4444
case a
4545
}
4646

test/Sema/bitwise_copyable.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ struct S_Explicit_With_Function_C : _BitwiseCopyable {
6262
public struct S_Public {}
6363

6464
struct S_Explicit_With_S_Public : _BitwiseCopyable {
65-
var s: S_Public
65+
var s: S_Public // expected-error {{non_bitwise_copyable_type_member}}
66+
// expected-note@-4 {{add_nominal_bitwise_copyable_conformance}}
6667
}
6768

6869
struct S_Explicit_With_Generic<T> : _BitwiseCopyable {

test/Sema/bitwise_copyable_2.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,13 @@ indirect enum E_Explicit_Indirect : _BitwiseCopyable { // expected-error {{non_b
2525
enum E_Explicit_Indirect_Case : _BitwiseCopyable { // expected-error {{non_bitwise_copyable_type_indirect_enum_element}}
2626
indirect case s(S) // expected-note {{note_non_bitwise_copyable_type_indirect_enum_element}}
2727
}
28+
29+
func take<T : _BitwiseCopyable>(_ t: T) {}
30+
31+
// public (effectively) => !conforms
32+
@usableFromInline internal struct InternalUsableStruct {
33+
public var int: Int
34+
}
35+
36+
func passInternalUsableStruct(_ s: InternalUsableStruct) { take(s) } // expected-error{{type_does_not_conform_decl_owner}}
37+
// expected-note@-8{{where_requirement_failure_one_subst}}

test/Sema/bitwise_copyable_nonresilient.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,17 @@ import Library
3232
func take<T: _BitwiseCopyable>(_ t: T) {}
3333

3434
struct S_Explicit_With_Oopsional<T> : _BitwiseCopyable {
35-
var o: Oopsional<T>
35+
var o: Oopsional<T> // expected-error{{non_bitwise_copyable_type_member}}
3636
}
3737

38-
func passOopsional<T>(_ t: Oopsional<T>) { take(t) }
38+
func passOopsional<T>(_ t: Oopsional<T>) { take(t) } // expected-error{{type_does_not_conform_decl_owner}}
39+
// expected-note@-7{{where_requirement_failure_one_subst}}
3940

4041

4142
struct S_Explicit_With_Woopsional<T> : _BitwiseCopyable {
42-
var o: Woopsional<T>
43+
var o: Woopsional<T> // expected-error{{non_bitwise_copyable_type_member}}
4344
}
4445

45-
func passWoopsional<T>(_ t: Woopsional<T>) { take(t) }
46+
func passWoopsional<T>(_ t: Woopsional<T>) { take(t) } // expected-error{{type_does_not_conform_decl_owner}}
47+
// expected-note@-15{{where_requirement_failure_one_subst}}
4648

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
// RUN: %target-swift-frontend \
5+
// RUN: %t/Library.swift \
6+
// RUN: -emit-module \
7+
// RUN: -package-name Package \
8+
// RUN: -enable-library-evolution \
9+
// RUN: -enable-experimental-feature BitwiseCopyable \
10+
// RUN: -module-name Library \
11+
// RUN: -emit-module-path %t/Library.swiftmodule \
12+
// RUN: -emit-module-interface-path %t/Library.swiftinterface
13+
14+
// RUN: %target-swift-frontend \
15+
// RUN: %t/Downstream.swift \
16+
// RUN: -typecheck -verify \
17+
// RUN: -package-name Package \
18+
// RUN: -debug-diagnostic-names \
19+
// RUN: -enable-experimental-feature BitwiseCopyable \
20+
// RUN: -I %t
21+
22+
//--- Library.swift
23+
24+
// !public => conforms
25+
package struct PackageStruct {
26+
package var int: Int
27+
}
28+
29+
// Public => !conforms
30+
public struct PublicStruct {
31+
public var int: Int
32+
}
33+
34+
//--- Downstream.swift
35+
import Library
36+
37+
func take<T : _BitwiseCopyable>(_ t: T) {}
38+
39+
func passPackageStruct(_ s: PackageStruct) { take(s) }
40+
41+
func passPublicStruct(_ s: PublicStruct) { take(s) } // expected-error{{type_does_not_conform_decl_owner}}
42+
// expected-note@-5{{where_requirement_failure_one_subst}}

0 commit comments

Comments
 (0)