Skip to content

Commit 81b1997

Browse files
authored
Unrolled build for #144801
Rollup merge of #144801 - estebank:issue-144734, r=spastorino Suggest bounds in more cases, accounting for type parameters referenced in predicate Use a `ty::Visitor` to see if the failed predicate references a type parameter. If it does, then we only suggest adding a bound to an (associated) item only if the referenced parameter is present in its generics. Provide adding bound suggestion in trait and impl associated functions in cases we previously weren't: ``` error[E0277]: `?` couldn't convert the error to `ApplicationError` --> $DIR/suggest-complex-bound-on-method.rs:18:16 | LL | t.run()?; | -----^ the trait `From<<T as Trait>::Error>` is not implemented for `ApplicationError` | | | this can't be annotated with `?` because it has type `Result<_, <T as Trait>::Error>` | note: `ApplicationError` needs to implement `From<<T as Trait>::Error>` --> $DIR/suggest-complex-bound-on-method.rs:12:1 | LL | enum ApplicationError { | ^^^^^^^^^^^^^^^^^^^^^ = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement | LL | fn thing<T: Trait>(&self, t: T) -> Result<(), ApplicationError> where ApplicationError: From<<T as Trait>::Error> { | +++++++++++++++++++++++++++++++++++++++++++++++++ ``` Fix #144734.
2 parents 0d0f4ea + fa6986e commit 81b1997

File tree

6 files changed

+136
-14
lines changed

6 files changed

+136
-14
lines changed

compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs

Lines changed: 67 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ use rustc_middle::ty::print::{
3232
};
3333
use rustc_middle::ty::{
3434
self, AdtKind, GenericArgs, InferTy, IsSuggestable, Ty, TyCtxt, TypeFoldable, TypeFolder,
35-
TypeSuperFoldable, TypeVisitableExt, TypeckResults, Upcast, suggest_arbitrary_trait_bound,
36-
suggest_constraining_type_param,
35+
TypeSuperFoldable, TypeSuperVisitable, TypeVisitableExt, TypeVisitor, TypeckResults, Upcast,
36+
suggest_arbitrary_trait_bound, suggest_constraining_type_param,
3737
};
3838
use rustc_middle::{bug, span_bug};
3939
use rustc_span::def_id::LocalDefId;
@@ -263,6 +263,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
263263
_ => (false, None),
264264
};
265265

266+
let mut finder = ParamFinder { .. };
267+
finder.visit_binder(&trait_pred);
268+
266269
// FIXME: Add check for trait bound that is already present, particularly `?Sized` so we
267270
// don't suggest `T: Sized + ?Sized`.
268271
loop {
@@ -411,6 +414,26 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
411414
}
412415
}
413416

