Skip to content

Commit 4710c43

Browse files
authored
Merge pull request #19992 from Azoy/sr-8811
[Sema] Disallow stored properties to have uninhabited types
2 parents f12c1c6 + 5dcf823 commit 4710c43

File tree

9 files changed

+68
-6
lines changed

9 files changed

+68
-6
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1367,6 +1367,15 @@ ERROR(pattern_binds_no_variables,none,
13671367
"variables",
13681368
(unsigned))
13691369

1370+
ERROR(pattern_no_uninhabited_type,none,
1371+
"%select{%select{variable|constant}0|stored property}1 %2 cannot have "
1372+
"enum type %3 with no cases",
1373+
(bool, bool, Identifier, Type))
1374+
ERROR(pattern_no_uninhabited_tuple_type,none,
1375+
"%select{%select{variable|constant}0|stored property}1 %2 cannot have "
1376+
"tuple type %3 containing enum with no cases",
1377+
(bool, bool, Identifier, Type))
1378+
13701379
ERROR(nscoding_unstable_mangled_name,none,
13711380
"%select{private|fileprivate|nested|local}0 class %1 has an "
13721381
"unstable name when archiving via 'NSCoding'",

lib/Sema/TypeCheckDecl.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2461,6 +2461,25 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
24612461
}
24622462
}
24632463

