0

Why does the following code yield an "Ambiguous use of 'foo'" compile error? I'd think that the return value makes it clear which one of the foo() overloads should be called.

Even more interestingly, why does the error disappear if I remove the print("x") line? What difference does that make?

(Xcode 10.2.1, Swift 5, default build settings for a new project.)

func foo(_: () -> Int) {}
func foo(_: () -> String) {}

func bar() {
    foo() {
        print("x")
        return 42
    }
}
imre
  • 1,667
  • 1
  • 14
  • 28
  • The type checker has special rules that only apply to single-expression closures. I'm not sure why that is, but that's what you're seeing here. – Alexander Nov 23 '19 at 22:01
  • 3
    Possibly helpful: [Why can't the Swift compiler infer this closure's type?](https://stackoverflow.com/q/42534207/1187415). – Martin R Nov 23 '19 at 22:10
  • @MartinR Yes, that link is indeed useful, thanks. – imre Nov 23 '19 at 22:13

1 Answers1

4

Type inference only applies to single-expression closures, so the compiler doesn't attempt to infer the type of the closure based on the return expression because there are two expressions (the print and the return). It then tries to infer the return type based on the return type of the closure passed to foo, but it finds two different foos and can't decide which one to use, so it then complains of an ambiguous use of foo. If you explicitly declare the type of the closure, the following code will compile:

func bar() {
    foo() { () -> Int in
        print("x")
        return 42
    }
}
Jack Lawrence
  • 10,664
  • 1
  • 47
  • 61