CTMacUser
(Daryle Walker)
1
This is in a new Xcode 11 playground:
public struct DivisibilityIterator<Element: BinaryInteger> where Element.Magnitude == Element {
enum State {
case zero
case one
case other(divisor: Element, dividend: Element)
}
var state: State
init<T: BinaryInteger>(divisor: T, firstDividend: T) where T.Magnitude == Element {
let absoluteDivisor = divisor.magnitude
switch absoluteDivisor {
case 0:
state = .zero // 1
case 1:
state = .one // 1
default:
let reducedDividend = firstDividend % divisor
let absoluteDividend: Element
if reducedDividend < 0 {
absoluteDividend = absoluteDivisor - reducedDividend.magnitude // 2
} else {
absoluteDividend = reducedDividend.magnitude // 2
}
state = .other(absoluteDivisor, absoluteDividend) // 1
}
}
}
The errors at 1 are: "'DivisibilityIterator' requires the types 'Element' and 'Element.Magnitude' be equivalent". The ones at 2 are: "Cannot assign value of type 'T.Magnitude' to type 'Element'", with a fix-it of: "Insert ' as! Element'".
Error 1 makes no sense because it's completely irrelevant to what I'm doing there! Error 2 makes no sense because the initializer's where clause already requires the types to be the same. Is there some subtle rules of Swift I'm missing in either case?
I tried moving the State type to a separate enum generic type; got the same error. I closed the playground window, quit Xcode, and reopened both; didn't help. I haven't rebooted the computer (yet). That has helped in the past, but it's totally unacceptable that the Playgrounds system is that fragile to need that workaround, especially that there's no guarantee that it'll work.
Lantua
2
A more compact code for error 1
struct Foo<Element: BinaryInteger> where Element.Magnitude == Element {
var value: Int
init<T: BinaryInteger>(divisor: T) where T.Magnitude == Element {
value = 1 /* 'Foo<Element>' requires the types 'Element' and 'Element.Magnitude' be equivalent */
}
}
Looks like T.Magnitude == Element makes compiler forget the Element constraint, or something. It looks like a bug.
mayoff
(Rob Mayoff)
3
This version crashes the compiler:
public struct Test<E: BinaryInteger> where E.Magnitude == E {
var x: Int = 0
init<F: BinaryInteger>(_: F) where F.Magnitude == E { }
}
Can you file a bug on bugs.swift.org? Thanks!
mayoff
(Rob Mayoff)
5
I opened SR-11531 for the inscrutable error message and SR-11532 for the compiler crash.
4 Likes
CTMacUser
(Daryle Walker)
6
I did a workaround that's probably better anyway. Not that finding bugs isn't important, especially the weird ones.
struct ModuloIterator<Element: BinaryInteger> {
let dividendLimit: Element.Magnitude
var reducedDividend: Element.Magnitude
init(divisor: Element, start: Element) {
let remainder = start % divisor // Crashes with out-of-range divisions.
if remainder >= 0 {
reducedDividend = remainder.magnitude
} else if divisor >= 0 {
reducedDividend = (remainder + divisor).magnitude
} else {
reducedDividend = (remainder - divisor).magnitude
}
dividendLimit = divisor.magnitude - 1
}
}
extension ModuloIterator: IteratorProtocol {
mutating func next() -> Element? {
defer {
if reducedDividend == dividendLimit {
reducedDividend = 0
} else {
reducedDividend += 1
}
}
return Element(reducedDividend)
}
}
struct DivisibilityIterator<Integer: BinaryInteger> {
enum State {
case zero, one, other(ModuloIterator<Integer>)
}
var state: State
init(divisor: Integer, start: Integer) {
switch divisor.magnitude {
case 0: state = .zero
case 1: state = .one
default: state = .other(ModuloIterator(divisor: divisor, start: start))
}
}
}
extension DivisibilityIterator: IteratorProtocol {
mutating func next() -> Bool? {
switch state {
case .zero: return false
case .one: return true
case .other(var iterator):
defer { state = .other(iterator) }
return iterator.next().map { $0 == 0 }
}
}
}