Skip to content

Commit

Permalink
Auto merge of rust-lang#91080 - matthiaskrgr:rollup-znh88cy, r=matthi…
Browse files Browse the repository at this point in the history
…askrgr

Rollup of 5 pull requests

Successful merges:

 - rust-lang#90575 (Improve suggestions for compatible variants on type mismatch.)
 - rust-lang#90628 (Clarify error messages caused by re-exporting `pub(crate)` visibility to outside)
 - rust-lang#90930 (Fix `non-constant value` ICE (rust-lang#90878))
 - rust-lang#90983 (Make scrollbar in the sidebar always visible for visual consistency)
 - rust-lang#91021 (Elaborate `Future::Output` when printing opaque `impl Future` type)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Nov 20, 2021
2 parents 6d48ee9 + 3379721 commit 3d78974
Show file tree
Hide file tree
Showing 67 changed files with 891 additions and 172 deletions.
66 changes: 55 additions & 11 deletions compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
});
}
Expand Down
16 changes: 14 additions & 2 deletions compiler/rustc_resolve/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
50 changes: 33 additions & 17 deletions compiler/rustc_resolve/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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, &note_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, &note_msg)
.emit();
}
}
}

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
19 changes: 12 additions & 7 deletions compiler/rustc_span/src/source_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down
83 changes: 70 additions & 13 deletions compiler/rustc_typeck/src/check/demand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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,
);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/html/static/css/rustdoc.css
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ nav.sub {
left: 0;
top: 0;
bottom: 0;
overflow: auto;
overflow-y: scroll;
}

/* Improve the scrollbar display on firefox */
Expand Down
4 changes: 2 additions & 2 deletions src/librustdoc/html/static/css/themes/ayu.css
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,11 @@ pre, .rustdoc.source .example-wrap {

/* Improve the scrollbar display on firefox */
* {
scrollbar-color: #5c6773 transparent;
scrollbar-color: #5c6773 #24292f;
}

.sidebar {
scrollbar-color: #5c6773 transparent;
scrollbar-color: #5c6773 #24292f;
}

/* Improve the scrollbar display on webkit-based browsers */
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/html/static/css/themes/dark.css
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pre, .rustdoc.source .example-wrap {
scrollbar-color: rgb(64, 65, 67) #717171;
}
.sidebar {
scrollbar-color: rgba(32,34,37,.6) transparent;
scrollbar-color: rgba(32,34,37,.6) #5a5a5a;
}

/* Improve the scrollbar display on webkit-based browsers */
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/async-await/async-fn-nonsend.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely
LL | assert_send(local_dropped_before_await());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `local_dropped_before_await` is not `Send`
|
= help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>`
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
note: future is not `Send` as this value is used across an await
--> $DIR/async-fn-nonsend.rs:24:5
|
Expand All @@ -27,7 +27,7 @@ error: future cannot be sent between threads safely
LL | assert_send(non_send_temporary_in_match());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send`
|
= help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>`
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
note: future is not `Send` as this value is used across an await
--> $DIR/async-fn-nonsend.rs:33:20
|
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/async-await/dont-suggest-missing-await.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ note: while checking the return type of the `async fn`
LL | async fn make_u32() -> u32 {
| ^^^ checked the `Output` of this `async fn`, found opaque type
= note: expected type `u32`
found opaque type `impl Future`
found opaque type `impl Future<Output = u32>`
help: consider `await`ing on the `Future`
|
LL | take_u32(x.await)
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/async-await/generator-desc.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ note: while checking the return type of the `async fn`
|
LL | async fn two() {}
| ^ checked the `Output` of this `async fn`, found opaque type
= note: expected opaque type `impl Future` (opaque type at <$DIR/generator-desc.rs:5:16>)
found opaque type `impl Future` (opaque type at <$DIR/generator-desc.rs:6:16>)
= note: expected opaque type `impl Future<Output = ()>` (opaque type at <$DIR/generator-desc.rs:5:16>)
found opaque type `impl Future<Output = ()>` (opaque type at <$DIR/generator-desc.rs:6:16>)
= help: consider `await`ing on both `Future`s
= note: distinct uses of `impl Trait` result in different opaque types

Expand Down
Loading

0 comments on commit 3d78974

Please sign in to comment.