417+
hir::Node::TraitItem(hir::TraitItem {
418+
generics,
419+
kind: hir::TraitItemKind::Fn(..),
420+
..
421+
})
422+
| hir::Node::ImplItem(hir::ImplItem {
423+
generics,
424+
trait_item_def_id: None,
425+
kind: hir::ImplItemKind::Fn(..),
426+
..
427+
}) if finder.can_suggest_bound(generics) => {
428+
// Missing generic type parameter bound.
429+
suggest_arbitrary_trait_bound(
430+
self.tcx,
431+
generics,
432+
err,
433+
trait_pred,
434+
associated_ty,
435+
);
436+
}
414437
hir::Node::Item(hir::Item {
415438
kind:
416439
hir::ItemKind::Struct(_, generics, _)
@@ -423,7 +446,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
423446
| hir::ItemKind::Const(_, generics, _, _)
424447
| hir::ItemKind::TraitAlias(_, generics, _),
425448
..
426-
}) if !param_ty => {
449+
}) if finder.can_suggest_bound(generics) => {
427450
// Missing generic type parameter bound.
428451
if suggest_arbitrary_trait_bound(
429452
self.tcx,
@@ -5068,8 +5091,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
50685091
// Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a
50695092
// borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);`
50705093
// is not. Look for invalid "bare" parameter uses, and suggest using indirection.
5071-
let mut visitor =
5072-
FindTypeParam { param: param.name.ident().name, invalid_spans: vec![], nested: false };
5094+
let mut visitor = FindTypeParam { param: param.name.ident().name, .. };
50735095
visitor.visit_item(item);
50745096
if visitor.invalid_spans.is_empty() {
50755097
return false;
@@ -5228,7 +5250,7 @@ fn hint_missing_borrow<'tcx>(
52285250
/// Used to suggest replacing associated types with an explicit type in `where` clauses.
52295251
#[derive(Debug)]
52305252
pub struct SelfVisitor<'v> {
5231-
pub paths: Vec<&'v hir::Ty<'v>>,
5253+
pub paths: Vec<&'v hir::Ty<'v>> = Vec::new(),
52325254
pub name: Option<Symbol>,
52335255
}
52345256

@@ -5599,7 +5621,7 @@ fn point_at_assoc_type_restriction<G: EmissionGuarantee>(
55995621
);
56005622
// Search for the associated type `Self::{name}`, get
56015623
// its type and suggest replacing the bound with it.
5602-
let mut visitor = SelfVisitor { paths: vec![], name: Some(name) };
5624+
let mut visitor = SelfVisitor { name: Some(name), .. };
56035625
visitor.visit_trait_ref(trait_ref);
56045626
for path in visitor.paths {
56055627
err.span_suggestion_verbose(
@@ -5610,7 +5632,7 @@ fn point_at_assoc_type_restriction<G: EmissionGuarantee>(
56105632
);
56115633
}
56125634
} else {
5613-
let mut visitor = SelfVisitor { paths: vec![], name: None };
5635+
let mut visitor = SelfVisitor { name: None, .. };
56145636
visitor.visit_trait_ref(trait_ref);
56155637
let span: MultiSpan =
56165638
visitor.paths.iter().map(|p| p.span).collect::<Vec<Span>>().into();
@@ -5640,8 +5662,8 @@ fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) {
56405662
/// `param: ?Sized` would be a valid constraint.
56415663
struct FindTypeParam {
56425664
param: rustc_span::Symbol,
5643-
invalid_spans: Vec<Span>,
5644-
nested: bool,
5665+
invalid_spans: Vec<Span> = Vec::new(),
5666+
nested: bool = false,
56455667
}
56465668

56475669
impl<'v> Visitor<'v> for FindTypeParam {
@@ -5679,3 +5701,38 @@ impl<'v> Visitor<'v> for FindTypeParam {
56795701
}
56805702
}
56815703
}
5704+
5705+
/// Look for type parameters in predicates. We use this to identify whether a bound is suitable in
5706+
/// on a given item.
5707+
struct ParamFinder {
5708+
params: Vec<Symbol> = Vec::new(),
5709+
}
5710+
5711+
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParamFinder {
5712+
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
5713+
match t.kind() {
5714+
ty::Param(p) => self.params.push(p.name),
5715+
_ => {}
5716+
}
5717+
t.super_visit_with(self)
5718+
}
5719+
}
5720+
5721+
impl ParamFinder {
5722+
/// Whether the `hir::Generics` of the current item can suggest the evaluated bound because its
5723+
/// references to type parameters are present in the generics.
5724+
fn can_suggest_bound(&self, generics: &hir::Generics<'_>) -> bool {
5725+
if self.params.is_empty() {
5726+
// There are no references to type parameters at all, so suggesting the bound
5727+
// would be reasonable.
5728+
return true;
5729+
}
5730+
generics.params.iter().any(|p| match p.name {
5731+
hir::ParamName::Plain(p_name) => {
5732+
// All of the parameters in the bound can be referenced in the current item.
5733+
self.params.iter().any(|p| *p == p_name.name || *p == kw::SelfUpper)
5734+
}
5735+
_ => true,
5736+
})
5737+
}
5738+
}

compiler/rustc_trait_selection/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#![feature(assert_matches)]
2020
#![feature(associated_type_defaults)]
2121
#![feature(box_patterns)]
22+
#![feature(default_field_values)]
2223
#![feature(if_let_guard)]
2324
#![feature(iter_intersperse)]
2425
#![feature(iterator_try_reduce)]

tests/ui/const-generics/failing_goal_with_repeat_expr_anon_const.stderr

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,6 @@ LL | [0u8; std::mem::size_of::<Self::A>()] == Self::P;
2121
| ^^ no implementation for `[u8; std::mem::size_of::<Self::A>()] == <Self as T>::A`
2222
|
2323
= help: the trait `PartialEq<<Self as T>::A>` is not implemented for `[u8; std::mem::size_of::<Self::A>()]`
24-
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
25-
|
26-
LL | pub trait T where [u8; std::mem::size_of::<Self::A>()]: PartialEq<<Self as T>::A> {
27-
| +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2824

2925
error: aborting due to 3 previous errors
3026

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//@ run-rustfix
2+
#![allow(dead_code)]
3+
struct Application;
4+
// https://github.com/rust-lang/rust/issues/144734
5+
trait Trait {
6+
type Error: std::error::Error;
7+
8+
fn run(&self) -> Result<(), Self::Error>;
9+
}
10+
11+
#[derive(Debug)]
12+
enum ApplicationError {
13+
Quit,
14+
}
15+
16+
impl Application {
17+
fn thing<T: Trait>(&self, t: T) -> Result<(), ApplicationError> where ApplicationError: From<<T as Trait>::Error> {
18+
t.run()?; //~ ERROR E0277
19+
Ok(())
20+
}
21+
}
22+
23+
fn main() {}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//@ run-rustfix
2+
#![allow(dead_code)]
3+
struct Application;
4+
// https://github.com/rust-lang/rust/issues/144734
5+
trait Trait {
6+
type Error: std::error::Error;
7+
8+
fn run(&self) -> Result<(), Self::Error>;
9+
}
10+
11+
#[derive(Debug)]
12+
enum ApplicationError {
13+
Quit,
14+
}
15+
16+
impl Application {
17+
fn thing<T: Trait>(&self, t: T) -> Result<(), ApplicationError> {
18+
t.run()?; //~ ERROR E0277
19+
Ok(())
20+
}
21+
}
22+
23+
fn main() {}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0277]: `?` couldn't convert the error to `ApplicationError`
2+
--> $DIR/suggest-complex-bound-on-method.rs:18:16
3+
|
4+
LL | t.run()?;
5+
| -----^ the trait `From<<T as Trait>::Error>` is not implemented for `ApplicationError`
6+
| |
7+
| this can't be annotated with `?` because it has type `Result<_, <T as Trait>::Error>`
8+
|
9+
note: `ApplicationError` needs to implement `From<<T as Trait>::Error>`
10+
--> $DIR/suggest-complex-bound-on-method.rs:12:1
11+
|
12+
LL | enum ApplicationError {
13+
| ^^^^^^^^^^^^^^^^^^^^^
14+
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
15+
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
16+
|
17+
LL | fn thing<T: Trait>(&self, t: T) -> Result<(), ApplicationError> where ApplicationError: From<<T as Trait>::Error> {
18+
| +++++++++++++++++++++++++++++++++++++++++++++++++
19+
20+
error: aborting due to 1 previous error
21+
22+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)