grammar ambiguity in closure signature

15 views
Skip to first unread message

Jon Rafkind

unread,
Apr 14, 2015, 9:46:08 PM4/14/15
to swift-l...@googlegroups.com
Swift accepts both of these closure expressions

  // Parens around the arguments
  {(a, b) -> Void in println(a)}

  // No parens
  {a, b -> Void in println(a)}

According to the grammar the signature for (a, b) should be parsed via this chain:

 closure-expression -> closure-signature -> parameter-clause

Because only parameter-clause can accept a list of things surrounded by parentheses, as opposed to identifier-list which is simply a list of comma separated identifiers. But how can parameter-clause match (a, b)?

parameter-clause is a comma separated list of parameter. parameter can basically have two forms

  id:type
  type

Where the first form allows a bunch of optional things such as 'inout', 'let', 'var', '#', etc. If the input is (a, b) and the parameter rule is used to try to match 'a' then only the second alternative consisting of 'type' would work. That means that 'a' is treated as a type node.

This 'works out' in the sense that the grammar accepts (a, b) in a closure signature, but is that really intended? It means a function that processes the closure expression syntax node must treat a parameter that only has a type as if it was an identifier.

Jon Rafkind

unread,
Apr 15, 2015, 2:38:32 PM4/15/15
to swift-l...@googlegroups.com
As far as I can tell, the 'parameter' rule is used by swift to parse the parameters in the closure signature (a, b). When a parameter matches a type-identifier that consists of a single identifier (no generics, and no dots) then that identifier is used as a binding and not a type. In all other cases, the parameter is treated as a type and no binding exists in the closure body.

  ({([Int], Int) -> Void in println(Int)})([], 2)

The first [Int] is a type because it is an array type, but the second unadorned Int is a binding. This expression prints '2'. The swift spec for 'closure expressions' says

 The parameters have the same form as the parameters in a function declaration, as described in Function Declaration.

Which may be technically true, but a function declaration does not bind a type identifier in a similar fashion to closures.

  func foo(Int){
    println(Int)
  }
  foo(2)

This prints 'Swift.Int', so Int must not be a variable but instead a plain type.

I may have missed something, but I didn't see anywhere in the spec how the binding behavior of closure parameters works.

  




--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to swift-languag...@googlegroups.com.
To post to this group, send email to swift-l...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/swift-language/24daa7a2-8304-4878-ada6-fa65dca03ff1%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages