Out of curiosity, I conducted some experiments about ExpressibleByIntegerLiteral
and type inference.
Given the following code:
struct MyUInt: ExpressibleByIntegerLiteral {
// Not conforms to `AdditiveArithmetic`
typealias IntegerLiteralType = UInt
init(integerLiteral: IntegerLiteralType) {}
}
struct MyPlusInt {}
extension MyUInt {
static prefix func +(_: MyUInt) -> MyPlusInt { .init() }
}
struct MyMinusInt {}
extension MyUInt {
static prefix func -(_: MyUInt) -> MyMinusInt { .init() }
}
func f(_: MyUInt) { print("Unsigned") }
func f(_: MyPlusInt) { print("+") }
func f(_: MyMinusInt) { print("-") }
@freestanding(expression) macro m(_: MyUInt) -> UInt = #externalMacro(module: "MyMacros", type: "MyWonderfulMacro")
@freestanding(expression) macro m(_: MyPlusInt) -> UInt = #externalMacro(module: "MyMacros", type: "MyWonderfulMacro")
@freestanding(expression) macro m(_: MyMinusInt) -> Int = #externalMacro(module: "MyMacros", type: "MyWonderfulMacro")
/* (0) */ let _: MyUInt = -1 // โ error: negative integer '-1' overflows when stored into unsigned type 'MyUInt'
/* (1) */ let _: MyUInt = 1 // โ
OK
/* (2) */ let _: MyPlusInt = +1 // โ
OK
/* (3) */ let _: MyMinusInt = -1 // โ error: cannot convert value of type 'Int' to specified type 'MyMinusInt'
/* (4) */ let _: MyMinusInt = -(1) // โ
OK
/* (i) */ f(1) // โ
Prints "Unsigned"
/* (ii) */ f(+1) // โ
Prints "+"
/* (iii) */ f(-1) // โ error: negative integer '-1' overflows when stored into unsigned type 'MyUInt'
/* (iv) */ f(-(1)) // โ
Prints "-"
/* (I) */ let _ = #m(1) // โ
`m(_: MyUInt) -> UInt` is chosen.
/* (II) */ let _ = #m(+1) // โ
`m(_: MyPlusInt) -> UInt` is chosen.
/* (III) */ let _ = #m(-1) // ๐คฏ `m(_: MyUInt) -> UInt` is chosen. ๐โ
/* (IV) */ let _ = #m(-(1)) // โ
`m(_: MyMinusInt) -> Int` is chosen.
Results and thoughts.
Results are described as the comments in the code.
My consideration is below:
(0)
: It is an error as I expected.(3)
: As left side is explicit about the type, I want the compiler to infer the type like(4)
.(iii)
: Same as above.(III)
: The weirdest thing happened! WhileMyUInt
must not be negative as the compiler said in(0)
, the compiler chosem(_: MyUInt) -> UInt
macro that takes an argument with typeMyUInt
. I'm not sure why.
Do you expect these results?