Skip to content

Bounds parsing refactoring 2#39158

Merged
bors merged 5 commits into
rust-lang:masterfrom
petrochenkov:bounds
Jan 27, 2017
Merged

Bounds parsing refactoring 2#39158
bors merged 5 commits into
rust-lang:masterfrom
petrochenkov:bounds

Conversation

@petrochenkov

@petrochenkov petrochenkov commented Jan 18, 2017

Copy link
Copy Markdown
Contributor

See #37511 for previous discussion.
cc @matklad

Relaxed parsing rules:

  • zero bounds after : are allowed in all contexts.
  • zero predicates are allowed after where.
  • trailing separator , is allowed after predicates in where clauses not followed by {.

Other parsing rules:

  • trailing separator + is still allowed in all bound lists.

Code is also cleaned up and tests added.

I haven't touched parsing of trait object types yet, I'll do it later.

@rust-highfive

Copy link
Copy Markdown
Contributor

r? @nikomatsakis

(rust_highfive has picked a reviewer for you, use r? to override)

@durka

durka commented Jan 18, 2017

Copy link
Copy Markdown
Contributor

Why disallow trailing + when trailing , is allowed? Does it create an ambiguity?

@petrochenkov

Copy link
Copy Markdown
Contributor Author

@durka
No ambiguity, it's a lang team decision.

(I'd personally keep it though, because 1) uniformity (other trailing separators are allowed), 2) it was accepted since 1.0 until now, 3) it's "naturally" allowed and you have to add extra code to the parser to prohibit it)

@petrochenkov

Copy link
Copy Markdown
Contributor Author

@durka
Do you have an example of trailing + being useful in macros?

@durka

durka commented Jan 18, 2017 via email

Copy link
Copy Markdown
Contributor

@durka

durka commented Jan 18, 2017 via email

Copy link
Copy Markdown
Contributor

@petrochenkov

Copy link
Copy Markdown
Contributor Author

But then again you don't want "1 + 1 +" to be a valid
arithmetic expression.

Expression + and type + are actually different! 🙂
Expression + is a binary operator and lists like 1 + 1 + 1 + 1 are desugared into several operator applications ((1 + 1) + 1) + 1.
Type + is not a binary operator and summands in lists like Trait + Trait + Trait can't be grouped. (Trait + Trait) + Trait and ArbitraryType + Trait in general are not valid.

@nikomatsakis

Copy link
Copy Markdown
Contributor

@petrochenkov I feel like I would keep it too -- which is probably why it's parsed in the first place. I wonder if it's worth revisiting this. I found your three points convincing, and I'm not sure that we focus on the backwards compatibility point in the meeting.

cc @rust-lang/lang -- we had previously decided to not accept T: Foo + Bar + (where + acts as a trailing separator) because it "looks weird" (which is indisputably true). However, @petrochenkov points out that it is accepted today (also indisputably true). "Looking weird" doesn't feel like reason enough to break backwards compatibility to me, particularly since accepting trailing separators is known to be useful for macros. So I think I'd like to revisit this decision. What do people think?

@withoutboats

Copy link
Copy Markdown
Contributor

I think when we agreed on that we thought we were talking about expanding what is accepted to include trailing +. I agree we shouldn't break the language.

@joshtriplett

Copy link
Copy Markdown
Member

@nikomatsakis If we accept this today, we should continue doing so, and document it for potential use by macros. Not worth breaking backward compatibility over.

@aturon

aturon commented Jan 21, 2017

Copy link
Copy Markdown
Contributor

@nikomatsakis I agree with your reasoning; let's keep it.

@nikomatsakis

Copy link
Copy Markdown
Contributor

@petrochenkov care to update the PR to accept trailing +?

@nrc you were the main one who objected, I think, so I'd like to get your input in particular

(Does anyone feel we need to use rfcbot here?)

@nrc

nrc commented Jan 23, 2017

Copy link
Copy Markdown
Member

@nikomatsakis yeah, I agree its not worth breaking for.

@petrochenkov

Copy link
Copy Markdown
Contributor Author

Updated with trailing +s permitted.

@nikomatsakis

Copy link
Copy Markdown
Contributor

@bors r+

Thanks @petrochenkov !

@bors

bors commented Jan 25, 2017

Copy link
Copy Markdown
Collaborator

📌 Commit 65aeafa has been approved by nikomatsakis

@nikomatsakis

Copy link
Copy Markdown
Contributor

@bors r-

@nikomatsakis

Copy link
Copy Markdown
Contributor

Oops :) had one thing I wanted to ask

}
}
for predicate in &g.where_clause.predicates {
if let WherePredicate::EqPredicate(ref predicate) = *predicate {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

heh, we should really remove this variant from the compiler (and parser)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to be clear, not as part of this PR =)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are no plans to implement this?
Then #20041 should be officially closed or something before removing WherePredicate::EqPredicate.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, eventually perhaps, but at the moment there are some theoretical limitations that I do not yet know how to overcome. I would say "we may implement it eventually, but in that case we can add that stuff back in to the compiler".

Comment thread src/libsyntax/parse/parser.rs Outdated
self.expect_and()?;
self.parse_borrowed_pointee()?
} else if self.check_keyword(keywords::For) {
// FIXME plus priority

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you clarify what this FIXME means? Ideally, if there's an actual bug we care about here, we'd open an issue describing what is going on. Otherwise, maybe just leave it out. =)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+ still has high priority in some cases.

