Skip to content

Conversation

@a-viv-a
Copy link

@a-viv-a a-viv-a commented Jan 31, 2026

This commit changes canParseAsGenericArgumentList such that the guard no longer returns early for '<>' which is a single token when the brackets aren't seperated by a space, which fixes #68290.

Also adds a test case for this behavior and enables a generic disambiguation test with no params, since this affects all use of generics in expressions.

With this PR, code like this works:

struct T<each U> {}
let _ = T<>()
T<>.self

There is some cause for concern about interacting with infix and postfix <> operators; I think this change doesn't pose an issue for that since my read of the surrounding code is that the token is only treated like a generic if it has a disambiguating token after it, but in a future where .self is dropped a decision might need to be made about which to prefer in some cases, and allowing T<>.self now would make it especially surprising to not allow T<> in that future.

SwiftParser explicitly excludes this case and will need to be updated if allowing this is the direction to go in.

This commit changes canParseAsGenericArgumentList such that the guard no
longer returns early for '<>' which is a single token when the brackets
aren't seperated by a space.

Also adds a test case for this behavior and enables a generic
disambiguation test with no params, since this affects all use of
generics in expressions.
@a-viv-a a-viv-a force-pushed the empty-generic-param-pack-support branch from 46ab215 to 64787d0 Compare January 31, 2026 03:37
@hamishknight
Copy link
Contributor

hamishknight commented Jan 31, 2026

There is some cause for concern about interacting with infix and postfix <> operators; I think this change doesn't pose an issue for that since my read of the surrounding code is that the token is only treated like a generic if it has a disambiguating token after it

The disambiguation token doesn't necessarily help us here since you can do things like this today (note that when parsing we don't know if the LHS is a type or value):

infix operator <>
func <> <T> (lhs: T, rhs: T) {}

postfix operator <>
postfix func <> <T> (lhs: T) -> T { lhs }

func foo(_ i: Int, _ xs: (Int, Int)) {
  xs<>(0, 1)
  i <> .zero
  _ = i<>.isMultiple(of: 2)
}

I think we need to investigate to see how often these cases come up in practice, if they're extremely rare then we can probably get away with handling it in the parser. Otherwise we might have to resolve this semantically based on whether the LHS is resolved to a TypeExpr (similar to what we do for protocol composition types). It would definitely be nice to recognize this in the parser though since this would also allow us to model it in the swift-syntax tree, and would avoid further complicating pre-checking.

@a-viv-a
Copy link
Author

a-viv-a commented Feb 2, 2026

Any ideas on how to approach that @hamishknight? I see ~179 examples on GitHub right now via code search which would get broken... probably more that aren't in public repos. if we did this after the parser we could save some or all of these yeah. I wonder if it would be defensible to ban <> as an operator in a future version? Could let the meta types be unambiguous too. Otherwise this would probably need to be a special check since I don't think doing it in the parser could be source compatible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Referring to a type with an empty generic parameter pack causes "Cannot find operator '<>' in scope" error.

2 participants