Skip to content

Commit 83b74f2

Browse files
authored
Rollup merge of #61438 - estebank:generics-span, r=varkor
Point at individual type args on arg count mismatch - Point at individual type arguments on arg count mismatch - Make generics always have a valid span, even when there are no args - Explain that `impl Trait` introduces an implicit type argument Fix #55991.
2 parents 5599985 + 31918d6 commit 83b74f2

File tree

10 files changed

+120
-49
lines changed

10 files changed

+120
-49
lines changed

src/librustc/hir/map/mod.rs

-4
Original file line numberDiff line numberDiff line change
@@ -628,10 +628,6 @@ impl<'hir> Map<'hir> {
628628
})
629629
}
630630

631-
pub fn get_generics_span(&self, id: DefId) -> Option<Span> {
632-
self.get_generics(id).map(|generics| generics.span).filter(|sp| *sp != DUMMY_SP)
633-
}
634-
635631
/// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
636632
pub fn find(&self, id: NodeId) -> Option<Node<'hir>> {
637633
let hir_id = self.node_to_hir_id(id);

src/librustc/hir/mod.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use crate::util::nodemap::{NodeMap, FxHashSet};
1616
use crate::mir::mono::Linkage;
1717

1818
use errors::FatalError;
19-
use syntax_pos::{Span, DUMMY_SP, symbol::InternedString};
19+
use syntax_pos::{Span, DUMMY_SP, symbol::InternedString, MultiSpan};
2020
use syntax::source_map::Spanned;
2121
use rustc_target::spec::abi::Abi;
2222
use syntax::ast::{self, CrateSugar, Ident, Name, NodeId, AsmDialect};
@@ -624,6 +624,14 @@ impl Generics {
624624
}
625625
None
626626
}
627+
628+
pub fn spans(&self) -> MultiSpan {
629+
if self.params.is_empty() {
630+
self.span.into()
631+
} else {
632+
self.params.iter().map(|p| p.span).collect::<Vec<Span>>().into()
633+
}
634+
}
627635
}
628636

629637
/// Synthetic type parameters are converted to another form during lowering; this allows

src/librustc_typeck/check/compare_method.rs