The first case is when trait object type starts with for:

trait Tr<'a> {}
fn f(arg: &for<'a> Tr<'a> + Send){} // Parsed as &(for<'a> Tr<'a> + Send)

I'm going to fix this in upcoming PR so I didn't create an issue.

The second case is impl Trait1 + Trait2 and it seems to be known.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated with better comments for FIXMEs.

@nikomatsakis

Copy link
Copy Markdown
Contributor

@bors r+

@bors

bors commented Jan 26, 2017

Copy link
Copy Markdown
Collaborator

📌 Commit bd4d5ec has been approved by nikomatsakis

@bors

bors commented Jan 26, 2017

Copy link
Copy Markdown
Collaborator

⌛ Testing commit bd4d5ec with merge d68ec42...

@bors

bors commented Jan 26, 2017

Copy link
Copy Markdown
Collaborator

💔 Test failed - status-travis

@alexcrichton

alexcrichton commented Jan 26, 2017 via email

Copy link
Copy Markdown
Member

@bors

bors commented Jan 27, 2017

Copy link
Copy Markdown
Collaborator

⌛ Testing commit bd4d5ec with merge 989cc5d...

@alexcrichton

Copy link
Copy Markdown
Member

@bors: retry

  • fiddling with homu

@bors

bors commented Jan 27, 2017

Copy link
Copy Markdown
Collaborator

⌛ Testing commit bd4d5ec with merge 23a9469...

bors added a commit that referenced this pull request Jan 27, 2017
Bounds parsing refactoring 2

See #37511 for previous discussion.
cc @matklad

Relaxed parsing rules:
 - zero bounds after `:` are allowed in all contexts.
 - zero predicates are allowed after `where`.
- trailing separator `,` is allowed after predicates in `where` clauses not followed by `{`.

Other parsing rules:
 - trailing separator `+` is still allowed in all bound lists.

Code is also cleaned up and tests added.

I haven't touched parsing of trait object types yet, I'll do it later.
@bors

bors commented Jan 27, 2017

Copy link
Copy Markdown
Collaborator

☀️ Test successful - status-appveyor, status-travis
Approved by: nikomatsakis
Pushing 23a9469 to master...

@bors bors merged commit bd4d5ec into rust-lang:master Jan 27, 2017
@petrochenkov petrochenkov deleted the bounds branch March 16, 2017 19:43
matklad added a commit to intellij-rust/intellij-rust that referenced this pull request Mar 21, 2017
@bors

bors commented Apr 12, 2017

Copy link
Copy Markdown
Collaborator

💥 Test timed out

JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Jun 7, 2026
Syntactically reject equality predicates

### Background (History)

Equality predicates have been *syntactically* valid since PR rust-lang#39158 / nightly-2017-02-02 / 1.16 (released 2017-03-16, 9 years ago), both forms that is: `$ty = $ty` *and* `$ty == $ty`. They're not registered as an unstable feature despite having a tracking issue (rust-lang#20041). Naturally, they don't have a feature gate. Of course, we reject them post-expansion, so they are still semantically invalid.

