Skip to content

Commit

Permalink
Rollup merge of rust-lang#61438 - estebank:generics-span, r=varkor
Browse files Browse the repository at this point in the history
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 rust-lang#55991.
  • Loading branch information
Centril authored Jun 2, 2019
2 parents 5599985 + 31918d6 commit 83b74f2
Show file tree
Hide file tree
Showing 10 changed files with 120 additions and 49 deletions.
4 changes: 0 additions & 4 deletions src/librustc/hir/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -628,10 +628,6 @@ impl<'hir> Map<'hir> {
})
}

pub fn get_generics_span(&self, id: DefId) -> Option<Span> {
self.get_generics(id).map(|generics| generics.span).filter(|sp| *sp != DUMMY_SP)
}

/// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
pub fn find(&self, id: NodeId) -> Option<Node<'hir>> {
let hir_id = self.node_to_hir_id(id);
Expand Down
10 changes: 9 additions & 1 deletion src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::util::nodemap::{NodeMap, FxHashSet};
use crate::mir::mono::Linkage;

use errors::FatalError;
use syntax_pos::{Span, DUMMY_SP, symbol::InternedString};
use syntax_pos::{Span, DUMMY_SP, symbol::InternedString, MultiSpan};
use syntax::source_map::Spanned;
use rustc_target::spec::abi::Abi;
use syntax::ast::{self, CrateSugar, Ident, Name, NodeId, AsmDialect};
Expand Down Expand Up @@ -624,6 +624,14 @@ impl Generics {
}
None
}

pub fn spans(&self) -> MultiSpan {
if self.params.is_empty() {
self.span.into()
} else {
self.params.iter().map(|p| p.span).collect::<Vec<Span>>().into()
}
}
}

