mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 08:44:35 +00:00
On incorrect equality constraint likely to be assoc type, suggest appropriate syntax
When encountering `where <A as Foo>::Bar = B`, it is possible that `Bar` is an associated type. If so, suggest `where A: Foo<Bar = B>`. CC #20041.
This commit is contained in:
parent
3453db7bfc
commit
d8d02f8f18
@ -23,6 +23,7 @@ use rustc_session::Session;
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
use rustc_span::Span;
|
||||
use std::mem;
|
||||
use std::ops::DerefMut;
|
||||
|
||||
const MORE_EXTERN: &str =
|
||||
"for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
|
||||
@ -1113,17 +1114,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
|
||||
for predicate in &generics.where_clause.predicates {
|
||||
if let WherePredicate::EqPredicate(ref predicate) = *predicate {
|
||||
self.err_handler()
|
||||
.struct_span_err(
|
||||
predicate.span,
|
||||
"equality constraints are not yet supported in `where` clauses",
|
||||
)
|
||||
.span_label(predicate.span, "not supported")
|
||||
.note(
|
||||
"see issue #20041 <https://github.com/rust-lang/rust/issues/20041> \
|
||||
for more information",
|
||||
)
|
||||
.emit();
|
||||
deny_equality_constraints(self, predicate, generics);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1300,6 +1291,87 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn deny_equality_constraints(
|
||||
this: &mut AstValidator<'_>,
|
||||
predicate: &WhereEqPredicate,
|
||||
generics: &Generics,
|
||||
) {
|
||||
let mut err = this.err_handler().struct_span_err(
|
||||
predicate.span,
|
||||
"equality constraints are not yet supported in `where` clauses",
|
||||
);
|
||||
err.span_label(predicate.span, "not supported");
|
||||
|
||||
// Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
|
||||
if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind {
|
||||
if let TyKind::Path(None, path) = &qself.ty.kind {
|
||||
match &path.segments[..] {
|
||||
[PathSegment { ident, args: None, .. }] => {
|
||||
for param in &generics.params {
|
||||
if param.ident == *ident {
|
||||
let param = ident;
|
||||
match &full_path.segments[qself.position..] {
|
||||
[PathSegment { ident, .. }] => {
|
||||
// Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
|
||||
let mut assoc_path = full_path.clone();
|
||||
// Remove `Bar` from `Foo::Bar`.
|
||||
assoc_path.segments.pop();
|
||||
let len = assoc_path.segments.len() - 1;
|
||||
// Build `<Bar = RhsTy>`.
|
||||
let arg = AngleBracketedArg::Constraint(AssocTyConstraint {
|
||||
id: rustc_ast::node_id::DUMMY_NODE_ID,
|
||||
ident: *ident,
|
||||
kind: AssocTyConstraintKind::Equality {
|
||||
ty: predicate.rhs_ty.clone(),
|
||||
},
|
||||
span: ident.span,
|
||||
});
|
||||
// Add `<Bar = RhsTy>` to `Foo`.
|
||||
match &mut assoc_path.segments[len].args {
|
||||
Some(args) => match args.deref_mut() {
|
||||
GenericArgs::Parenthesized(_) => continue,
|
||||
GenericArgs::AngleBracketed(args) => {
|
||||
args.args.push(arg);
|
||||
}
|
||||
},
|
||||
empty_args => {
|
||||
*empty_args = AngleBracketedArgs {
|
||||
span: ident.span,
|
||||
args: vec![arg],
|
||||
}
|
||||
.into();
|
||||
}
|
||||
}
|
||||
err.span_suggestion_verbose(
|
||||
predicate.span,
|
||||
&format!(
|
||||
"if `{}` is an associated type you're trying to set, \
|
||||
use the associated type binding syntax",
|
||||
ident
|
||||
),
|
||||
format!(
|
||||
"{}: {}",
|
||||
param,
|
||||
pprust::path_to_string(&assoc_path)
|
||||
),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
err.note(
|
||||
"see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information",
|
||||
);
|
||||
err.emit();
|
||||
}
|
||||
|
||||
pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
|
||||
let mut validator = AstValidator {
|
||||
session,
|
||||
|
@ -32,4 +32,15 @@ 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>, B: std::ops::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) //~ ERROR mismatched types
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -32,4 +32,15 @@ impl<B> Add for D<B> {
|
||||
}
|
||||
}
|
||||
|
||||
struct E<B>(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) //~ ERROR mismatched types
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -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
|
||||
|
|
||||
@ -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 std::ops::Add>::Output`
|
||||
help: consider further restricting type parameter `B`
|
||||
|
|
||||
LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B, B: std::ops::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`.
|
||||
|
Loading…
Reference in New Issue
Block a user