Is this a compiler bug?

I expected this code to compile:

extension Sequence where Element: Numeric {
    
    func product () -> Element {
        self.reduce(into: .init(integerLiteral: 1)) { $0 *= $1 }
    }
}

But I'm hit with this error:

Why would the Element itself need to conform to _ExpressibleByBuiltinIntegerLiteral when the protocol ExpressibleByIntegerLiteral requires only that the IntegerLiteral associated type conforms to it?

That initializer requires its argument to be of the associated type IntegerLiteralType, which conforms to the underscored protocol.

The initializer is declared as a protocol requirement here in CompilerProtocols.swift.

A default implementation is provided here in Integers.swift, but only when Self conforms to the underscored protocol.

Now, the underscored protocol does not refine ExpressibleByIntegerLiteral. In other words, there is no requirement that a type which conforms to the underscored protocol needs to be expressible by an integer literal.

In your example, Element.IntegerLiteralType conforms to the underscored protocol, but it is not constrained to conform to ExpressibleByIntegerLiteral.

So when the compiler sees that you are attempting to pass the integer literal 1 into the initializer, the only candidate it finds is the default implementation. But that is not a match, for the reason shown in the error message.

In summary, this is not a compiler error. Try writing this instead:

extension Sequence where Element: Numeric {
  func product () -> Element {
    reduce(into: 1, *=)
  }
}

Or this:

extension Sequence where Element: Numeric {
  func product () -> Element {
    reduce(1, *)
  }
}
1 Like

Awesome, thanks a lot for updated code! That's really all I need, but out of curiosity:

I was assuming that if a type conforms to _ExpressibleByBuiltinIntegerLiteral then I would be able to pass the literal 1 anywhere that a value of that type is required and it would work.

Does this sentence of yours mean precisely that what I was assuming is not true?

Indeed.