From 7991aecfce7c5c015da90c441869977d9a1cac20 Mon Sep 17 00:00:00 2001 From: Azoy Date: Mon, 22 Oct 2018 19:03:47 -0500 Subject: [PATCH 1/5] Disallow stored properties to have uninhabited types Reword comment Add tuple test case --- include/swift/AST/DiagnosticsSema.def | 4 ++++ lib/Sema/TypeCheckDecl.cpp | 9 +++++++++ test/decl/var/properties.swift | 9 +++++++++ 3 files changed, 22 insertions(+) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 3765b344febcc..24f91e0d195b6 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1367,6 +1367,10 @@ ERROR(pattern_binds_no_variables,none, "variables", (unsigned)) +ERROR(stored_property_no_uninhabited_type,none, + "stored property %0 cannot have uninhabited type %1", + (Identifier, Type)) + ERROR(nscoding_unstable_mangled_name,none, "%select{private|fileprivate|nested|local}0 class %1 has an " "unstable name when archiving via 'NSCoding'", diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index f993087abe611..729557c9705a0 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2461,6 +2461,15 @@ class DeclChecker : public DeclVisitor { } } + // Reject variable if it is a stored property with a structurally + // uninhabited type + if (VD->isInstanceMember() && VD->hasStorage() && + VD->getInterfaceType()->isStructurallyUninhabited()) { + TC.diagnose(VD->getLoc(), diag::stored_property_no_uninhabited_type, + VD->getName(), VD->getInterfaceType()); + VD->markInvalid(); + } + if (!checkOverrides(VD)) { // If a property has an override attribute but does not override // anything, complain. diff --git a/test/decl/var/properties.swift b/test/decl/var/properties.swift index 12ef699fc53e4..ed57d4074b0e8 100644 --- a/test/decl/var/properties.swift +++ b/test/decl/var/properties.swift @@ -1267,3 +1267,12 @@ class WeakFixItTest { // expected-error @+1 {{'weak' variable should have optional type '(WFI_P1 & WFI_P2)?'}} {{18-18=(}} {{33-33=)?}} weak var bar : WFI_P1 & WFI_P2 } + +// SR-8811 +// Stored properties cannot have uninhabited types + +struct SR8811 { + var x: Never // expected-error {{stored property 'x' cannot have uninhabited type 'Never'}} + + var y: (Int, Never, Bool) // expected-error {{stored property 'y' cannot have uninhabited type '(Int, Never, Bool)'}} +} From f085c288656071bb601ee7e3df83d1d97d7b5ced Mon Sep 17 00:00:00 2001 From: Azoy Date: Tue, 23 Oct 2018 18:08:00 -0500 Subject: [PATCH 2/5] Not just instance members & better diagnostic fix some tests --- include/swift/AST/DiagnosticsSema.def | 11 ++++++++--- lib/Sema/TypeCheckDecl.cpp | 16 +++++++++++----- test/IRGen/generic_enums.swift | 1 + test/Reflection/Inputs/TypeLowering.swift | 8 +++++++- test/Reflection/typeref_lowering.swift | 4 +++- test/attr/attr_objc.swift | 4 +++- test/decl/var/properties.swift | 13 +++++++++++-- 7 files changed, 44 insertions(+), 13 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 24f91e0d195b6..90af8c8b3f198 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1367,9 +1367,14 @@ ERROR(pattern_binds_no_variables,none, "variables", (unsigned)) -ERROR(stored_property_no_uninhabited_type,none, - "stored property %0 cannot have uninhabited type %1", - (Identifier, Type)) +ERROR(pattern_no_uninhabited_type,none, + "%select{%select{variable|constant}0|stored property}1 %2 cannot have " + "enum type %3 with no cases", + (bool, bool, Identifier, Type)) +ERROR(pattern_no_uninhabited_tuple_type,none, + "%select{%select{variable|constant}0|stored property}1 %2 cannot have " + "tuple type %3 containing enum with no cases", + (bool, bool, Identifier, Type)) ERROR(nscoding_unstable_mangled_name,none, "%select{private|fileprivate|nested|local}0 class %1 has an " diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 729557c9705a0..d259e0b93d50e 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2461,12 +2461,18 @@ class DeclChecker : public DeclVisitor { } } - // Reject variable if it is a stored property with a structurally - // uninhabited type - if (VD->isInstanceMember() && VD->hasStorage() && + // Reject variable if it is a stored property with an uninhabited type + if (VD->hasStorage() && VD->getInterfaceType()->isStructurallyUninhabited()) { - TC.diagnose(VD->getLoc(), diag::stored_property_no_uninhabited_type, - VD->getName(), VD->getInterfaceType()); + auto uninhabitedTypeDiag = diag::pattern_no_uninhabited_type; + + if (VD->getInterfaceType()->is()) { + uninhabitedTypeDiag = diag::pattern_no_uninhabited_tuple_type; + } + + TC.diagnose(VD->getLoc(), uninhabitedTypeDiag, VD->isLet(), + VD->isInstanceMember(), VD->getName(), + VD->getInterfaceType()); VD->markInvalid(); } diff --git a/test/IRGen/generic_enums.swift b/test/IRGen/generic_enums.swift index 4d28aae8c7ca6..31286b399c338 100644 --- a/test/IRGen/generic_enums.swift +++ b/test/IRGen/generic_enums.swift @@ -6,4 +6,5 @@ struct Bar { } enum Foo{ + case bar } diff --git a/test/Reflection/Inputs/TypeLowering.swift b/test/Reflection/Inputs/TypeLowering.swift index c11b2575bf8db..7c8683925e289 100644 --- a/test/Reflection/Inputs/TypeLowering.swift +++ b/test/Reflection/Inputs/TypeLowering.swift @@ -144,8 +144,14 @@ public struct MetatypeStruct { public let abstractMetatype: MetadataHolder } +// We don't allow stored properties to have uninhabited types now, but make a +// wrapper over one to continue testing this public enum EmptyEnum {} +public struct EmptyEnumWrapper { + public var value: T +} + public enum NoPayloadEnum { case A case B @@ -194,7 +200,7 @@ public enum MultiPayloadGenericDynamic { } public struct EnumStruct { - public let empty: EmptyEnum + public let empty: EmptyEnumWrapper public let noPayload: NoPayloadEnum public let sillyNoPayload: SillyNoPayloadEnum public let singleton: SingletonEnum diff --git a/test/Reflection/typeref_lowering.swift b/test/Reflection/typeref_lowering.swift index b72c45be0701c..b15074409b1fc 100644 --- a/test/Reflection/typeref_lowering.swift +++ b/test/Reflection/typeref_lowering.swift @@ -926,7 +926,9 @@ // CHECK-64: (struct TypeLowering.EnumStruct) // CHECK-64-NEXT: (struct size=81 alignment=8 stride=88 num_extra_inhabitants=[[PTR_XI]] // CHECK-64-NEXT: (field name=empty offset=0 -// CHECK-64-NEXT: (no_payload_enum size=0 alignment=1 stride=1 num_extra_inhabitants=0)) +// CHECK-64-NEXT: (struct size=0 alignment=1 stride=1 num_extra_inhabitants=0 +// CHECK-64-NEXT: (field name=value offset=0 +// CHECK-64-NEXT: (no_payload_enum size=0 alignment=1 stride=1 num_extra_inhabitants=0)))) // CHECK-64-NEXT: (field name=noPayload offset=0 // CHECK-64-NEXT: (no_payload_enum size=1 alignment=1 stride=1 num_extra_inhabitants=0)) // CHECK-64-NEXT: (field name=sillyNoPayload offset=1 diff --git a/test/attr/attr_objc.swift b/test/attr/attr_objc.swift index 49f74cdafa107..ac6a76a2583ff 100644 --- a/test/attr/attr_objc.swift +++ b/test/attr/attr_objc.swift @@ -941,11 +941,12 @@ class infer_instanceVar1 { // expected-note@-2 {{Swift structs cannot be represented in Objective-C}} var var_PlainEnum: PlainEnum -// CHECK-LABEL: {{^}} var var_PlainEnum: PlainEnum + // expected-error@-1 {{stored property 'var_PlainEnum' cannot have enum type 'PlainEnum' with no cases}} @objc var var_PlainEnum_: PlainEnum // expected-error@-1 {{property cannot be marked @objc because its type cannot be represented in Objective-C}} // expected-note@-2 {{non-'@objc' enums cannot be represented in Objective-C}} + // expected-error@-3 {{stored property 'var_PlainEnum_' cannot have enum type 'PlainEnum' with no cases}} var var_PlainProtocol: PlainProtocol // CHECK-LABEL: {{^}} var var_PlainProtocol: PlainProtocol @@ -1271,6 +1272,7 @@ class infer_instanceVar1 { // expected-error@-1 {{'unowned' may only be applied to class and class-bound protocol types, not 'PlainStruct'}} unowned var var_Unowned_bad3: PlainEnum // expected-error@-1 {{'unowned' may only be applied to class and class-bound protocol types, not 'PlainEnum'}} + // expected-error@-2 {{stored property 'var_Unowned_bad3' cannot have enum type 'PlainEnum' with no cases}} unowned var var_Unowned_bad4: String // expected-error@-1 {{'unowned' may only be applied to class and class-bound protocol types, not 'String'}} // CHECK-NOT: @objc{{.*}}Unowned_fail diff --git a/test/decl/var/properties.swift b/test/decl/var/properties.swift index ed57d4074b0e8..35603391de35e 100644 --- a/test/decl/var/properties.swift +++ b/test/decl/var/properties.swift @@ -1272,7 +1272,16 @@ class WeakFixItTest { // Stored properties cannot have uninhabited types struct SR8811 { - var x: Never // expected-error {{stored property 'x' cannot have uninhabited type 'Never'}} + var x: Never // expected-error {{stored property 'x' cannot have enum type 'Never' with no cases}} - var y: (Int, Never, Bool) // expected-error {{stored property 'y' cannot have uninhabited type '(Int, Never, Bool)'}} + var y: (Int, Never, Bool) // expected-error {{stored property 'y' cannot have tuple type '(Int, Never, Bool)' containing enum with no cases}} +} + +let sr8811x: Never // expected-error {{constant 'sr8811x' cannot have enum type 'Never' with no cases}} + +var sr8811y: (Int, Never) // expected-error {{variable 'sr8811y' cannot have tuple type '(Int, Never)' containing enum with no cases}} + +// Ok +var sr8811z: Never { + return fatalError() } From 83e0cfae0fd0499a98cfb01eb2808e3674bcbf4c Mon Sep 17 00:00:00 2001 From: Azoy Date: Tue, 23 Oct 2018 18:31:44 -0500 Subject: [PATCH 3/5] Assert for unknown structurally uninhabited types --- lib/Sema/TypeCheckDecl.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index d259e0b93d50e..e3eb715a13cd9 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2468,6 +2468,9 @@ class DeclChecker : public DeclVisitor { if (VD->getInterfaceType()->is()) { uninhabitedTypeDiag = diag::pattern_no_uninhabited_tuple_type; + } else { + assert(VD->getInterfaceType()->is() && + "unknown structurally uninhabited type"); } TC.diagnose(VD->getLoc(), uninhabitedTypeDiag, VD->isLet(), From 2973696a24b55191783566f5c06a7a10c1ad0f77 Mon Sep 17 00:00:00 2001 From: Azoy Date: Tue, 23 Oct 2018 19:29:42 -0500 Subject: [PATCH 4/5] and generic enums aswell Add generic enum test case --- lib/Sema/TypeCheckDecl.cpp | 3 ++- test/decl/var/properties.swift | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index e3eb715a13cd9..d3c5939a79bed 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2469,7 +2469,8 @@ class DeclChecker : public DeclVisitor { if (VD->getInterfaceType()->is()) { uninhabitedTypeDiag = diag::pattern_no_uninhabited_tuple_type; } else { - assert(VD->getInterfaceType()->is() && + assert((VD->getInterfaceType()->is() || + VD->getInterfaceType()->is()) && "unknown structurally uninhabited type"); } diff --git a/test/decl/var/properties.swift b/test/decl/var/properties.swift index 35603391de35e..3d15163231c9a 100644 --- a/test/decl/var/properties.swift +++ b/test/decl/var/properties.swift @@ -1285,3 +1285,7 @@ var sr8811y: (Int, Never) // expected-error {{variable 'sr8811y' cannot have tup var sr8811z: Never { return fatalError() } + +enum SR8811EmptyGenericEnum {} + +let sr8811z: SR8811SR8811EmptyGenericEnum // expected-error {{constant 'sr8811z' cannot have enum type 'SR8811EmptyGenericEnum' with no cases}} From 5dcf823d8dc8ac9b31eefacbaa7dfdd367e88c8a Mon Sep 17 00:00:00 2001 From: Azoy Date: Tue, 23 Oct 2018 21:09:38 -0500 Subject: [PATCH 5/5] Fix non instance member tests --- test/attr/attr_noreturn.swift | 3 ++- test/decl/var/properties.swift | 2 +- test/expr/expressions.swift | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/test/attr/attr_noreturn.swift b/test/attr/attr_noreturn.swift index 8dea7613d6954..d68b44238024e 100644 --- a/test/attr/attr_noreturn.swift +++ b/test/attr/attr_noreturn.swift @@ -34,7 +34,8 @@ func noReturn3(_: Int) // expected-error@-2 {{'@noreturn' has been removed; functions that never return should have a return type of 'Never' instead}}{{1-11=}}{{53-56=Never}} // Test that error recovery gives us the 'Never' return type -let x: Never = noReturn1(0) // No error +let x: Never = noReturn1(0) +// expected-error@-1 {{constant 'x' cannot have enum type 'Never' with no cases}} // @noreturn in function type declarations let valueNoReturn: @noreturn () -> () diff --git a/test/decl/var/properties.swift b/test/decl/var/properties.swift index 3d15163231c9a..6e1f6f7e38008 100644 --- a/test/decl/var/properties.swift +++ b/test/decl/var/properties.swift @@ -1288,4 +1288,4 @@ var sr8811z: Never { enum SR8811EmptyGenericEnum {} -let sr8811z: SR8811SR8811EmptyGenericEnum // expected-error {{constant 'sr8811z' cannot have enum type 'SR8811EmptyGenericEnum' with no cases}} +let sr8811z: SR8811EmptyGenericEnum // expected-error {{constant 'sr8811z' cannot have enum type 'SR8811EmptyGenericEnum' with no cases}} diff --git a/test/expr/expressions.swift b/test/expr/expressions.swift index f28c7b05b476f..0473b67d103cc 100644 --- a/test/expr/expressions.swift +++ b/test/expr/expressions.swift @@ -584,9 +584,9 @@ func conversionTest(_ a: inout Double, b: inout Int) { var pi_f3 = float.init(getPi()) // expected-error {{ambiguous use of 'init(_:)'}} var pi_f4 = float.init(pi_f) - var e = Empty(f) + var e = Empty(f) // expected-error {{variable 'e' cannot have enum type 'Empty' with no cases}} var e2 = Empty(d) // expected-error{{cannot convert value of type 'Double' to expected argument type 'Float'}} - var e3 = Empty(Float(d)) + var e3 = Empty(Float(d)) // expected-error {{variable 'e3' cannot have enum type 'Empty' with no cases}} } struct Rule { // expected-note {{'init(target:dependencies:)' declared here}}