File: enum_raw_representable.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (315 lines) | stat: -rw-r--r-- 11,848 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
// RUN: %target-typecheck-verify-swift

enum Foo : Int {
  case a, b, c
}

var raw1: Int = Foo.a.rawValue
var raw2: Foo.RawValue = raw1
var cooked1: Foo? = Foo(rawValue: 0)
var cooked2: Foo? = Foo(rawValue: 22)

enum Bar : Double {
  case a, b, c
}

func localEnum() -> Int {
  enum LocalEnum : Int {
    case a, b, c
  }
  return LocalEnum.a.rawValue
}

enum MembersReferenceRawType : Int {
  case a, b, c

  init?(rawValue: Int) {
    self = MembersReferenceRawType(rawValue: rawValue)!
  }

  func successor() -> MembersReferenceRawType {
    return MembersReferenceRawType(rawValue: rawValue + 1)!
  }
}

func serialize<T : RawRepresentable>(_ values: [T]) -> [T.RawValue] {
  return values.map { $0.rawValue }
}

func deserialize<T : RawRepresentable>(_ serialized: [T.RawValue]) -> [T] {
  return serialized.map { T(rawValue: $0)! }
}

var ints: [Int] = serialize([Foo.a, .b, .c])
var doubles: [Double] = serialize([Bar.a, .b, .c])

var foos: [Foo] = deserialize([1, 2, 3])
var bars: [Bar] = deserialize([1.2, 3.4, 5.6])

// We reject enums where the raw type stated in the inheritance clause does not
// match the types of the witnesses.
enum Color : Int {
  case red
  case blue

  init?(rawValue: Double) {
    return nil
  }

  var rawValue: Double { // expected-note {{found this candidate}}
    return 1.0
  }
}

func useRawValue(of color: Color) {
  _ = color.rawValue
  // expected-error@-1 {{ambiguous use of 'rawValue'}}
}

var colorRaw: Color.RawValue = 7.5
// expected-error@-1 {{cannot convert value of type 'Double' to specified type 'Color.RawValue' (aka 'Int')}}

// Mismatched case types

enum BadPlain : UInt { // expected-error {{'BadPlain' declares raw type 'UInt', but does not conform to RawRepresentable and conformance could not be synthesized}}
    case a = "hello"   // expected-error {{cannot convert value of type 'String' to raw type 'UInt'}}
}

// Recursive diagnostics issue in tryRawRepresentableFixIts()
class Outer {
  // The setup is that we have to trigger the conformance check
  // while diagnosing the conversion here. For the purposes of
  // the test I'm putting everything inside a class in the right
  // order, but the problem can trigger with a multi-file
  // scenario too.
  let a: Int = E.a // expected-error {{cannot convert value of type 'Outer.E' to specified type 'Int'}}

  enum E : Array<Int> {
  // expected-error@-1 {{raw type 'Array<Int>' is not expressible by a string, integer, or floating-point literal}}
  // expected-error@-2 {{'Outer.E' declares raw type 'Array<Int>', but does not conform to RawRepresentable and conformance could not be synthesized}}
    case a
  }
}

// rdar://problem/32431736 - Conversion fix-it from String to String raw value enum can't look through optionals

func rdar32431736() {
  enum E : String {
    case A = "A"
    case B = "B"
  }

  let items1: [String] = ["A", "a"]
  let items2: [String]? = ["A"]

  let myE1: E = items1.first
  // expected-error@-1 {{cannot convert value of type 'String?' to specified type 'E'}}
  // expected-note@-2 {{construct 'E' from unwrapped 'String' value}} {{17-17=E(rawValue: }} {{29-29=!) ?? <#default value#>}}

  let myE2: E = items2?.first
  // expected-error@-1 {{cannot convert value of type 'String?' to specified type 'E'}}
  // expected-note@-2 {{construct 'E' from unwrapped 'String' value}} {{17-17=E(rawValue: (}} {{30-30=)!) ?? <#default value#>}}
}

// rdar://problem/32431165 - improve diagnostic for raw representable argument mismatch

enum E_32431165 : String {
  case foo = "foo"
  case bar = "bar" // expected-note {{'bar' declared here}}
}

func rdar32431165_1(_: E_32431165) {}
func rdar32431165_1(_: Int) {}
func rdar32431165_1(_: Int, _: E_32431165) {}

rdar32431165_1(E_32431165.baz)
// expected-error@-1 {{type 'E_32431165' has no member 'baz'; did you mean 'bar'?}}

