From 4954389a9dccf2e915a639155b7039f1454acc9c Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Thu, 25 Nov 2021 01:38:05 +0000 Subject: [PATCH] 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 #20041. --- .../rustc_ast_passes/src/ast_validation.rs | 49 ++++++++++++++++++- compiler/rustc_ast_passes/src/lib.rs | 1 + .../equality-bound.rs | 15 ++++++ .../equality-bound.stderr | 43 ++++++++++++++++ .../missing-bounds.fixed | 5 +- .../missing-bounds.rs | 5 +- .../missing-bounds.stderr | 30 +++++++++++- 7 files changed, 142 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/generic-associated-types/equality-bound.rs create mode 100644 src/test/ui/generic-associated-types/equality-bound.stderr diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 1822ba6ec9964..efc30121987e2 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -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"; @@ -1714,6 +1714,53 @@ fn deny_equality_constraints( } } } + // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo`. + 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 ¶m.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 for more information", ); diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index 47666670b2b63..adc4d117b805f 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -6,6 +6,7 @@ #![feature(iter_is_partitioned)] #![feature(box_patterns)] +#![feature(let_else)] #![recursion_limit = "256"] pub mod ast_validation; diff --git a/src/test/ui/generic-associated-types/equality-bound.rs b/src/test/ui/generic-associated-types/equality-bound.rs new file mode 100644 index 0000000000000..fcc2da8014f87 --- /dev/null +++ b/src/test/ui/generic-associated-types/equality-bound.rs @@ -0,0 +1,15 @@ +fn sum>(i: I) -> i32 where I::Item = i32 { +//~^ ERROR equality constraints are not yet supported in `where` clauses + panic!() +} +fn sum2(i: I) -> i32 where I::Item = i32 { +//~^ ERROR equality constraints are not yet supported in `where` clauses + panic!() +} +fn sum3(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() {} diff --git a/src/test/ui/generic-associated-types/equality-bound.stderr b/src/test/ui/generic-associated-types/equality-bound.stderr new file mode 100644 index 0000000000000..27432641958bd --- /dev/null +++ b/src/test/ui/generic-associated-types/equality-bound.stderr @@ -0,0 +1,43 @@ +error: equality constraints are not yet supported in `where` clauses + --> $DIR/equality-bound.rs:1:51 + | +LL | fn sum>(i: I) -> i32 where I::Item = i32 { + | ^^^^^^^^^^^^^ not supported + | + = note: see issue #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: I) -> i32 where I::Item = i32 { +LL + fn sum>(i: I) -> i32 where { + | + +error: equality constraints are not yet supported in `where` clauses + --> $DIR/equality-bound.rs:5:41 + | +LL | fn sum2(i: I) -> i32 where I::Item = i32 { + | ^^^^^^^^^^^^^ not supported + | + = note: see issue #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: I) -> i32 where I::Item = i32 { +LL + fn sum2>(i: I) -> i32 where { + | + +error: equality constraints are not yet supported in `where` clauses + --> $DIR/equality-bound.rs:9:41 + | +LL | fn sum3(i: J) -> i32 where I::Item = i32 { + | ^^^^^^^^^^^^^ not supported + | + = note: see issue #20041 for more information + +error[E0433]: failed to resolve: use of undeclared type `I` + --> $DIR/equality-bound.rs:9:41 + | +LL | fn sum3(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`. diff --git a/src/test/ui/generic-associated-types/missing-bounds.fixed b/src/test/ui/generic-associated-types/missing-bounds.fixed index 54478d1628245..0e234120a51c5 100644 --- a/src/test/ui/generic-associated-types/missing-bounds.fixed +++ b/src/test/ui/generic-associated-types/missing-bounds.fixed @@ -34,11 +34,12 @@ impl> Add for D { struct E(B); -impl Add for E where B: Add { +impl Add for E where B: Add, B: Add { + //~^ 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 } } diff --git a/src/test/ui/generic-associated-types/missing-bounds.rs b/src/test/ui/generic-associated-types/missing-bounds.rs index 962d2db9476bd..ffafff5e9f586 100644 --- a/src/test/ui/generic-associated-types/missing-bounds.rs +++ b/src/test/ui/generic-associated-types/missing-bounds.rs @@ -34,11 +34,12 @@ impl Add for D { struct E(B); -impl Add for E where B: Add { +impl Add for E where ::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 } } diff --git a/src/test/ui/generic-associated-types/missing-bounds.stderr b/src/test/ui/generic-associated-types/missing-bounds.stderr index 4d33fe84829e0..c9603b8d1ea4a 100644 --- a/src/test/ui/generic-associated-types/missing-bounds.stderr +++ b/src/test/ui/generic-associated-types/missing-bounds.stderr @@ -1,3 +1,15 @@ +error: equality constraints are not yet supported in `where` clauses + --> $DIR/missing-bounds.rs:37:33 + | +LL | impl Add for E where ::Output = B { + | ^^^^^^^^^^^^^^^^^^^^^^ not supported + | + = note: see issue #20041 for more information +help: if `Output` is an associated type you're trying to set, use the associated type binding syntax + | +LL | impl Add for E where B: Add { + | ~~~~~~~~~~~~~~~~~~ + error[E0308]: mismatched types --> $DIR/missing-bounds.rs:11:11 | @@ -43,7 +55,23 @@ help: consider restricting type parameter `B` LL | impl> Add for D { | +++++++++++++++++++++++++++ -error: aborting due to 3 previous errors +error[E0308]: mismatched types + --> $DIR/missing-bounds.rs:42:14 + | +LL | impl Add for E where ::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 `::Output` +help: consider further restricting type parameter `B` + | +LL | impl Add for E where ::Output = B, B: Add { + | ++++++++++++++++++++ + +error: aborting due to 5 previous errors Some errors have detailed explanations: E0308, E0369. For more information about an error, try `rustc --explain E0308`.