Hey, I'm very new to Swift, learning it for use in Ladybird and so far I like it :)
One thing I've noticed is that generics in expressions uses the Type<T> syntax and not something like turbofishType::<T> (or Type.<T> which seems more appropriate for Swift).
This makes this code snippet not highlight in Zed (which is using tree-sitter based on this grammar):
not highlight correctly (Optional should be green).
I wanted to ask if this means that that parsing cannot be done without more first doing type checking or other analysis (which is a problem e.g. c++ has with generics, and it makes it hard to parse for tools such as tree-sitter that does not perform deeper analysis of the language (like the above screenshot), and potentially confusing error messages from the compiler for subtle syntax and type errors).
At a glance Type<T>.variant seems like it could be parsed as Type < T > .variant, but I couldn't get something like this to compile, does Swift have strict and coherent rules for how this is handled, and if so are they specified somewhere?
I don’t remember the details but the ambiguity you refer to is resolved by some combination of rules, one of which is that binary operators must have consistent spacing on both sides, so T> U is not a valid operator expression for example.
Another thing that helps here is that < and > are in the same precedence group, which means that you must use parentheses to specify which operation should be performed first in a < b > c. So generic argument lists could never be valid expression-level syntax.
Now that I think about it, the fixity and precedence of operators doesn’t enter the picture because those are not looked up and resolved until Sema time either. From reading the code I believe it simply tries to parse a generic parameter list first in any position where one may appear, and if this fails, it parses the < as an operator.
Right. Swift borrows a trick from C# where it parses ahead after a < to see if there’s something that looks like a type list followed by a > and then a member access (an opening bracket or .); if that condition holds, then the text is parsed as a generic parameter list. This isn’t foolproof since (a < b, c > (d)) or (a < b, c > .d) are potentially valid tuple expressions in Swift too, but so far nobody seems to have noticed (to my knowledge).