diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_middle/src/ty/print/pretty.rs | 66 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/diagnostics.rs | 16 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/imports.rs | 50 | ||||
| -rw-r--r-- | compiler/rustc_span/src/lib.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_span/src/source_map.rs | 19 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/demand.rs | 83 |
6 files changed, 185 insertions, 50 deletions
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 5d9e7aaf72f..c8e898c6849 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -649,30 +649,74 @@ pub trait PrettyPrinter<'tcx>: let mut first = true; let mut is_sized = false; + let mut is_future = false; + let mut future_output_ty = None; + p!("impl"); for (predicate, _) in bounds { let predicate = predicate.subst(self.tcx(), substs); let bound_predicate = predicate.kind(); - if let ty::PredicateKind::Trait(pred) = bound_predicate.skip_binder() { - let trait_ref = bound_predicate.rebind(pred.trait_ref); - // Don't print +Sized, but rather +?Sized if absent. - if Some(trait_ref.def_id()) == self.tcx().lang_items().sized_trait() { - is_sized = true; - continue; + + match bound_predicate.skip_binder() { + ty::PredicateKind::Projection(projection_predicate) => { + let Some(future_trait) = self.tcx().lang_items().future_trait() else { continue }; + let future_output_def_id = + self.tcx().associated_item_def_ids(future_trait)[0]; + + if projection_predicate.projection_ty.item_def_id + == future_output_def_id + { + // We don't account for multiple `Future::Output = Ty` contraints. + is_future = true; + future_output_ty = Some(projection_predicate.ty); + } } + ty::PredicateKind::Trait(pred) => { + let trait_ref = bound_predicate.rebind(pred.trait_ref); + // Don't print +Sized, but rather +?Sized if absent. + if Some(trait_ref.def_id()) == self.tcx().lang_items().sized_trait() + { + is_sized = true; + continue; + } - p!( - write("{}", if first { " " } else { "+" }), - print(trait_ref.print_only_trait_path()) - ); - first = false; + if Some(trait_ref.def_id()) + == self.tcx().lang_items().future_trait() + { + is_future = true; + continue; + } + + p!( + write("{}", if first { " " } else { "+" }), + print(trait_ref.print_only_trait_path()) + ); + + first = false; + } + _ => {} } } + + if is_future { + p!(write("{}Future", if first { " " } else { "+" })); + first = false; + + if let Some(future_output_ty) = future_output_ty { + // Don't print projection types, which we (unfortunately) see often + // in the error outputs involving async blocks. + if !matches!(future_output_ty.kind(), ty::Projection(_)) { + p!("<Output = ", print(future_output_ty), ">"); + } + } + } + if !is_sized { p!(write("{}?Sized", if first { " " } else { "+" })); } else if first { p!(" Sized"); } + Ok(self) }); } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index c46a18e5103..2e4cb4ff727 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -450,12 +450,24 @@ impl<'a> Resolver<'a> { // let foo =... // ^^^ given this Span // ------- get this Span to have an applicable suggestion + + // edit: + // only do this if the const and usage of the non-constant value are on the same line + // the further the two are apart, the higher the chance of the suggestion being wrong + // also make sure that the pos for the suggestion is not 0 (ICE #90878) + let sp = self.session.source_map().span_extend_to_prev_str(ident.span, current, true); - if sp.lo().0 == 0 { + + let pos_for_suggestion = sp.lo().0.saturating_sub(current.len() as u32); + + if sp.lo().0 == 0 + || pos_for_suggestion == 0 + || self.session.source_map().is_multiline(sp) + { err.span_label(ident.span, &format!("this would need to be a `{}`", sugg)); } else { - let sp = sp.with_lo(BytePos(sp.lo().0 - current.len() as u32)); + let sp = sp.with_lo(BytePos(pos_for_suggestion)); err.span_suggestion( sp, &format!("consider using `{}` instead of `{}`", sugg, current), diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 4262c1e9051..bf4cece8bde 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1180,11 +1180,17 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let mut reexport_error = None; let mut any_successful_reexport = false; + let mut crate_private_reexport = false; self.r.per_ns(|this, ns| { if let Ok(binding) = source_bindings[ns].get() { let vis = import.vis.get(); if !binding.vis.is_at_least(vis, &*this) { reexport_error = Some((ns, binding)); + if let ty::Visibility::Restricted(binding_def_id) = binding.vis { + if binding_def_id.is_top_level_module() { + crate_private_reexport = true; + } + } } else { any_successful_reexport = true; } @@ -1207,24 +1213,34 @@ impl<'a, 'b> ImportResolver<'a, 'b> { import.span, &msg, ); - } else if ns == TypeNS { - struct_span_err!( - self.r.session, - import.span, - E0365, - "`{}` is private, and cannot be re-exported", - ident - ) - .span_label(import.span, format!("re-export of private `{}`", ident)) - .note(&format!("consider declaring type or module `{}` with `pub`", ident)) - .emit(); } else { - let msg = format!("`{}` is private, and cannot be re-exported", ident); - let note_msg = - format!("consider marking `{}` as `pub` in the imported module", ident,); - struct_span_err!(self.r.session, import.span, E0364, "{}", &msg) - .span_note(import.span, ¬e_msg) - .emit(); + let error_msg = if crate_private_reexport { + format!( + "`{}` is only public within the crate, and cannot be re-exported outside", + ident + ) + } else { + format!("`{}` is private, and cannot be re-exported", ident) + }; + + if ns == TypeNS { + let label_msg = if crate_private_reexport { + format!("re-export of crate public `{}`", ident) + } else { + format!("re-export of private `{}`", ident) + }; + + struct_span_err!(self.r.session, import.span, E0365, "{}", error_msg) + .span_label(import.span, label_msg) + .note(&format!("consider declaring type or module `{}` with `pub`", ident)) + .emit(); + } else { + let note_msg = + format!("consider marking `{}` as `pub` in the imported module", ident); + struct_span_err!(self.r.session, import.span, E0364, "{}", error_msg) + .span_note(import.span, ¬e_msg) + .emit(); + } } } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index dfc64f37e4c..1445c59710c 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1935,6 +1935,7 @@ pub struct Loc { #[derive(Debug)] pub struct SourceFileAndLine { pub sf: Lrc<SourceFile>, + /// Index of line, starting from 0. pub line: usize, } #[derive(Debug)] diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 74958c49849..7414d201f51 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -593,14 +593,19 @@ impl SourceMap { } pub fn span_to_margin(&self, sp: Span) -> Option<usize> { - match self.span_to_prev_source(sp) { - Err(_) => None, - Ok(source) => { - let last_line = source.rsplit_once('\n').unwrap_or(("", &source)).1; + Some(self.indentation_before(sp)?.len()) + } - Some(last_line.len() - last_line.trim_start().len()) - } - } + pub fn indentation_before(&self, sp: Span) -> Option<String> { + self.span_to_source(sp, |src, start_index, _| { + let before = &src[..start_index]; + let last_line = before.rsplit_once('\n').map_or(before, |(_, last)| last); + Ok(last_line + .split_once(|c: char| !c.is_whitespace()) + .map_or(last_line, |(indent, _)| indent) + .to_string()) + }) + .ok() } /// Returns the source snippet as `String` before the given `Span`. diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index 9bbe5259147..ece2d7b4f37 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -199,7 +199,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } - let mut compatible_variants = expected_adt + // If the expression is of type () and it's the return expression of a block, + // we suggest adding a separate return expression instead. + // (To avoid things like suggesting `Ok(while .. { .. })`.) + if expr_ty.is_unit() { + if let Some(hir::Node::Block(&hir::Block { + span: block_span, expr: Some(e), .. + })) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id)) + { + if e.hir_id == expr.hir_id { + if let Some(span) = expr.span.find_ancestor_inside(block_span) { + let return_suggestions = + if self.tcx.is_diagnostic_item(sym::Result, expected_adt.did) { + vec!["Ok(())".to_string()] + } else if self.tcx.is_diagnostic_item(sym::Option, expected_adt.did) + { + vec!["None".to_string(), "Some(())".to_string()] + } else { + return; + }; + if let Some(indent) = + self.tcx.sess.source_map().indentation_before(span.shrink_to_lo()) + { + // Add a semicolon, except after `}`. + let semicolon = + match self.tcx.sess.source_map().span_to_snippet(span) { + Ok(s) if s.ends_with('}') => "", + _ => ";", + }; + err.span_suggestions( + span.shrink_to_hi(), + "try adding an expression at the end of the block", + return_suggestions + .into_iter() + .map(|r| format!("{}\n{}{}", semicolon, indent, r)), + Applicability::MaybeIncorrect, + ); + } + return; + } + } + } + } + + let compatible_variants: Vec<String> = expected_adt .variants .iter() .filter(|variant| variant.fields.len() == 1) @@ -220,19 +263,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None } }) - .peekable(); + .collect(); - if compatible_variants.peek().is_some() { - if let Ok(expr_text) = self.tcx.sess.source_map().span_to_snippet(expr.span) { - let suggestions = compatible_variants.map(|v| format!("{}({})", v, expr_text)); - let msg = "try using a variant of the expected enum"; - err.span_suggestions( - expr.span, - msg, - suggestions, - Applicability::MaybeIncorrect, - ); - } + if let [variant] = &compatible_variants[..] { + // Just a single matching variant. + err.multipart_suggestion( + &format!("try wrapping the expression in `{}`", variant), + vec![ + (expr.span.shrink_to_lo(), format!("{}(", variant)), + (expr.span.shrink_to_hi(), ")".to_string()), + ], + Applicability::MaybeIncorrect, + ); + } else if compatible_variants.len() > 1 { + // More than one matching variant. + err.multipart_suggestions( + &format!( + "try wrapping the expression in a variant of `{}`", + self.tcx.def_path_str(expected_adt.did) + ), + compatible_variants.into_iter().map(|variant| { + vec![ + (expr.span.shrink_to_lo(), format!("{}(", variant)), + (expr.span.shrink_to_hi(), ")".to_string()), + ] + }), + Applicability::MaybeIncorrect, + ); } } } |
