Skip to content

Commit

Permalink
Rollup merge of rust-lang#91208 - estebank:eq-constraint, r=cjgillot
Browse files Browse the repository at this point in the history
Account for incorrect `where T::Assoc = Ty` bound

Provide suggestoin to constrain trait bound for associated type.
Revert incorrect changes to `missing-bounds` test.

Address part of rust-lang#20041.
  • Loading branch information
matthiaskrgr committed Nov 27, 2021
2 parents 55f8b5f + 4954389 commit 7c5bcd5
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 6 deletions.
49 changes: 48 additions & 1 deletion compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Span;
use rustc_target::spec::abi;
use std::mem;
use std::ops::DerefMut;
use std::ops::{Deref, DerefMut};

const MORE_EXTERN: &str =
"for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
Expand Down Expand Up @@ -1714,6 +1714,53 @@ fn deny_equality_constraints(
}
}
}
// Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
if let [potential_param, potential_assoc] = &full_path.segments[..] {
for param in &generics.params {
if param.ident == potential_param.ident {
for bound in &param.bounds {
if let ast::GenericBound::Trait(trait_ref, TraitBoundModifier::None) = bound
{
if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] {
let assoc = pprust::path_to_string(&ast::Path::from_ident(
potential_assoc.ident,
));
let ty = pprust::ty_to_string(&predicate.rhs_ty);
let (args, span) = match &trait_segment.args {
Some(args) => match args.deref() {
ast::GenericArgs::AngleBracketed(args) => {
let Some(arg) = args.args.last() else {
continue;
};
(
format!(", {} = {}", assoc, ty),
arg.span().shrink_to_hi(),
)
}
_ => continue,
},
None => (
format!("<{} = {}>", assoc, ty),
trait_segment.span().shrink_to_hi(),
),
};
err.multipart_suggestion(
&format!(
"if `{}::{}` is an associated type you're trying to set, \
use the associated type binding syntax",
trait_segment.ident, potential_assoc.ident,
),
vec![(span, args), (predicate.span, String::new())],
Applicability::MaybeIncorrect,
);
}
}
}
}
}
}
}
err.note(
"see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information",
);
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast_passes/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#![feature(iter_is_partitioned)]
#![feature(box_patterns)]
#![feature(let_else)]
#![recursion_limit = "256"]

pub mod ast_validation;
Expand Down
15 changes: 15 additions & 0 deletions src/test/ui/generic-associated-types/equality-bound.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
fn sum<I: Iterator<Item = ()>>(i: I) -> i32 where I::Item = i32 {
//~^ ERROR equality constraints are not yet supported in `where` clauses
panic!()
}
fn sum2<I: Iterator>(i: I) -> i32 where I::Item = i32 {
//~^ ERROR equality constraints are not yet supported in `where` clauses
panic!()
}
fn sum3<J: Iterator>(i: J) -> i32 where I::Item = i32 {
//~^ ERROR equality constraints are not yet supported in `where` clauses
//~| ERROR failed to resolve: use of undeclared type `I`
panic!()
}

fn main() {}
43 changes: 43 additions & 0 deletions src/test/ui/generic-associated-types/equality-bound.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
error: equality constraints are not yet supported in `where` clauses
--> $DIR/equality-bound.rs:1:51
|
LL | fn sum<I: Iterator<Item = ()>>(i: I) -> i32 where I::Item = i32 {
| ^^^^^^^^^^^^^ not supported
|
= note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
help: if `Iterator::Item` is an associated type you're trying to set, use the associated type binding syntax
|
LL - fn sum<I: Iterator<Item = ()>>(i: I) -> i32 where I::Item = i32 {
LL + fn sum<I: Iterator<Item = (), Item = i32>>(i: I) -> i32 where {
|

error: equality constraints are not yet supported in `where` clauses
--> $DIR/equality-bound.rs:5:41
|
LL | fn sum2<I: Iterator>(i: I) -> i32 where I::Item = i32 {
| ^^^^^^^^^^^^^ not supported
|
= note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
help: if `Iterator::Item` is an associated type you're trying to set, use the associated type binding syntax
|
LL - fn sum2<I: Iterator>(i: I) -> i32 where I::Item = i32 {
LL + fn sum2<I: Iterator<Item = i32>>(i: I) -> i32 where {
|

error: equality constraints are not yet supported in `where` clauses
--> $DIR/equality-bound.rs:9:41
|
LL | fn sum3<J: Iterator>(i: J) -> i32 where I::Item = i32 {
| ^^^^^^^^^^^^^ not supported
|
= note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information

error[E0433]: failed to resolve: use of undeclared type `I`
--> $DIR/equality-bound.rs:9:41
|
LL | fn sum3<J: Iterator>(i: J) -> i32 where I::Item = i32 {
| ^ use of undeclared type `I`

error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0433`.
5 changes: 3 additions & 2 deletions src/test/ui/generic-associated-types/missing-bounds.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,12 @@ impl<B: std::ops::Add<Output = B>> Add for D<B> {

struct E<B>(B);

impl<B: Add> Add for E<B> where B: Add<Output = B> {
impl<B: Add> Add for E<B> where B: Add<Output = B>, B: Add<Output = B> {
//~^ ERROR equality constraints are not yet supported in `where` clauses
type Output = Self;

fn add(self, rhs: Self) -> Self {
Self(self.0 + rhs.0)
Self(self.0 + rhs.0) //~ ERROR mismatched types
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/test/ui/generic-associated-types/missing-bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,12 @@ impl<B> Add for D<B> {

struct E<B>(B);

impl<B: Add> Add for E<B> where B: Add<Output = B> {
impl<B: Add> Add for E<B> where <B as Add>::Output = B {
//~^ ERROR equality constraints are not yet supported in `where` clauses
type Output = Self;

fn add(self, rhs: Self) -> Self {
Self(self.0 + rhs.0)
Self(self.0 + rhs.0) //~ ERROR mismatched types
}
}

Expand Down
30 changes: 29 additions & 1 deletion src/test/ui/generic-associated-types/missing-bounds.stderr
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
error: equality constraints are not yet supported in `where` clauses
--> $DIR/missing-bounds.rs:37:33
|
LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B {
| ^^^^^^^^^^^^^^^^^^^^^^ not supported
|
= note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
help: if `Output` is an associated type you're trying to set, use the associated type binding syntax
|
LL | impl<B: Add> Add for E<B> where B: Add<Output = B> {
| ~~~~~~~~~~~~~~~~~~

error[E0308]: mismatched types
--> $DIR/missing-bounds.rs:11:11
|
Expand Down Expand Up @@ -43,7 +55,23 @@ help: consider restricting type parameter `B`
LL | impl<B: std::ops::Add<Output = B>> Add for D<B> {
| +++++++++++++++++++++++++++

error: aborting due to 3 previous errors
error[E0308]: mismatched types
--> $DIR/missing-bounds.rs:42:14
|
LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B {
| - this type parameter
...
LL | Self(self.0 + rhs.0)
| ^^^^^^^^^^^^^^ expected type parameter `B`, found associated type
|
= note: expected type parameter `B`
found associated type `<B as Add>::Output`
help: consider further restricting type parameter `B`
|
LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B, B: Add<Output = B> {
| ++++++++++++++++++++

error: aborting due to 5 previous errors

Some errors have detailed explanations: E0308, E0369.
For more information about an error, try `rustc --explain E0308`.

0 comments on commit 7c5bcd5

Please sign in to comment.