Negative integer literal converted to generic unsigned integer type without warning

Hello! This is my first post, please tell me even more so if I'm making a mess! :wave:

I came across a case where a negative integer literal can be converted to an unsigned integer type without warning, when generics are involved. I posted to StackOverflow and was directed here with my question (mostly-repost follows).

In this simple piece of code, I'm using the integer literal -1 in a context where a value of type T is expected. T conforms to FixedWidthInteger so it's unknown at compile time whether the literal can be converted to the actual type T. If T is set to an unsigned integer type, the -1 simply becomes a 0. I would have expected a runtime error, or at least a warning at compile time. Is this a bug or is this documented somewhere?

struct Bad<T: FixedWidthInteger> {
    func getNegativeOne() -> T {
        return -1
    }
}

print(Bad<UInt32>().getNegativeOne())
$ swiftc bad.swift 
$ ./bad
0

My system:

$ swift --version
swift-driver version: 1.26.21 Apple Swift version 5.5.2 (swiftlang-1300.0.47.5 clang-1300.0.29.30)
Target: arm64-apple-macosx12.0
2 Likes

Hi @feuermurmel! :wave:

Since that behavior is different when you're using concrete types, I agree that it's a bug. Here's a reduced case:

let x = -1 as UInt
// error: negative integer '-1' overflows when stored into unsigned type 'UInt'

func f<T: FixedWidthInteger>(_: T.Type) -> T { -1 as T }
f(UInt.self) // 0 (no error!)

If you wouldn't mind filing a bug over at bugs.swift.org and then posting the link to it here, that'd be great. Someone can triage it there. From a cursory glance it seems like it'd be straightforward to do something about it, but the key question is whether something can be done without regressing performance in the concrete case.

/cc @scanon

Yep, I create a bug report: [SR-15971] Negative integer literal converted to generic unsigned integer type without warning - Swift

3 Likes