|
| 1 | +// RUN: %target-typecheck-verify-swift -parse-as-library -enable-experimental-feature NestedProtocols |
| 2 | + |
| 3 | +// Protocols can be nested inside non-generic types. |
| 4 | + |
| 5 | +protocol Delegate {} |
| 6 | + |
| 7 | +enum Table { |
| 8 | + protocol Delegate {} |
| 9 | +} |
| 10 | + |
| 11 | +enum Button { |
| 12 | + protocol Delegate {} |
| 13 | +} |
| 14 | + |
| 15 | +struct PlainDelegateConformer: Delegate {} |
| 16 | +struct TableDelegateConformer: Table.Delegate {} |
| 17 | +struct ButtonDelegateConformer: Button.Delegate {} |
| 18 | + |
| 19 | +func testDifferent() { |
| 20 | + let plain = PlainDelegateConformer() |
| 21 | + if plain is Delegate { print("ok (1)") } // expected-warning {{'is' test is always true}} |
| 22 | + if plain is Table.Delegate { print("bad (2)") } |
| 23 | + if plain is Button.Delegate { print("bad (3)") } |
| 24 | + |
| 25 | + let tableDel = TableDelegateConformer() |
| 26 | + if tableDel is Delegate { print("bad (4)") } |
| 27 | + if tableDel is Table.Delegate { print("ok (5)") } // expected-warning {{'is' test is always true}} |
| 28 | + if tableDel is Button.Delegate { print("bad (6)") } |
| 29 | + |
| 30 | + let buttonDel = ButtonDelegateConformer() |
| 31 | + if buttonDel is Delegate { print("bad (7)") } |
| 32 | + if buttonDel is Table.Delegate { print("bad (8)") } |
| 33 | + if buttonDel is Button.Delegate { print("ok (9)") } // expected-warning {{'is' test is always true}} |
| 34 | +} |
| 35 | + |
| 36 | +enum OuterEnum { |
| 37 | + protocol C {} |
| 38 | + case C(C) |
| 39 | + // expected-error@-1{{invalid redeclaration of 'C'}} |
| 40 | + // expected-note@-3{{'C' previously declared here}} |
| 41 | +} |
| 42 | + |
| 43 | +class OuterClass { |
| 44 | + protocol InnerProtocol : OuterClass { } |
| 45 | +} |
| 46 | + |
| 47 | +// Deeply nested. |
| 48 | + |
| 49 | +enum Level0 { |
| 50 | + struct Level1 { |
| 51 | + class Level2 { |
| 52 | + actor Level3 { |
| 53 | + struct Level4 { |
| 54 | + class Level5 { |
| 55 | + protocol DeeplyNested { |
| 56 | + func someRequirement() |
| 57 | + } |
| 58 | + func lookupTest(_ input: some DeeplyNested) {} |
| 59 | + } |
| 60 | + func lookupTest(_ input: some Level5.DeeplyNested) {} |
| 61 | + } |
| 62 | + func lookupTest(_ input: some Level4.Level5.DeeplyNested) {} |
| 63 | + } |
| 64 | + } |
| 65 | + } |
| 66 | +} |
| 67 | + |
| 68 | +func useDeeplyNested(_ input: some Level0.Level1.Level2.Level3.Level4.Level5.DeeplyNested) { |
| 69 | + input.someRequirement() |
| 70 | +} |
| 71 | + |
| 72 | +// Add a nested protocol in an extension. |
| 73 | + |
| 74 | +extension Level0.Level1.Level2 { |
| 75 | + protocol ModeratelyNested { |
| 76 | + associatedtype ReturnValue |
| 77 | + func anotherRequirement() -> ReturnValue |
| 78 | + } |
| 79 | + |
| 80 | + func lookupTest(_: some ModeratelyNested) { } |
| 81 | +} |
| 82 | + |
| 83 | +func useModeratelyNested<Input>( |
| 84 | + _ input: Input |
| 85 | +) -> Input.ReturnValue where Input: Level0.Level1.Level2.ModeratelyNested { |
| 86 | + input.anotherRequirement() |
| 87 | +} |
| 88 | + |
| 89 | +struct ModeratelyNestedConformer: Level0.Level1.Level2.ModeratelyNested { |
| 90 | + func anotherRequirement() -> Int { |
| 91 | + 99 |
| 92 | + } |
| 93 | +} |
| 94 | + |
| 95 | +let _umn: Int = useModeratelyNested(ModeratelyNestedConformer()) |
| 96 | + |
| 97 | +// Extend a nested protocol. |
| 98 | + |
| 99 | +extension Level0.Level1.Level2.ModeratelyNested { |
| 100 | + func extensionMethod() -> ReturnValue { |
| 101 | + anotherRequirement() |
| 102 | + } |
| 103 | +} |
| 104 | + |
| 105 | +extension Level0.Level1.Level2.ModeratelyNested where ReturnValue == Int { |
| 106 | + func extensionMethod() -> Int { |
| 107 | + anotherRequirement() + 1 |
| 108 | + } |
| 109 | +} |
| 110 | + |
| 111 | +// Protocols may be nested inside non-generic functions. |
| 112 | + |
| 113 | +func someFunction_0() { |
| 114 | + protocol Yes {} |
| 115 | + struct Foo: Yes {} |
| 116 | + struct Bar: Yes {} |
| 117 | +} |
| 118 | + |
| 119 | +func someFunction_1() { |
| 120 | + |
| 121 | + struct HowAboutThis { |
| 122 | + protocol AlsoYes { |
| 123 | + associatedtype SomeType |
| 124 | + func doSomething() -> SomeType |
| 125 | + } |
| 126 | + } |
| 127 | + |
| 128 | + struct Conforms0: HowAboutThis.AlsoYes { |
| 129 | + typealias SomeType = Int |
| 130 | + func doSomething() -> SomeType { -99 } |
| 131 | + } |
| 132 | + |
| 133 | + struct Conforms1: HowAboutThis.AlsoYes { |
| 134 | + typealias SomeType = String |
| 135 | + func doSomething() -> SomeType { "works" } |
| 136 | + } |
| 137 | + |
| 138 | + func usesNested<T: HowAboutThis.AlsoYes>(_ input: T) -> T.SomeType { |
| 139 | + input.doSomething() |
| 140 | + } |
| 141 | + |
| 142 | + let _: Int = usesNested(Conforms0()) |
| 143 | + let _: String = usesNested(Conforms1()) |
| 144 | +} |
| 145 | + |
| 146 | +// Protocols cannot be nested in generic types or other protocols. |
| 147 | + |
| 148 | +struct OuterGeneric<D> { |
| 149 | + protocol InnerProtocol { // expected-error{{protocol 'InnerProtocol' cannot be nested inside a generic context}} |
| 150 | + associatedtype Rooster |
| 151 | + func flip(_ r: Rooster) |
| 152 | + func flop(_ t: D) // expected-error{{cannot find type 'D' in scope}} |
| 153 | + } |
| 154 | +} |
| 155 | + |
| 156 | +class OuterGenericClass<T> { |
| 157 | + protocol InnerProtocol { // expected-error{{protocol 'InnerProtocol' cannot be nested inside a generic context}} |
| 158 | + associatedtype Rooster |
| 159 | + func flip(_ r: Rooster) |
| 160 | + func flop(_ t: T) // expected-error{{cannot find type 'T' in scope}} |
| 161 | + } |
| 162 | +} |
| 163 | + |
| 164 | +protocol OuterProtocol { |
| 165 | + associatedtype Hen |
| 166 | + protocol InnerProtocol { // expected-error{{protocol 'InnerProtocol' cannot be nested inside another protocol}} |
| 167 | + associatedtype Rooster |
| 168 | + func flip(_ r: Rooster) |
| 169 | + func flop(_ h: Hen) // expected-error{{cannot find type 'Hen' in scope}} |
| 170 | + } |
| 171 | +} |
| 172 | + |
| 173 | +struct ConformsToOuterProtocol : OuterProtocol { |
| 174 | + typealias Hen = Int |
| 175 | + |
| 176 | + func f() { let _ = InnerProtocol.self } // expected-error {{use of protocol 'OuterProtocol.InnerProtocol' as a type must be written 'any OuterProtocol.InnerProtocol'}} |
| 177 | +} |
| 178 | + |
| 179 | +// 'InnerProtocol' does not inherit the generic parameters of |
| 180 | +// 'OtherGenericClass', so the occurrence of 'OtherGenericClass' |
| 181 | +// in 'InnerProtocol' is not "in context" with implicitly |
| 182 | +// inferred generic arguments <T, U>. |
| 183 | +class OtherGenericClass<T, U> { // expected-note {{generic type 'OtherGenericClass' declared here}} |
| 184 | + protocol InnerProtocol : OtherGenericClass { } |
| 185 | + // expected-error@-1{{protocol 'InnerProtocol' cannot be nested inside a generic context}} |
| 186 | + // expected-error@-2{{reference to generic type 'OtherGenericClass' requires arguments in <...>}} |
| 187 | +} |
| 188 | + |
| 189 | +protocol SelfDotTest { |
| 190 | + func f(_: Self.Class) |
| 191 | + class Class {} |
| 192 | + // expected-error@-1{{type 'Class' cannot be nested in protocol 'SelfDotTest'}} |
| 193 | +} |
| 194 | + |
| 195 | +struct Outer { |
| 196 | + typealias E = NestedValidation.T |
| 197 | + protocol NestedValidation { |
| 198 | + typealias T = A.B |
| 199 | + class A { // expected-error {{type 'A' cannot be nested in protocol 'NestedValidation'}} |
| 200 | + typealias B = Int |
| 201 | + } |
| 202 | + } |
| 203 | +} |
| 204 | + |
| 205 | +struct OuterForUFI { |
| 206 | + @usableFromInline |
| 207 | + protocol Inner { |
| 208 | + func req() |
| 209 | + } |
| 210 | +} |
| 211 | + |
| 212 | +extension OuterForUFI.Inner { |
| 213 | + public func extMethod() {} // The 'public' puts this in a special path. |
| 214 | +} |
| 215 | + |
| 216 | +func testLookup(_ x: OuterForUFI.Inner) { |
| 217 | + x.req() |
| 218 | + x.extMethod() |
| 219 | +} |
| 220 | + |
| 221 | +func testLookup<T: OuterForUFI.Inner>(_ x: T) { |
| 222 | + x.req() |
| 223 | + x.extMethod() |
| 224 | +} |
| 225 | + |
| 226 | +// Protocols cannot be nested inside of generic functions. |
| 227 | + |
| 228 | +func invalidProtocolInGeneric<T>(_: T) { |
| 229 | + protocol Test {} // expected-error{{protocol 'Test' cannot be nested inside a generic context}} |
| 230 | +} |
| 231 | + |
| 232 | +struct NestedInGenericMethod<T> { |
| 233 | + func someMethod() { |
| 234 | + protocol AnotherTest {} // expected-error{{protocol 'AnotherTest' cannot be nested inside a generic context}} |
| 235 | + } |
| 236 | +} |
| 237 | + |
| 238 | +// Types cannot be nested inside of protocols. |
| 239 | + |
| 240 | +protocol Racoon { |
| 241 | + associatedtype Stripes |
| 242 | + class Claw<T> { // expected-error{{type 'Claw' cannot be nested in protocol 'Racoon'}} |
| 243 | + func mangle(_ s: Stripes) {} |
| 244 | + // expected-error@-1 {{cannot find type 'Stripes' in scope}} |
| 245 | + } |
| 246 | + struct Fang<T> { // expected-error{{type 'Fang' cannot be nested in protocol 'Racoon'}} |
| 247 | + func gnaw(_ s: Stripes) {} |
| 248 | + // expected-error@-1 {{cannot find type 'Stripes' in scope}} |
| 249 | + } |
| 250 | + enum Fur { // expected-error{{type 'Fur' cannot be nested in protocol 'Racoon'}} |
| 251 | + case Stripes |
| 252 | + } |
| 253 | +} |
| 254 | + |
| 255 | +enum SillyRawEnum : SillyProtocol.InnerClass {} // expected-error {{an enum with no cases cannot declare a raw type}} |
| 256 | +// expected-error@-1 {{reference to generic type 'SillyProtocol.InnerClass' requires arguments in <...>}} |
| 257 | + |
| 258 | +protocol SillyProtocol { |
| 259 | + class InnerClass<T> {} // expected-error {{type 'InnerClass' cannot be nested in protocol 'SillyProtocol'}} |
| 260 | + // expected-note@-1 {{generic type 'InnerClass' declared here}} |
| 261 | +} |
0 commit comments