Xcode 8 beta 6.
I have the following code. The only difference between 1, 2, 3, 4 and 5 is what is in the 'metrics' parameter.
let a = 20
// 1: This compiles.
_ = NSLayoutConstraint.constraints(withVisualFormat: "|[v1(a)]|", metrics: ["a": 20], views: ["v1": v1])
// 2: This fails with "Cannot convert value of type 'Int' to expected dictionary value type 'NSNumber'".
_ = NSLayoutConstraint.constraints(withVisualFormat: "|[v1(a)]|", metrics: ["a": a], views: ["v1": v1])
let met = ["a": a]
// 3: This fails with "Cannot convert value of type '[String: Int]' to expected argument type '[String: NSNumber]?'".
_ = NSLayoutConstraint.constraints(withVisualFormat: "|[v1(a)]|", metrics: met, views: ["v1": v1])
// 4: This compiles.
_ = NSLayoutConstraint.constraints(withVisualFormat: "|[v1(a)]|", metrics: met as [String: NSNumber]?, views: ["v1": v1])
// 5: This fails with "Cannot convert value of type 'Int' to expected dictionary value type 'NSNumber'".
_ = NSLayoutConstraint.constraints(withVisualFormat: "|[v1(a)]|", metrics: ["a": a] as [String: NSNumber]?, views: ["v1": v1])
Why does 1 compile, but 2 does not?
Why does 1 compile, but 3 does not?
Why does 4 compile, but 5 does not?
Your #1 works because "20" is typeless, and type inference from the expected type (NSNumber) finds a NSNumber initializer that takes a numeric literal. So, the "20" literal can be treated as a NSNumber value automatically.
Your definition of a:
let a = 20
requires the compiler to infer the type of a, and it chooses Int. It's not typeless like "20" is. (Well, 20 isn't typeless, it's a compile-time-numeric-literal type, but you know what I mean.)
Formerly, the Swift compiler would automatically bridge (that is, convert the type and value) from Swift types to certain Obj-C types, so it could handle an Int where it expected a NSNumber. This implicit behavior has recently been removed, so now you have to code the bridging explictly ("a as NSNumber").