+62-21
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
385385
// the moment, give a kind of vague error message.
386386
if trait_params != impl_params {
387387
let def_span = tcx.sess.source_map().def_span(span);
388-
let span = tcx.hir().get_generics_span(impl_m.def_id).unwrap_or(def_span);
388+
let span = tcx.hir().get_generics(impl_m.def_id).map(|g| g.span).unwrap_or(def_span);
389389
let mut err = struct_span_err!(
390390
tcx.sess,
391391
span,
@@ -396,7 +396,7 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
396396
err.span_label(span, "lifetimes do not match method in trait");
397397
if let Some(sp) = tcx.hir().span_if_local(trait_m.def_id) {
398398
let def_sp = tcx.sess.source_map().def_span(sp);
399-
let sp = tcx.hir().get_generics_span(trait_m.def_id).unwrap_or(def_sp);
399+
let sp = tcx.hir().get_generics(trait_m.def_id).map(|g| g.span).unwrap_or(def_sp);
400400
err.span_label(sp, "lifetimes in impl do not match this method in trait");
401401
}
402402
err.emit();
@@ -583,7 +583,7 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
583583
fn compare_number_of_generics<'a, 'tcx>(
584584
tcx: TyCtxt<'a, 'tcx, 'tcx>,
585585
impl_: &ty::AssocItem,
586-
impl_span: Span,
586+
_impl_span: Span,
587587
trait_: &ty::AssocItem,
588588
trait_span: Option<Span>,
589589
) -> Result<(), ErrorReported> {
@@ -600,17 +600,44 @@ fn compare_number_of_generics<'a, 'tcx>(
600600
if impl_count != trait_count {
601601
err_occurred = true;
602602

603-
let impl_hir_id = tcx.hir().as_local_hir_id(impl_.def_id).unwrap();
604-
let impl_item = tcx.hir().expect_impl_item(impl_hir_id);
605-
let span = if impl_item.generics.params.is_empty()
606-
|| impl_item.generics.span.is_dummy() { // argument position impl Trait (#55374)
607-
impl_span
603+
let (
604+
trait_spans,
605+
impl_trait_spans,
606+
) = if let Some(trait_hir_id) = tcx.hir().as_local_hir_id(trait_.def_id) {
607+
let trait_item = tcx.hir().expect_trait_item(trait_hir_id);
608+
if trait_item.generics.params.is_empty() {
609+
(Some(vec![trait_item.generics.span]), vec![])
610+
} else {
611+
let arg_spans: Vec<Span> = trait_item.generics.params.iter()
612+
.map(|p| p.span)
613+
.collect();
614+
let impl_trait_spans: Vec<Span> = trait_item.generics.params.iter()
615+
.filter_map(|p| match p.kind {
616+
GenericParamKind::Type {
617+
synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), ..
618+
} => Some(p.span),
619+
_ => None,
620+
}).collect();
621+
(Some(arg_spans), impl_trait_spans)
622+
}
608623
} else {
609-
impl_item.generics.span
624+
(trait_span.map(|s| vec![s]), vec![])
610625
};
611626

627+
let impl_hir_id = tcx.hir().as_local_hir_id(impl_.def_id).unwrap();
628+
let impl_item = tcx.hir().expect_impl_item(impl_hir_id);
629+
let impl_item_impl_trait_spans: Vec<Span> = impl_item.generics.params.iter()
630+
.filter_map(|p| match p.kind {
631+
GenericParamKind::Type {
632+
synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), ..
633+
} => Some(p.span),
634+
_ => None,
635+
}).collect();
636+
let spans = impl_item.generics.spans();
637+
let span = spans.primary_span();
638+
612639
let mut err = tcx.sess.struct_span_err_with_code(
613-
span,
640+
spans,
614641
&format!(
615642
"method `{}` has {} {kind} parameter{} but its trait \
616643
declaration has {} {kind} parameter{}",
@@ -626,22 +653,36 @@ fn compare_number_of_generics<'a, 'tcx>(
626653

627654
let mut suffix = None;
628655

629-
if let Some(span) = trait_span {
630-
err.span_label(
631-
span,
632-
format!("expected {} {} parameter{}", trait_count, kind,
633-
if trait_count != 1 { "s" } else { "" })
634-
);
656+
if let Some(spans) = trait_spans {
657+
let mut spans = spans.iter();
658+
if let Some(span) = spans.next() {
659+
err.span_label(*span, format!(
660+
"expected {} {} parameter{}",
661+
trait_count,
662+
kind,
663+
if trait_count != 1 { "s" } else { "" },
664+
));
665+
}
666+
for span in spans {
667+
err.span_label(*span, "");
668+
}
635669
} else {
636670
suffix = Some(format!(", expected {}", trait_count));
637671
}
638672

639-
err.span_label(
640-
span,
641-
format!("found {} {} parameter{}{}", impl_count, kind,
673+
if let Some(span) = span {
674+
err.span_label(span, format!(
675+
"found {} {} parameter{}{}",
676+
impl_count,
677+
kind,
642678
if impl_count != 1 { "s" } else { "" },
643-
suffix.unwrap_or_else(|| String::new())),
644-
);
679+
suffix.unwrap_or_else(|| String::new()),
680+
));
681+
}
682+
683+
for span in impl_trait_spans.iter().chain(impl_item_impl_trait_spans.iter()) {
684+
err.span_label(*span, "`impl Trait` introduces an implicit type parameter");
685+
}
645686

646687
err.emit();
647688
}

src/libsyntax/parse/parser.rs

+13-12
Original file line numberDiff line numberDiff line change
@@ -5050,21 +5050,22 @@ impl<'a> Parser<'a> {
50505050
/// where typaramseq = ( typaram ) | ( typaram , typaramseq )
50515051
fn parse_generics(&mut self) -> PResult<'a, ast::Generics> {
50525052
let span_lo = self.span;
5053-
if self.eat_lt() {
5053+
let (params, span) = if self.eat_lt() {
50545054
let params = self.parse_generic_params()?;
50555055
self.expect_gt()?;
5056-
Ok(ast::Generics {
5057-
params,
5058-
where_clause: WhereClause {
5059-
id: ast::DUMMY_NODE_ID,
5060-
predicates: Vec::new(),
5061-
span: DUMMY_SP,
5062-
},
5063-
span: span_lo.to(self.prev_span),
5064-
})
5056+
(params, span_lo.to(self.prev_span))
50655057
} else {
5066-
Ok(ast::Generics::default())
5067-
}
5058+
(vec![], self.prev_span.between(self.span))
5059+
};
5060+
Ok(ast::Generics {
5061+
params,
5062+
where_clause: WhereClause {
5063+
id: ast::DUMMY_NODE_ID,
5064+
predicates: Vec::new(),
5065+
span: DUMMY_SP,
5066+
},
5067+
span,
5068+
})
50685069
}
50695070

50705071
/// Parses generic args (within a path segment) with recovery for extra leading angle brackets.

src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,13 @@ LL | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d
3636
| ^^
3737

3838
error[E0195]: lifetime parameters or bounds on method `wrong_bound2` do not match the trait declaration
39-
--> $DIR/regions-bound-missing-bound-in-impl.rs:41:5
39+
--> $DIR/regions-bound-missing-bound-in-impl.rs:41:20
4040
|
4141
LL | fn wrong_bound2<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
4242
| ---------------- lifetimes in impl do not match this method in trait
4343
...
4444
LL | fn wrong_bound2(self, b: Inv, c: Inv, d: Inv) {
45-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait
45+
| ^ lifetimes do not match method in trait
4646

4747
error[E0276]: impl has stricter requirements than trait
4848
--> $DIR/regions-bound-missing-bound-in-impl.rs:48:5

src/test/ui/error-codes/E0049.rs

+10
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,15 @@ impl Foo for Bar {
88
fn foo(x: bool) -> Self { Bar } //~ ERROR E0049
99
}
1010

11+
trait Fuzz {
12+
fn fuzz<A: Default, B>(x: A, y: B) -> Self;
13+
}
14+
15+
struct Baz;
16+
17+
impl Fuzz for Baz {
18+
fn fuzz(x: bool, y: bool) -> Self { Baz } //~ ERROR E0049
19+
}
20+
1121
fn main() {
1222
}

src/test/ui/error-codes/E0049.stderr

+15-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,23 @@
11
error[E0049]: method `foo` has 0 type parameters but its trait declaration has 1 type parameter
2-
--> $DIR/E0049.rs:8:5
2+
--> $DIR/E0049.rs:8:11
33
|
44
LL | fn foo<T: Default>(x: T) -> Self;
5-
| --------------------------------- expected 1 type parameter
5+
| - expected 1 type parameter
66
...
77
LL | fn foo(x: bool) -> Self { Bar }
8-
| ^^^^^^^^^^^^^^^^^^^^^^^ found 0 type parameters
8+
| ^ found 0 type parameters
99

10-
error: aborting due to previous error
10+
error[E0049]: method `fuzz` has 0 type parameters but its trait declaration has 2 type parameters
11+
--> $DIR/E0049.rs:18:12
12+
|
13+
LL | fn fuzz<A: Default, B>(x: A, y: B) -> Self;
14+
| - -
15+
| |
16+
| expected 2 type parameters
17+
...
18+
LL | fn fuzz(x: bool, y: bool) -> Self { Baz }
19+
| ^ found 0 type parameters
20+
21+
error: aborting due to 2 previous errors
1122

1223
For more information about this error, try `rustc --explain E0049`.

src/test/ui/issues/issue-36708.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0049]: method `foo` has 1 type parameter but its trait declaration has 0 type parameters
2-
--> $DIR/issue-36708.rs:8:11
2+
--> $DIR/issue-36708.rs:8:12
33
|
44
LL | fn foo<T>() {}
5-
| ^^^ found 1 type parameter, expected 0
5+
| ^ found 1 type parameter, expected 0
66

77
error: aborting due to previous error
88

src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.rs

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ impl Foo for u32 {
1010
fn foo(&self, t: impl Clone) {}
1111
//~^ ERROR method `foo` has 1 type parameter but its trait declaration has 0 type parameters
1212
//~| NOTE found 1 type parameter
13+
//~| NOTE `impl Trait` introduces an implicit type parameter
1314
}
1415

1516
fn main() {}

src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.stderr

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
error[E0049]: method `foo` has 1 type parameter but its trait declaration has 0 type parameters
2-
--> $DIR/type-arg-mismatch-due-to-impl-trait.rs:10:5
2+
--> $DIR/type-arg-mismatch-due-to-impl-trait.rs:10:22
33
|
44
LL | fn foo(&self, t: Self::T);
5-
| -------------------------- expected 0 type parameters
5+
| - expected 0 type parameters
66
...
77
LL | fn foo(&self, t: impl Clone) {}
8-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found 1 type parameter
8+
| ^^^^^^^^^^
9+
| |
10+
| found 1 type parameter
11+
| `impl Trait` introduces an implicit type parameter
912

1013
error: aborting due to previous error
1114

0 commit comments

Comments
 (0)