Why: calling SwiftUI.Color(red:green:blue:alpha:) compiler can infer param type is Double, but calling with .init(red:green:blue:alpha) it cannot and must use explicit Double literal

I have my own type named Color, so instead of using SwiftUI.Color to disambiguate, in the context where the SwiftUI.Color type is known, I tried just .init(red:green:blue:alpha):

import SwiftUI

let a1 = LinearGradient(
    gradient: Gradient(colors: [Color(red:   3 / 255, green: 251 / 255, blue: 232 / 255),   // Calling Color(...), it can infer parameter type
                                .init(red: 215 / 255, green:   3 / 255, blue: 252 / 255),   // Calling .init(...), it cannot infer parameter type is double
                                //         ^^^ error: cannot convert value of type 'Int' to expected argument type 'Double'
                                .init(red: 252.0 / 255, green: 202.0 / 255, blue:   3.0 / 255)  // must explicitly use Double literal
                               ]),
    startPoint: .topLeading, endPoint: .bottomTrailing)

with .init(...), the compiler should know the red:green:blue:alpha parameters are Double, but it appears it cannot tell.

:thinking:

looks like compiler bug. minimal example without swiftUI dependencies:

struct S {
	init(_ v: Double) {}
}
func foo(_ v: S) {}
func bar(_ v: [S]) {}
let s: S = .init(1/2)   // ok
foo(.init(1/2))         // ok
bar([S(1/2)])           // ok
bar([.init(1/2)]) // Cannot convert value of type 'Int' to expected argument type 'Double'
1 Like

Do you think this is the same bug: [SR-15221] Whole number literal type inference fail, maybe due to SE-0307 CGFloat/Double Interchangeable? · Issue #57543 · apple/swift · GitHub

no, SR-15221 is very different and more convoluted.

shorter form:

import SwiftUI
    
struct SomeView: View {
	let width: CGFloat = 0

	func foo(_ v: Double) -> some View {
		EmptyView()
	}

	// not ok
	var body: some View {
		foo(2 * width / 3)   // Error: Ambiguous use of operator '/'
	}

	// ok
//    var body: some View {
//        foo(2 * width / 3) // yet this is ok
//        return EmptyView()
//    }
}
1 Like
2 Likes