2464+
// Reject variable if it is a stored property with an uninhabited type
2465+
if (VD->hasStorage() &&
2466+
VD->getInterfaceType()->isStructurallyUninhabited()) {
2467+
auto uninhabitedTypeDiag = diag::pattern_no_uninhabited_type;
2468+
2469+
if (VD->getInterfaceType()->is<TupleType>()) {
2470+
uninhabitedTypeDiag = diag::pattern_no_uninhabited_tuple_type;
2471+
} else {
2472+
assert((VD->getInterfaceType()->is<EnumType>() ||
2473+
VD->getInterfaceType()->is<BoundGenericEnumType>()) &&
2474+
"unknown structurally uninhabited type");
2475+
}
2476+
2477+
TC.diagnose(VD->getLoc(), uninhabitedTypeDiag, VD->isLet(),
2478+
VD->isInstanceMember(), VD->getName(),
2479+
VD->getInterfaceType());
2480+
VD->markInvalid();
2481+
}
2482+
24642483
if (!checkOverrides(VD)) {
24652484
// If a property has an override attribute but does not override
24662485
// anything, complain.

test/IRGen/generic_enums.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ struct Bar<A1, A2> {
66
}
77

88
enum Foo<A>{
9+
case bar
910
}

test/Reflection/Inputs/TypeLowering.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,14 @@ public struct MetatypeStruct {
144144
public let abstractMetatype: MetadataHolder<BasicStruct.Type, BasicStruct>
145145
}
146146

147+
// We don't allow stored properties to have uninhabited types now, but make a
148+
// wrapper over one to continue testing this
147149
public enum EmptyEnum {}
148150

151+
public struct EmptyEnumWrapper<T> {
152+
public var value: T
153+
}
154+
149155
public enum NoPayloadEnum {
150156
case A
151157
case B
@@ -194,7 +200,7 @@ public enum MultiPayloadGenericDynamic<T, U> {
194200
}
195201

196202
public struct EnumStruct {
197-
public let empty: EmptyEnum
203+
public let empty: EmptyEnumWrapper<EmptyEnum>
198204
public let noPayload: NoPayloadEnum
199205
public let sillyNoPayload: SillyNoPayloadEnum
200206
public let singleton: SingletonEnum

test/Reflection/typeref_lowering.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -926,7 +926,9 @@
926926
// CHECK-64: (struct TypeLowering.EnumStruct)
927927
// CHECK-64-NEXT: (struct size=81 alignment=8 stride=88 num_extra_inhabitants=[[PTR_XI]]
928928
// CHECK-64-NEXT: (field name=empty offset=0
929-
// CHECK-64-NEXT: (no_payload_enum size=0 alignment=1 stride=1 num_extra_inhabitants=0))
929+
// CHECK-64-NEXT: (struct size=0 alignment=1 stride=1 num_extra_inhabitants=0
930+
// CHECK-64-NEXT: (field name=value offset=0
931+
// CHECK-64-NEXT: (no_payload_enum size=0 alignment=1 stride=1 num_extra_inhabitants=0))))
930932
// CHECK-64-NEXT: (field name=noPayload offset=0
931933
// CHECK-64-NEXT: (no_payload_enum size=1 alignment=1 stride=1 num_extra_inhabitants=0))
932934
// CHECK-64-NEXT: (field name=sillyNoPayload offset=1

test/attr/attr_noreturn.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ func noReturn3(_: Int)
3434
// expected-error@-2 {{'@noreturn' has been removed; functions that never return should have a return type of 'Never' instead}}{{1-11=}}{{53-56=Never}}
3535

3636
// Test that error recovery gives us the 'Never' return type
37-
let x: Never = noReturn1(0) // No error
37+
let x: Never = noReturn1(0)
38+
// expected-error@-1 {{constant 'x' cannot have enum type 'Never' with no cases}}
3839

3940
// @noreturn in function type declarations
4041
let valueNoReturn: @noreturn () -> ()

test/attr/attr_objc.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -941,11 +941,12 @@ class infer_instanceVar1 {
941941
// expected-note@-2 {{Swift structs cannot be represented in Objective-C}}
942942

943943
var var_PlainEnum: PlainEnum
944-
// CHECK-LABEL: {{^}} var var_PlainEnum: PlainEnum
944+
// expected-error@-1 {{stored property 'var_PlainEnum' cannot have enum type 'PlainEnum' with no cases}}
945945

946946
@objc var var_PlainEnum_: PlainEnum
947947
// expected-error@-1 {{property cannot be marked @objc because its type cannot be represented in Objective-C}}
948948
// expected-note@-2 {{non-'@objc' enums cannot be represented in Objective-C}}
949+
// expected-error@-3 {{stored property 'var_PlainEnum_' cannot have enum type 'PlainEnum' with no cases}}
949950

950951
var var_PlainProtocol: PlainProtocol
951952
// CHECK-LABEL: {{^}} var var_PlainProtocol: PlainProtocol
@@ -1271,6 +1272,7 @@ class infer_instanceVar1 {
12711272
// expected-error@-1 {{'unowned' may only be applied to class and class-bound protocol types, not 'PlainStruct'}}
12721273
unowned var var_Unowned_bad3: PlainEnum
12731274
// expected-error@-1 {{'unowned' may only be applied to class and class-bound protocol types, not 'PlainEnum'}}
1275+
// expected-error@-2 {{stored property 'var_Unowned_bad3' cannot have enum type 'PlainEnum' with no cases}}
12741276
unowned var var_Unowned_bad4: String
12751277
// expected-error@-1 {{'unowned' may only be applied to class and class-bound protocol types, not 'String'}}
12761278
// CHECK-NOT: @objc{{.*}}Unowned_fail

test/decl/var/properties.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,3 +1267,25 @@ class WeakFixItTest {
12671267
// expected-error @+1 {{'weak' variable should have optional type '(WFI_P1 & WFI_P2)?'}} {{18-18=(}} {{33-33=)?}}
12681268
weak var bar : WFI_P1 & WFI_P2
12691269
}
1270+
1271+
// SR-8811
1272+
// Stored properties cannot have uninhabited types
1273+
1274+
struct SR8811 {
1275+
var x: Never // expected-error {{stored property 'x' cannot have enum type 'Never' with no cases}}
1276+
1277+
var y: (Int, Never, Bool) // expected-error {{stored property 'y' cannot have tuple type '(Int, Never, Bool)' containing enum with no cases}}
1278+
}
1279+
1280+
let sr8811x: Never // expected-error {{constant 'sr8811x' cannot have enum type 'Never' with no cases}}
1281+
1282+
var sr8811y: (Int, Never) // expected-error {{variable 'sr8811y' cannot have tuple type '(Int, Never)' containing enum with no cases}}
1283+
1284+
// Ok
1285+
var sr8811z: Never {
1286+
return fatalError()
1287+
}
1288+
1289+
enum SR8811EmptyGenericEnum<A> {}
1290+
1291+
let sr8811z: SR8811EmptyGenericEnum<Int> // expected-error {{constant 'sr8811z' cannot have enum type 'SR8811EmptyGenericEnum<Int>' with no cases}}

test/expr/expressions.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -584,9 +584,9 @@ func conversionTest(_ a: inout Double, b: inout Int) {
584584
var pi_f3 = float.init(getPi()) // expected-error {{ambiguous use of 'init(_:)'}}
585585
var pi_f4 = float.init(pi_f)
586586

587-
var e = Empty(f)
587+
var e = Empty(f) // expected-error {{variable 'e' cannot have enum type 'Empty' with no cases}}
588588
var e2 = Empty(d) // expected-error{{cannot convert value of type 'Double' to expected argument type 'Float'}}
589-
var e3 = Empty(Float(d))
589+
var e3 = Empty(Float(d)) // expected-error {{variable 'e3' cannot have enum type 'Empty' with no cases}}
590590
}
591591

592592
struct Rule { // expected-note {{'init(target:dependencies:)' declared here}}

0 commit comments

Comments
 (0)