rdar32431165_1(.baz)
// expected-error@-1 {{reference to member 'baz' cannot be resolved without a contextual type}}

rdar32431165_1("")
// expected-error@-1 {{cannot convert value of type 'String' to expected argument type 'E_32431165'}}
rdar32431165_1(42, "")
// expected-error@-1 {{cannot convert value of type 'String' to expected argument type 'E_32431165'}} {{20-20=E_32431165(rawValue: }} {{22-22=) ?? <#default value#>}}

func rdar32431165_2(_: String) {}
func rdar32431165_2(_: Int) {}
func rdar32431165_2(_: Int, _: String) {}

rdar32431165_2(E_32431165.bar)
// expected-error@-1 {{cannot convert value of type 'E_32431165' to expected argument type 'String'}} {{30-30=.rawValue}}
rdar32431165_2(42, E_32431165.bar)
// expected-error@-1 {{cannot convert value of type 'E_32431165' to expected argument type 'String'}} {{34-34=.rawValue}}

// TODO: In following two examples it's possible to fix a problem by either using `.rawValue` on first argument
// or constructing raw representable type from second, both ways are valid.
do {
  E_32431165.bar == "bar"
  // expected-error@-1 {{cannot convert value of type 'E_32431165' to expected argument type 'String'}} {{17-17=.rawValue}}

  "bar" == E_32431165.bar
  // expected-error@-1 {{cannot convert value of type 'E_32431165' to expected argument type 'String'}} {{26-26=.rawValue}}
}

func rdar32431165_overloaded() -> Int { 42 }     // expected-note {{'rdar32431165_overloaded()' produces 'Int', not the expected contextual result type 'E_32431165'}}
func rdar32431165_overloaded() -> String { "A" } // expected-note {{'rdar32431165_overloaded()' produces 'String', not the expected contextual result type 'E_32431165'}}

func test_candidate_diagnostic() {
  func test_argument(_: E_32431165) {}

  let _: E_32431165 = rdar32431165_overloaded() // expected-error {{no 'rdar32431165_overloaded' candidates produce the expected contextual result type 'E_32431165'}}
  test_argument(rdar32431165_overloaded()) // expected-error {{cannot convert value of type 'String' to expected argument type 'E_32431165'}} {{17-17=E_32431165(rawValue: }} {{42-42=) ?? <#default value#>}}
}

func rdar32432253(_ condition: Bool = false) {
  let choice: E_32431165 = condition ? .foo : .bar
  let _ = choice == "bar"
  // expected-error@-1 {{cannot convert value of type 'E_32431165' to expected argument type 'String'}} {{17-17=.rawValue}}
}

// https://github.com/apple/swift/issues/50682
do {
  func helper1(_: Int) {}
  func helper1(_: Double) {}

  func helper2(_: Double) {}
  func helper2(_: Int) {}

  func helper3(_: Foo) {}
  func helper3(_: Bar) {}

  func helper4(_: Bar) {}
  func helper4(_: Foo) {}

  do {
    let bar: Bar

    helper1(bar)
    // expected-error@-1 {{cannot convert value of type 'Bar' to expected argument type 'Double'}} {{16-16=.rawValue}}
    helper2(bar)
    // expected-error@-1 {{cannot convert value of type 'Bar' to expected argument type 'Double'}} {{16-16=.rawValue}}
    helper3(0.0)
    // expected-error@-1 {{cannot convert value of type 'Double' to expected argument type 'Bar'}} {{13-13=Bar(rawValue: }} {{16-16=) ?? <#default value#>}}
    helper4(0.0)
    // expected-error@-1 {{cannot convert value of type 'Double' to expected argument type 'Bar'}} {{13-13=Bar(rawValue: }} {{16-16=) ?? <#default value#>}}
  }

  // Bonus problem with mutable values being passed.
  do {
    class Box {
      var bar: Bar
      init(bar: Bar) {}
    }

    let box: Box

    helper1(box.bar)
    // expected-error@-1 {{cannot convert value of type 'Bar' to expected argument type 'Double'}} {{20-20=.rawValue}}

    var bar = box.bar
    helper1(bar)
    // expected-error@-1 {{cannot convert value of type 'Bar' to expected argument type 'Double'}} {{16-16=.rawValue}}
  }

  do {
    let opt: Bar?

    helper1(opt)
    // expected-error@-1 {{cannot convert value of type 'Bar?' to expected argument type 'Double'}} {{16-16=?.rawValue ?? <#default value#>}}
    helper1(opt ?? Bar.a)
    // expected-error@-1 {{cannot convert value of type 'Bar' to expected argument type 'Double'}} {{13-13=(}} {{25-25=).rawValue}}
    let _: Double? = opt
    // expected-error@-1 {{cannot convert value of type 'Bar?' to specified type 'Double?'}} {{25-25=?.rawValue}}
  }
}

struct NotEquatable { }

enum ArrayOfNewEquatable : Array<NotEquatable> { }
// expected-error@-1{{raw type 'Array<NotEquatable>' is not expressible by a string, integer, or floating-point literal}}
// expected-error@-2{{'ArrayOfNewEquatable' declares raw type 'Array<NotEquatable>', but does not conform to RawRepresentable and conformance could not be synthesized}}
// expected-error@-3{{RawRepresentable conformance cannot be synthesized because raw type 'Array<NotEquatable>' is not Equatable}}
// expected-error@-4{{an enum with no cases cannot declare a raw type}}

// rdar://58127114
struct NotEquatableInteger : ExpressibleByIntegerLiteral {
  typealias IntegerLiteralType = Int

  init(integerLiteral: Int) {}
}

enum NotEquatableRawType1 : NotEquatableInteger {
// expected-error@-1 {{'NotEquatableRawType1' declares raw type 'NotEquatableInteger', but does not conform to RawRepresentable and conformance could not be synthesized}}
// expected-error@-2 {{RawRepresentable conformance cannot be synthesized because raw type 'NotEquatableInteger' is not Equatable}}
  case a = 123
}


enum NotEquatableRawType2 : NotEquatableInteger {
// expected-error@-1 {{'NotEquatableRawType2' declares raw type 'NotEquatableInteger', but does not conform to RawRepresentable and conformance could not be synthesized}}
// expected-error@-2 {{RawRepresentable conformance cannot be synthesized because raw type 'NotEquatableInteger' is not Equatable}}
  typealias RawValue = NotEquatableInteger

  case a = 123
}

struct NotEquatableString : ExpressibleByStringLiteral {
  init(stringLiteral: String) {}
}

// FIXME: This could be diagnosed a bit better. The notes are disembodied
enum NotEquatableRawType3: NotEquatableString {
// expected-error@-1 {{RawRepresentable conformance cannot be synthesized because raw type 'NotEquatableString' is not Equatable}}
// expected-error@-2 {{'NotEquatableRawType3' declares raw type 'NotEquatableString', but does not conform to RawRepresentable and conformance could not be synthesized}}
  case a
  typealias RawValue = NotEquatableString
  init?(rawValue: Int) { self = .a }
  // expected-note@-1 {{candidate has non-matching type '(rawValue: Int)'}}
  var rawValue: Int { 0 }
  // expected-note@-1 {{candidate has non-matching type 'Int'}}
}

enum MismatchedRawValues {
  enum ExistentialBound: Any? {
    // expected-error@-1 {{raw type 'Any?' is not expressible}}
    // expected-error@-2 {{'MismatchedRawValues.ExistentialBound' declares raw type 'Any?'}}
    // expected-error@-3 {{RawRepresentable conformance cannot be synthesized }}
    case test = nil
  }

  public enum StringViaStaticString: StaticString {
    // expected-error@-1 {{'MismatchedRawValues.StringViaStaticString' declares raw type 'StaticString', but does not conform to RawRepresentable}}
    // expected-error@-2 {{RawRepresentable conformance cannot be synthesized because}}
    public typealias RawValue = String

    case TRUE = "TRUE"
    case FALSE = "FALSE"
  }

  public enum IntViaString: String {
    // expected-error@-1 {{'MismatchedRawValues.IntViaString' declares raw type 'String', but does not conform to RawRepresentable}}
    public typealias RawValue = Int

    case TRUE = "TRUE"
    case FALSE = "FALSE"
  }

  public enum ViaNested: String {
    // expected-error@-1 {{'MismatchedRawValues.ViaNested' declares raw type 'String', but does not conform to RawRepresentable}}
    struct RawValue: Equatable {
      let x: String
    }

    case TRUE = "TRUE"
    case FALSE = "FALSE"
  }

  public enum ViaGenericBound<RawValue: Equatable>: String {
    // expected-error@-1 {{'MismatchedRawValues.ViaGenericBound<RawValue>' declares raw type 'String'}}
    typealias RawValue = RawValue
    case TRUE = "TRUE"
    case FALSE = "FALSE"
  }
}