diff options
| author | Esteban Küber <esteban@kuber.com.ar> | 2020-09-22 19:19:33 -0700 |
|---|---|---|
| committer | Esteban Küber <esteban@kuber.com.ar> | 2020-10-09 14:44:24 -0700 |
| commit | 5217007a2087d8364df8db91d503703c6b0be256 (patch) | |
| tree | 76de2d54f80f49d146180565e229252ebb7587f4 /compiler/rustc_resolve | |
| parent | 711760c8ec9dc431de43a0a72593abcdd74e0b3e (diff) | |
| download | rust-5217007a2087d8364df8db91d503703c6b0be256.tar.gz rust-5217007a2087d8364df8db91d503703c6b0be256.zip | |
Tweak output and add test cases
Diffstat (limited to 'compiler/rustc_resolve')
| -rw-r--r-- | compiler/rustc_resolve/src/late/diagnostics.rs | 56 |
1 files changed, 51 insertions, 5 deletions
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index a3948cc00d6..ca13d749e52 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -19,7 +19,7 @@ use rustc_session::config::nightly_options; use rustc_session::parse::feature_err; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{BytePos, Span, DUMMY_SP}; +use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP}; use tracing::debug; @@ -446,12 +446,58 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { err.span_label(base_span, fallback_label); if let PathSource::Trait(AliasPossibility::Maybe) = source { - if let Some([start, .., end]) = self.diagnostic_metadata.current_trait_object { + if let Some(bounds @ [_, .., _]) = self.diagnostic_metadata.current_trait_object { + let spans: Vec<Span> = bounds + .iter() + .map(|bound| bound.span()) + .filter(|&sp| sp != base_span) + .collect(); + + let start_span = bounds.iter().map(|bound| bound.span()).next().unwrap(); + // `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><) + let end_span = bounds.iter().map(|bound| bound.span()).last().unwrap(); + // `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar) + let last_bound_span = spans.last().cloned().unwrap(); + let mut multi_span: MultiSpan = spans.clone().into(); + for sp in spans { + let msg = if sp == last_bound_span { + format!( + "...because of {} bound{}", + if bounds.len() <= 2 { "this" } else { "these" }, + if bounds.len() <= 2 { "" } else { "s" }, + ) + } else { + String::new() + }; + multi_span.push_span_label(sp, msg); + } + multi_span.push_span_label( + base_span, + "expected this type to be a trait...".to_string(), + ); err.span_help( - start.span().to(end.span()), - "`+` can be used to constrain a \"trait object\" type with lifetimes or \ - auto-traits, structs and enums can't be bound in that way", + multi_span, + "`+` is used to constrain a \"trait object\" type with lifetimes or \ + auto-traits; structs and enums can't be bound in that way", ); + if bounds.iter().all(|bound| match bound { + ast::GenericBound::Outlives(_) => true, + ast::GenericBound::Trait(tr, _) => tr.span == base_span, + }) { + let mut sugg = vec![]; + if base_span != start_span { + sugg.push((start_span.until(base_span), String::new())); + } + if base_span != end_span { + sugg.push((base_span.shrink_to_hi().to(end_span), String::new())); + } + + err.multipart_suggestion( + "if you meant to use a type and not a trait here, remove the bounds", + sugg, + Applicability::MaybeIncorrect, + ); + } } } match self.diagnostic_metadata.current_let_binding { |