Parser scaffolding for `$ident = $ty` was added in RUST-19391 (2014) which was then generalized to `$ty = $ty` in RUST-20002 (2014) and extended to additionally cover `$ty == $ty` in RUST-39158 (2017). As mentioned, the last PR also made them grammatical.

RUST-87471 (2021) attempted to start impl'ing typeck'ing but it was closed due to concerns: rust-lang#87471 (comment) (already back in 2017 there were concerns: https://github.com/rust-lang/rust/pull/39158/changes#r97811244).

In 2022, T-lang discussed this feature during a meeting and raised concerns: rust-lang#20041 (comment). However, they were inclined to accept a restricted form, namely `T::AssocTy = $ty` (`T` is a (self) ty param or a self ty alias) and `<$ty as Trait>::AssocTy = $ty` since that's trivial to support in HIR ty lowering (this is still accurate).

### Change

This renders equality predicates `$ty = $ty` and `$ty == $ty` syntactically invalid again. On stable, they're merely semantically invalid. This is motivated by the fact that

1. their syntax isn't even decided upon
   1. should it be `=` or `==`?
   2. should the LHS be syntactically restricted to (possibly qualified) paths (i.e., *TypePath | QualifiedPathInType*), only semantically or not at all?
      * "syntactically" could indeed make sense since we might want to generalize types to so-called *terms* here (i.e., *Type | GenericArgsConst*) for [mGCA](rust-lang#132980) but we can't generalize `$ty = $ty` to `$term = $term` due to ambiguities [^1] that would require backtracking whereas `$typepath = $term` wouldn't have that problem
2. we might (decide to) never impl this feature
   * after all, implementation concerns were raised as early as 9 years ago which are still relevant today even with the next-gen trait solver on the horizon
3. the compiler + tools contain a bunch of code for dealing with these predicates
   * like lowering, name resolution, rustfmt and Clippy
   * that's entirely useless since they get unconditionally rejected anyway
   * this code doesn't need to exist (for now)

I've merely upgraded the semantic hard error to a syntactic hard error, I've intentionally not introduced an unstable feature under which equality predicates become legal.

That's because a hard error is easier to push through procedurally, it's an important first step (we can always turn it into a feature gate error later on) and since this potential feature isn't backed by any official lang experiment.

I don't consider T-lang's message rust-lang#20041 (comment) from 2022 to be sufficient because it doesn't answer questions like (1.i), (1.ii) or whether code like `T: Trait<A>, <T as Trait<B>>::AssocTy = Ty` (`A` ≠ `B`) or `T: Trait<'r>, for<'a> <T as Trait<'a>>::AssocTy = Ty` should be legal (which would be more powerful / could lead to typechecking issues, idk) or not assuming we're going with the restricted form ofc (we would need input from T-types).

### Lang nomination

rust-lang#153513 (comment)

[^1]: Code lile `fn f() -> i32 where { 0 }` is intentionally legal today but if we had `$term = $term` the `{ 0 }` could then also be the start of an equality predicate like `{ 0 } = 0`.
jhpratt added a commit to jhpratt/rust that referenced this pull request Jun 7, 2026
Syntactically reject equality predicates

### Background (History)

Equality predicates have been *syntactically* valid since PR rust-lang#39158 / nightly-2017-02-02 / 1.16 (released 2017-03-16, 9 years ago), both forms that is: `$ty = $ty` *and* `$ty == $ty`. They're not registered as an unstable feature despite having a tracking issue (rust-lang#20041). Naturally, they don't have a feature gate. Of course, we reject them post-expansion, so they are still semantically invalid.

Parser scaffolding for `$ident = $ty` was added in RUST-19391 (2014) which was then generalized to `$ty = $ty` in RUST-20002 (2014) and extended to additionally cover `$ty == $ty` in RUST-39158 (2017). As mentioned, the last PR also made them grammatical.

RUST-87471 (2021) attempted to start impl'ing typeck'ing but it was closed due to concerns: rust-lang#87471 (comment) (already back in 2017 there were concerns: https://github.com/rust-lang/rust/pull/39158/changes#r97811244).

In 2022, T-lang discussed this feature during a meeting and raised concerns: rust-lang#20041 (comment). However, they were inclined to accept a restricted form, namely `T::AssocTy = $ty` (`T` is a (self) ty param or a self ty alias) and `<$ty as Trait>::AssocTy = $ty` since that's trivial to support in HIR ty lowering (this is still accurate).

### Change

This renders equality predicates `$ty = $ty` and `$ty == $ty` syntactically invalid again. On stable, they're merely semantically invalid. This is motivated by the fact that

1. their syntax isn't even decided upon
   1. should it be `=` or `==`?
   2. should the LHS be syntactically restricted to (possibly qualified) paths (i.e., *TypePath | QualifiedPathInType*), only semantically or not at all?
      * "syntactically" could indeed make sense since we might want to generalize types to so-called *terms* here (i.e., *Type | GenericArgsConst*) for [mGCA](rust-lang#132980) but we can't generalize `$ty = $ty` to `$term = $term` due to ambiguities [^1] that would require backtracking whereas `$typepath = $term` wouldn't have that problem
2. we might (decide to) never impl this feature
   * after all, implementation concerns were raised as early as 9 years ago which are still relevant today even with the next-gen trait solver on the horizon
3. the compiler + tools contain a bunch of code for dealing with these predicates
   * like lowering, name resolution, rustfmt and Clippy
   * that's entirely useless since they get unconditionally rejected anyway
   * this code doesn't need to exist (for now)

I've merely upgraded the semantic hard error to a syntactic hard error, I've intentionally not introduced an unstable feature under which equality predicates become legal.

That's because a hard error is easier to push through procedurally, it's an important first step (we can always turn it into a feature gate error later on) and since this potential feature isn't backed by any official lang experiment.

I don't consider T-lang's message rust-lang#20041 (comment) from 2022 to be sufficient because it doesn't answer questions like (1.i), (1.ii) or whether code like `T: Trait<A>, <T as Trait<B>>::AssocTy = Ty` (`A` ≠ `B`) or `T: Trait<'r>, for<'a> <T as Trait<'a>>::AssocTy = Ty` should be legal (which would be more powerful / could lead to typechecking issues, idk) or not assuming we're going with the restricted form ofc (we would need input from T-types).

### Lang nomination

rust-lang#153513 (comment)

[^1]: Code lile `fn f() -> i32 where { 0 }` is intentionally legal today but if we had `$term = $term` the `{ 0 }` could then also be the start of an equality predicate like `{ 0 } = 0`.
jhpratt added a commit to jhpratt/rust that referenced this pull request Jun 7, 2026
Syntactically reject equality predicates

### Background (History)

Equality predicates have been *syntactically* valid since PR rust-lang#39158 / nightly-2017-02-02 / 1.16 (released 2017-03-16, 9 years ago), both forms that is: `$ty = $ty` *and* `$ty == $ty`. They're not registered as an unstable feature despite having a tracking issue (rust-lang#20041). Naturally, they don't have a feature gate. Of course, we reject them post-expansion, so they are still semantically invalid.

Parser scaffolding for `$ident = $ty` was added in RUST-19391 (2014) which was then generalized to `$ty = $ty` in RUST-20002 (2014) and extended to additionally cover `$ty == $ty` in RUST-39158 (2017). As mentioned, the last PR also made them grammatical.

RUST-87471 (2021) attempted to start impl'ing typeck'ing but it was closed due to concerns: rust-lang#87471 (comment) (already back in 2017 there were concerns: https://github.com/rust-lang/rust/pull/39158/changes#r97811244).

In 2022, T-lang discussed this feature during a meeting and raised concerns: rust-lang#20041 (comment). However, they were inclined to accept a restricted form, namely `T::AssocTy = $ty` (`T` is a (self) ty param or a self ty alias) and `<$ty as Trait>::AssocTy = $ty` since that's trivial to support in HIR ty lowering (this is still accurate).

### Change

This renders equality predicates `$ty = $ty` and `$ty == $ty` syntactically invalid again. On stable, they're merely semantically invalid. This is motivated by the fact that

1. their syntax isn't even decided upon
   1. should it be `=` or `==`?
   2. should the LHS be syntactically restricted to (possibly qualified) paths (i.e., *TypePath | QualifiedPathInType*), only semantically or not at all?
      * "syntactically" could indeed make sense since we might want to generalize types to so-called *terms* here (i.e., *Type | GenericArgsConst*) for [mGCA](rust-lang#132980) but we can't generalize `$ty = $ty` to `$term = $term` due to ambiguities [^1] that would require backtracking whereas `$typepath = $term` wouldn't have that problem
2. we might (decide to) never impl this feature
   * after all, implementation concerns were raised as early as 9 years ago which are still relevant today even with the next-gen trait solver on the horizon
3. the compiler + tools contain a bunch of code for dealing with these predicates
   * like lowering, name resolution, rustfmt and Clippy
   * that's entirely useless since they get unconditionally rejected anyway
   * this code doesn't need to exist (for now)

I've merely upgraded the semantic hard error to a syntactic hard error, I've intentionally not introduced an unstable feature under which equality predicates become legal.

That's because a hard error is easier to push through procedurally, it's an important first step (we can always turn it into a feature gate error later on) and since this potential feature isn't backed by any official lang experiment.

I don't consider T-lang's message rust-lang#20041 (comment) from 2022 to be sufficient because it doesn't answer questions like (1.i), (1.ii) or whether code like `T: Trait<A>, <T as Trait<B>>::AssocTy = Ty` (`A` ≠ `B`) or `T: Trait<'r>, for<'a> <T as Trait<'a>>::AssocTy = Ty` should be legal (which would be more powerful / could lead to typechecking issues, idk) or not assuming we're going with the restricted form ofc (we would need input from T-types).

### Lang nomination

rust-lang#153513 (comment)

[^1]: Code like `fn f() -> i32 where { 0 }` is intentionally legal today but if we had `$term = $term` the `{ 0 }` could then also be the start of an equality predicate like `{ 0 } = 0`.
rust-timer added a commit that referenced this pull request Jun 8, 2026
Rollup merge of #153513 - fmease:gate-eq-pred, r=jackh726

Syntactically reject equality predicates

### Background (History)

Equality predicates have been *syntactically* valid since PR #39158 / nightly-2017-02-02 / 1.16 (released 2017-03-16, 9 years ago), both forms that is: `$ty = $ty` *and* `$ty == $ty`. They're not registered as an unstable feature despite having a tracking issue (#20041). Naturally, they don't have a feature gate. Of course, we reject them post-expansion, so they are still semantically invalid.

Parser scaffolding for `$ident = $ty` was added in RUST-19391 (2014) which was then generalized to `$ty = $ty` in RUST-20002 (2014) and extended to additionally cover `$ty == $ty` in RUST-39158 (2017). As mentioned, the last PR also made them grammatical.

RUST-87471 (2021) attempted to start impl'ing typeck'ing but it was closed due to concerns: #87471 (comment) (already back in 2017 there were concerns: https://github.com/rust-lang/rust/pull/39158/changes#r97811244).

In 2022, T-lang discussed this feature during a meeting and raised concerns: #20041 (comment). However, they were inclined to accept a restricted form, namely `T::AssocTy = $ty` (`T` is a (self) ty param or a self ty alias) and `<$ty as Trait>::AssocTy = $ty` since that's trivial to support in HIR ty lowering (this is still accurate).

### Change

This renders equality predicates `$ty = $ty` and `$ty == $ty` syntactically invalid again. On stable, they're merely semantically invalid. This is motivated by the fact that

1. their syntax isn't even decided upon
   1. should it be `=` or `==`?
   2. should the LHS be syntactically restricted to (possibly qualified) paths (i.e., *TypePath | QualifiedPathInType*), only semantically or not at all?
      * "syntactically" could indeed make sense since we might want to generalize types to so-called *terms* here (i.e., *Type | GenericArgsConst*) for [mGCA](#132980) but we can't generalize `$ty = $ty` to `$term = $term` due to ambiguities [^1] that would require backtracking whereas `$typepath = $term` wouldn't have that problem
2. we might (decide to) never impl this feature
   * after all, implementation concerns were raised as early as 9 years ago which are still relevant today even with the next-gen trait solver on the horizon
3. the compiler + tools contain a bunch of code for dealing with these predicates
   * like lowering, name resolution, rustfmt and Clippy
   * that's entirely useless since they get unconditionally rejected anyway
   * this code doesn't need to exist (for now)

I've merely upgraded the semantic hard error to a syntactic hard error, I've intentionally not introduced an unstable feature under which equality predicates become legal.

That's because a hard error is easier to push through procedurally, it's an important first step (we can always turn it into a feature gate error later on) and since this potential feature isn't backed by any official lang experiment.

I don't consider T-lang's message #20041 (comment) from 2022 to be sufficient because it doesn't answer questions like (1.i), (1.ii) or whether code like `T: Trait<A>, <T as Trait<B>>::AssocTy = Ty` (`A` ≠ `B`) or `T: Trait<'r>, for<'a> <T as Trait<'a>>::AssocTy = Ty` should be legal (which would be more powerful / could lead to typechecking issues, idk) or not assuming we're going with the restricted form ofc (we would need input from T-types).

### Lang nomination

#153513 (comment)

[^1]: Code like `fn f() -> i32 where { 0 }` is intentionally legal today but if we had `$term = $term` the `{ 0 }` could then also be the start of an equality predicate like `{ 0 } = 0`.
github-actions Bot pushed a commit to rust-lang/stdarch that referenced this pull request Jun 8, 2026
Syntactically reject equality predicates

### Background (History)

Equality predicates have been *syntactically* valid since PR rust-lang/rust#39158 / nightly-2017-02-02 / 1.16 (released 2017-03-16, 9 years ago), both forms that is: `$ty = $ty` *and* `$ty == $ty`. They're not registered as an unstable feature despite having a tracking issue (rust-lang/rust#20041). Naturally, they don't have a feature gate. Of course, we reject them post-expansion, so they are still semantically invalid.

Parser scaffolding for `$ident = $ty` was added in RUST-19391 (2014) which was then generalized to `$ty = $ty` in RUST-20002 (2014) and extended to additionally cover `$ty == $ty` in RUST-39158 (2017). As mentioned, the last PR also made them grammatical.

RUST-87471 (2021) attempted to start impl'ing typeck'ing but it was closed due to concerns: rust-lang/rust#87471 (comment) (already back in 2017 there were concerns: https://github.com/rust-lang/rust/pull/39158/changes#r97811244).

In 2022, T-lang discussed this feature during a meeting and raised concerns: rust-lang/rust#20041 (comment). However, they were inclined to accept a restricted form, namely `T::AssocTy = $ty` (`T` is a (self) ty param or a self ty alias) and `<$ty as Trait>::AssocTy = $ty` since that's trivial to support in HIR ty lowering (this is still accurate).

### Change

This renders equality predicates `$ty = $ty` and `$ty == $ty` syntactically invalid again. On stable, they're merely semantically invalid. This is motivated by the fact that

1. their syntax isn't even decided upon
   1. should it be `=` or `==`?
   2. should the LHS be syntactically restricted to (possibly qualified) paths (i.e., *TypePath | QualifiedPathInType*), only semantically or not at all?
      * "syntactically" could indeed make sense since we might want to generalize types to so-called *terms* here (i.e., *Type | GenericArgsConst*) for [mGCA](rust-lang/rust#132980) but we can't generalize `$ty = $ty` to `$term = $term` due to ambiguities [^1] that would require backtracking whereas `$typepath = $term` wouldn't have that problem
2. we might (decide to) never impl this feature
   * after all, implementation concerns were raised as early as 9 years ago which are still relevant today even with the next-gen trait solver on the horizon
3. the compiler + tools contain a bunch of code for dealing with these predicates
   * like lowering, name resolution, rustfmt and Clippy
   * that's entirely useless since they get unconditionally rejected anyway
   * this code doesn't need to exist (for now)

I've merely upgraded the semantic hard error to a syntactic hard error, I've intentionally not introduced an unstable feature under which equality predicates become legal.

That's because a hard error is easier to push through procedurally, it's an important first step (we can always turn it into a feature gate error later on) and since this potential feature isn't backed by any official lang experiment.

I don't consider T-lang's message rust-lang/rust#20041 (comment) from 2022 to be sufficient because it doesn't answer questions like (1.i), (1.ii) or whether code like `T: Trait<A>, <T as Trait<B>>::AssocTy = Ty` (`A` ≠ `B`) or `T: Trait<'r>, for<'a> <T as Trait<'a>>::AssocTy = Ty` should be legal (which would be more powerful / could lead to typechecking issues, idk) or not assuming we're going with the restricted form ofc (we would need input from T-types).

### Lang nomination

rust-lang/rust#153513 (comment)

[^1]: Code like `fn f() -> i32 where { 0 }` is intentionally legal today but if we had `$term = $term` the `{ 0 }` could then also be the start of an equality predicate like `{ 0 } = 0`.
asukaminato0721 pushed a commit to asukaminato0721/rust-analyzer that referenced this pull request Jun 8, 2026
Syntactically reject equality predicates

### Background (History)

Equality predicates have been *syntactically* valid since PR rust-lang/rust#39158 / nightly-2017-02-02 / 1.16 (released 2017-03-16, 9 years ago), both forms that is: `$ty = $ty` *and* `$ty == $ty`. They're not registered as an unstable feature despite having a tracking issue (rust-lang/rust#20041). Naturally, they don't have a feature gate. Of course, we reject them post-expansion, so they are still semantically invalid.

Parser scaffolding for `$ident = $ty` was added in RUST-19391 (2014) which was then generalized to `$ty = $ty` in RUST-20002 (2014) and extended to additionally cover `$ty == $ty` in RUST-39158 (2017). As mentioned, the last PR also made them grammatical.

RUST-87471 (2021) attempted to start impl'ing typeck'ing but it was closed due to concerns: rust-lang/rust#87471 (comment) (already back in 2017 there were concerns: https://github.com/rust-lang/rust/pull/39158/changes#r97811244).

In 2022, T-lang discussed this feature during a meeting and raised concerns: rust-lang/rust#20041 (comment). However, they were inclined to accept a restricted form, namely `T::AssocTy = $ty` (`T` is a (self) ty param or a self ty alias) and `<$ty as Trait>::AssocTy = $ty` since that's trivial to support in HIR ty lowering (this is still accurate).

### Change

This renders equality predicates `$ty = $ty` and `$ty == $ty` syntactically invalid again. On stable, they're merely semantically invalid. This is motivated by the fact that

1. their syntax isn't even decided upon
   1. should it be `=` or `==`?
   2. should the LHS be syntactically restricted to (possibly qualified) paths (i.e., *TypePath | QualifiedPathInType*), only semantically or not at all?
      * "syntactically" could indeed make sense since we might want to generalize types to so-called *terms* here (i.e., *Type | GenericArgsConst*) for [mGCA](rust-lang/rust#132980) but we can't generalize `$ty = $ty` to `$term = $term` due to ambiguities [^1] that would require backtracking whereas `$typepath = $term` wouldn't have that problem
2. we might (decide to) never impl this feature
   * after all, implementation concerns were raised as early as 9 years ago which are still relevant today even with the next-gen trait solver on the horizon
3. the compiler + tools contain a bunch of code for dealing with these predicates
   * like lowering, name resolution, rustfmt and Clippy
   * that's entirely useless since they get unconditionally rejected anyway
   * this code doesn't need to exist (for now)

I've merely upgraded the semantic hard error to a syntactic hard error, I've intentionally not introduced an unstable feature under which equality predicates become legal.

That's because a hard error is easier to push through procedurally, it's an important first step (we can always turn it into a feature gate error later on) and since this potential feature isn't backed by any official lang experiment.

I don't consider T-lang's message rust-lang/rust#20041 (comment) from 2022 to be sufficient because it doesn't answer questions like (1.i), (1.ii) or whether code like `T: Trait<A>, <T as Trait<B>>::AssocTy = Ty` (`A` ≠ `B`) or `T: Trait<'r>, for<'a> <T as Trait<'a>>::AssocTy = Ty` should be legal (which would be more powerful / could lead to typechecking issues, idk) or not assuming we're going with the restricted form ofc (we would need input from T-types).

### Lang nomination

rust-lang/rust#153513 (comment)

[^1]: Code like `fn f() -> i32 where { 0 }` is intentionally legal today but if we had `$term = $term` the `{ 0 }` could then also be the start of an equality predicate like `{ 0 } = 0`.
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.

10 participants