/// Synthetic type parameters are converted to another form during lowering; this allows
Expand Down
83 changes: 62 additions & 21 deletions src/librustc_typeck/check/compare_method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// the moment, give a kind of vague error message.
if trait_params != impl_params {
let def_span = tcx.sess.source_map().def_span(span);
let span = tcx.hir().get_generics_span(impl_m.def_id).unwrap_or(def_span);
let span = tcx.hir().get_generics(impl_m.def_id).map(|g| g.span).unwrap_or(def_span);
let mut err = struct_span_err!(
tcx.sess,
span,
Expand All @@ -396,7 +396,7 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
err.span_label(span, "lifetimes do not match method in trait");
if let Some(sp) = tcx.hir().span_if_local(trait_m.def_id) {
let def_sp = tcx.sess.source_map().def_span(sp);
let sp = tcx.hir().get_generics_span(trait_m.def_id).unwrap_or(def_sp);
let sp = tcx.hir().get_generics(trait_m.def_id).map(|g| g.span).unwrap_or(def_sp);
err.span_label(sp, "lifetimes in impl do not match this method in trait");
}
err.emit();
Expand Down Expand Up @@ -583,7 +583,7 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
fn compare_number_of_generics<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl_: &ty::AssocItem,
impl_span: Span,
_impl_span: Span,
trait_: &ty::AssocItem,
trait_span: Option<Span>,
) -> Result<(), ErrorReported> {
Expand All @@ -600,17 +600,44 @@ fn compare_number_of_generics<'a, 'tcx>(
if impl_count != trait_count {
err_occurred = true;

let impl_hir_id = tcx.hir().as_local_hir_id(impl_.def_id).unwrap();
let impl_item = tcx.hir().expect_impl_item(impl_hir_id);
let span = if impl_item.generics.params.is_empty()
|| impl_item.generics.span.is_dummy() { // argument position impl Trait (#55374)
impl_span
let (
trait_spans,
impl_trait_spans,
) = if let Some(trait_hir_id) = tcx.hir().as_local_hir_id(trait_.def_id) {
let trait_item = tcx.hir().expect_trait_item(trait_hir_id);
if trait_item.generics.params.is_empty() {
(Some(vec![trait_item.generics.span]), vec![])
} else {
let arg_spans: Vec<Span> = trait_item.generics.params.iter()
.map(|p| p.span)
.collect();
let impl_trait_spans: Vec<Span> = trait_item.generics.params.iter()
.filter_map(|p| match p.kind {
GenericParamKind::Type {
synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), ..
} => Some(p.span),
_ => None,
}).collect();
(Some(arg_spans), impl_trait_spans)
}
} else {
impl_item.generics.span
(trait_span.map(|s| vec![s]), vec![])
};

let impl_hir_id = tcx.hir().as_local_hir_id(impl_.def_id).unwrap();
let impl_item = tcx.hir().expect_impl_item(impl_hir_id);
let impl_item_impl_trait_spans: Vec<Span> = impl_item.generics.params.iter()
.filter_map(|p| match p.kind {
GenericParamKind::Type {
synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), ..
} => Some(p.span),
_ => None,
}).collect();
let spans = impl_item.generics.spans();
let span = spans.primary_span();

let mut err = tcx.sess.struct_span_err_with_code(
span,
spans,
&format!(
"method `{}` has {} {kind} parameter{} but its trait \
declaration has {} {kind} parameter{}",
Expand All @@ -626,22 +653,36 @@ fn compare_number_of_generics<'a, 'tcx>(

let mut suffix = None;

if let Some(span) = trait_span {
err.span_label(
span,
format!("expected {} {} parameter{}", trait_count, kind,
if trait_count != 1 { "s" } else { "" })
);
if let Some(spans) = trait_spans {
let mut spans = spans.iter();
if let Some(span) = spans.next() {
err.span_label(*span, format!(
"expected {} {} parameter{}",
trait_count,
kind,
if trait_count != 1 { "s" } else { "" },
));
}
for span in spans {
err.span_label(*span, "");
}
} else {
suffix = Some(format!(", expected {}", trait_count));
}

err.span_label(
span,
format!("found {} {} parameter{}{}", impl_count, kind,
if let Some(span) = span {
err.span_label(span, format!(
"found {} {} parameter{}{}",
impl_count,
kind,
if impl_count != 1 { "s" } else { "" },
suffix.unwrap_or_else(|| String::new())),
);
suffix.unwrap_or_else(|| String::new()),
));
}

for span in impl_trait_spans.iter().chain(impl_item_impl_trait_spans.iter()) {
err.span_label(*span, "`impl Trait` introduces an implicit type parameter");
}

err.emit();
}
Expand Down
25 changes: 13 additions & 12 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5050,21 +5050,22 @@ impl<'a> Parser<'a> {
/// where typaramseq = ( typaram ) | ( typaram , typaramseq )
fn parse_generics(&mut self) -> PResult<'a, ast::Generics> {
let span_lo = self.span;
if self.eat_lt() {
let (params, span) = if self.eat_lt() {
let params = self.parse_generic_params()?;
self.expect_gt()?;
Ok(ast::Generics {
params,
where_clause: WhereClause {
id: ast::DUMMY_NODE_ID,
predicates: Vec::new(),
span: DUMMY_SP,
},
span: span_lo.to(self.prev_span),
})
(params, span_lo.to(self.prev_span))
} else {
Ok(ast::Generics::default())
}
(vec![], self.prev_span.between(self.span))
};
Ok(ast::Generics {
params,
where_clause: WhereClause {
id: ast::DUMMY_NODE_ID,
predicates: Vec::new(),
span: DUMMY_SP,
},
span,
})
}

/// Parses generic args (within a path segment) with recovery for extra leading angle brackets.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ LL | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d
| ^^

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

error[E0276]: impl has stricter requirements than trait
--> $DIR/regions-bound-missing-bound-in-impl.rs:48:5
Expand Down
10 changes: 10 additions & 0 deletions src/test/ui/error-codes/E0049.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,15 @@ impl Foo for Bar {
fn foo(x: bool) -> Self { Bar } //~ ERROR E0049
}

trait Fuzz {
fn fuzz<A: Default, B>(x: A, y: B) -> Self;
}

struct Baz;

impl Fuzz for Baz {
fn fuzz(x: bool, y: bool) -> Self { Baz } //~ ERROR E0049
}

fn main() {
}
19 changes: 15 additions & 4 deletions src/test/ui/error-codes/E0049.stderr
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
error[E0049]: method `foo` has 0 type parameters but its trait declaration has 1 type parameter
--> $DIR/E0049.rs:8:5
--> $DIR/E0049.rs:8:11
|
LL | fn foo<T: Default>(x: T) -> Self;
| --------------------------------- expected 1 type parameter
| - expected 1 type parameter
...
LL | fn foo(x: bool) -> Self { Bar }
| ^^^^^^^^^^^^^^^^^^^^^^^ found 0 type parameters
| ^ found 0 type parameters

error: aborting due to previous error
error[E0049]: method `fuzz` has 0 type parameters but its trait declaration has 2 type parameters
--> $DIR/E0049.rs:18:12
|
LL | fn fuzz<A: Default, B>(x: A, y: B) -> Self;
| - -
| |
| expected 2 type parameters
...
LL | fn fuzz(x: bool, y: bool) -> Self { Baz }
| ^ found 0 type parameters

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0049`.
4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-36708.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0049]: method `foo` has 1 type parameter but its trait declaration has 0 type parameters
--> $DIR/issue-36708.rs:8:11
--> $DIR/issue-36708.rs:8:12
|
LL | fn foo<T>() {}
| ^^^ found 1 type parameter, expected 0
| ^ found 1 type parameter, expected 0

error: aborting due to previous error

Expand Down
1 change: 1 addition & 0 deletions src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ impl Foo for u32 {
fn foo(&self, t: impl Clone) {}
//~^ ERROR method `foo` has 1 type parameter but its trait declaration has 0 type parameters
//~| NOTE found 1 type parameter
//~| NOTE `impl Trait` introduces an implicit type parameter
}

fn main() {}
9 changes: 6 additions & 3 deletions src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
error[E0049]: method `foo` has 1 type parameter but its trait declaration has 0 type parameters
--> $DIR/type-arg-mismatch-due-to-impl-trait.rs:10:5
--> $DIR/type-arg-mismatch-due-to-impl-trait.rs:10:22
|
LL | fn foo(&self, t: Self::T);
| -------------------------- expected 0 type parameters
| - expected 0 type parameters
...
LL | fn foo(&self, t: impl Clone) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found 1 type parameter
| ^^^^^^^^^^
| |
| found 1 type parameter
| `impl Trait` introduces an implicit type parameter

error: aborting due to previous error

Expand Down

0 comments on commit 83b74f2

Please sign in to comment.