Skip to content

Commit 722d136

Browse files
committed
Use hir::Map to prevent false positives
1 parent bafa89b commit 722d136

File tree

3 files changed

+58
-40
lines changed

3 files changed

+58
-40
lines changed

compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs

Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -524,8 +524,8 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
524524
if self.not_enough_args_provided() {
525525
self.suggest_adding_args(err);
526526
} else if self.too_many_args_provided() {
527+
self.suggest_moving_args_from_assoc_fn_to_trait(err);
527528
self.suggest_removing_args_or_generics(err);
528-
self.suggest_moving_args(err);
529529
} else {
530530
unreachable!();
531531
}
@@ -661,34 +661,62 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
661661
/// ```compile_fail
662662
/// Into::into::<Option<_>>(42) // suggests considering `Into::<Option<_>>::into(42)`
663663
/// ```
664-
fn suggest_moving_args(&self, err: &mut Diagnostic) {
665-
if let Some(trait_) = self.tcx.trait_of_item(self.def_id) {
666-
// HACK(hkmatsumoto): Ugly way to tell "<trait>::<assoc fn>()" from "x.<assoc fn>()";
667-
// we don't care the latter (for now).
668-
if self.path_segment.res == Some(hir::def::Res::Err) {
669-
return;
670-
}
671-
672-
// Say, if the assoc fn takes `A`, `B` and `C` as generic arguments while expecting 1
673-
// argument, and its trait expects 2 arguments. It is hard to "split" them right as
674-
// there are too many cases to handle: `A` `B` | `C`, `A` `B` | `C`, `A` `C` | `B`, ...
675-
let num_assoc_fn_expected_args =
676-
self.num_expected_type_or_const_args() + self.num_expected_lifetime_args();
677-
if num_assoc_fn_expected_args > 0 {
678-
return;
679-
}
664+
fn suggest_moving_args_from_assoc_fn_to_trait(&self, err: &mut Diagnostic) {
665+
let trait_ = match self.tcx.trait_of_item(self.def_id) {
666+
Some(def_id) => def_id,
667+
None => return,
668+
};
680669

681-
let num_assoc_fn_excess_args =
682-
self.num_excess_type_or_const_args() + self.num_excess_lifetime_args();
670+
// Skip suggestion when the associated function is itself generic, it is unclear
671+
// how to split the provided parameters between those to suggest to the trait and
672+
// those to remain on the associated type.
673+
let num_assoc_fn_expected_args =
674+
self.num_expected_type_or_const_args() + self.num_expected_lifetime_args();
675+
if num_assoc_fn_expected_args > 0 {
676+
return;
677+
}
683678

684-
let trait_generics = self.tcx.generics_of(trait_);
685-
let num_trait_generics_except_self =
686-
trait_generics.count() - if trait_generics.has_self { 1 } else { 0 };
679+
let num_assoc_fn_excess_args =
680+
self.num_excess_type_or_const_args() + self.num_excess_lifetime_args();
681+
682+
let trait_generics = self.tcx.generics_of(trait_);
683+
let num_trait_generics_except_self =
684+
trait_generics.count() - if trait_generics.has_self { 1 } else { 0 };
685+
686+
if let Some(hir_id) = self.path_segment.hir_id
687+
&& let Some(parent_node) = self.tcx.hir().find_parent_node(hir_id)
688+
&& let Some(parent_node) = self.tcx.hir().find(parent_node)
689+
&& let hir::Node::Expr(expr) = parent_node {
690+
match expr.kind {
691+
hir::ExprKind::Path(ref qpath) => {
692+
self.suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path(
693+
err,
694+
trait_,
695+
qpath,
696+
num_assoc_fn_excess_args,
697+
num_trait_generics_except_self
698+
)
699+
},
700+
// TODO(hkmatsumoto): Emit similar suggestion for "x.<assoc fn>()"
701+
hir::ExprKind::MethodCall(..) => return,
702+
_ => return,
703+
}
704+
}
705+
}
687706

688-
// FIXME(hkmatsumoto): RHS of this condition ideally should be
689-
// `num_trait_generics_except_self` - "# of generic args already provided to trait"
690-
// but unable to get that information with `self.def_id`.
691-
if num_assoc_fn_excess_args == num_trait_generics_except_self {
707+
fn suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path(
708+
&self,
709+
err: &mut Diagnostic,
710+
trait_: DefId,
711+
qpath: &'tcx hir::QPath<'tcx>,
712+
num_assoc_fn_excess_args: usize,
713+
num_trait_generics_except_self: usize,
714+
) {
715+
if let hir::QPath::Resolved(_, path) = qpath
716+
&& let Some(trait_path_segment) = path.segments.get(0) {
717+
let num_generic_args_supplied_to_trait = trait_path_segment.args().num_generic_params();
718+
719+
if num_assoc_fn_excess_args == num_trait_generics_except_self - num_generic_args_supplied_to_trait {
692720
if let Some(span) = self.gen_args.span_ext()
693721
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
694722
let msg = format!(

src/test/ui/suggestions/issue-89064.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,7 @@ fn main() {
2424
//~| HELP remove these generics
2525
//~| HELP consider moving these generic arguments
2626

27-
// bad suggestion
2827
let _ = A::<S>::foo::<S>();
2928
//~^ ERROR
3029
//~| HELP remove these generics
31-
//~| HELP consider moving this generic argument
3230
}

src/test/ui/suggestions/issue-89064.stderr

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,26 +43,18 @@ LL + let _ = B::<S, S>::bar();
4343
|
4444

4545
error[E0107]: this associated function takes 0 generic arguments but 1 generic argument was supplied
46-
--> $DIR/issue-89064.rs:28:21
46+
--> $DIR/issue-89064.rs:27:21
4747
|
4848
LL | let _ = A::<S>::foo::<S>();
49-
| ^^^ expected 0 generic arguments
49+
| ^^^----- help: remove these generics
50+
| |
51+
| expected 0 generic arguments
5052
|
5153
note: associated function defined here, with 0 generic parameters
5254
--> $DIR/issue-89064.rs:4:8
5355
|
5456
LL | fn foo() {}
5557
| ^^^
56-
help: remove these generics
57-
|
58-
LL - let _ = A::<S>::foo::<S>();
59-
LL + let _ = A::<S>::foo();
60-
|
61-
help: consider moving this generic argument to the `A` trait, which takes up to 1 argument
62-
|
63-
LL - let _ = A::<S>::foo::<S>();
64-
LL + let _ = A::<S>::<S>::foo();
65-
|
6658

6759
error: aborting due to 3 previous errors
6860

0 commit comments

Comments
 (0)