Rollup merge of #70725 - Centril:nix-unwraps, r=estebank
Avoid `.unwrap()`s on `.span_to_snippet(...)`s First commit fixes https://github.com/rust-lang/rust/issues/70724 and the others fix similar issues found by grepping. r? @estebank
This commit is contained in:
commit
b91c376e4a
7 changed files with 116 additions and 75 deletions
|
@ -165,9 +165,9 @@ impl<'a> Parser<'a> {
|
||||||
// Rewind to before attempting to parse the type and continue parsing.
|
// Rewind to before attempting to parse the type and continue parsing.
|
||||||
let parser_snapshot_after_type = self.clone();
|
let parser_snapshot_after_type = self.clone();
|
||||||
mem::replace(self, parser_snapshot_before_type);
|
mem::replace(self, parser_snapshot_before_type);
|
||||||
|
if let Ok(snip) = self.span_to_snippet(pat.span) {
|
||||||
let snippet = self.span_to_snippet(pat.span).unwrap();
|
err.span_label(pat.span, format!("while parsing the type for `{}`", snip));
|
||||||
err.span_label(pat.span, format!("while parsing the type for `{}`", snippet));
|
}
|
||||||
(Some((parser_snapshot_after_type, colon_sp, err)), None)
|
(Some((parser_snapshot_after_type, colon_sp, err)), None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@ pub trait InferCtxtExt<'tcx> {
|
||||||
/// returns a span and `ArgKind` information that describes the
|
/// returns a span and `ArgKind` information that describes the
|
||||||
/// arguments it expects. This can be supplied to
|
/// arguments it expects. This can be supplied to
|
||||||
/// `report_arg_count_mismatch`.
|
/// `report_arg_count_mismatch`.
|
||||||
fn get_fn_like_arguments(&self, node: Node<'_>) -> (Span, Vec<ArgKind>);
|
fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec<ArgKind>)>;
|
||||||
|
|
||||||
/// Reports an error when the number of arguments needed by a
|
/// Reports an error when the number of arguments needed by a
|
||||||
/// trait match doesn't match the number that the expression
|
/// trait match doesn't match the number that the expression
|
||||||
|
@ -611,10 +611,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
let (closure_span, found) = found_did
|
let (closure_span, found) = found_did
|
||||||
.and_then(|did| self.tcx.hir().get_if_local(did))
|
.and_then(|did| {
|
||||||
.map(|node| {
|
let node = self.tcx.hir().get_if_local(did)?;
|
||||||
let (found_span, found) = self.get_fn_like_arguments(node);
|
let (found_span, found) = self.get_fn_like_arguments(node)?;
|
||||||
(Some(found_span), found)
|
Some((Some(found_span), found))
|
||||||
})
|
})
|
||||||
.unwrap_or((found_span, found));
|
.unwrap_or((found_span, found));
|
||||||
|
|
||||||
|
@ -672,43 +672,38 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
/// returns a span and `ArgKind` information that describes the
|
/// returns a span and `ArgKind` information that describes the
|
||||||
/// arguments it expects. This can be supplied to
|
/// arguments it expects. This can be supplied to
|
||||||
/// `report_arg_count_mismatch`.
|
/// `report_arg_count_mismatch`.
|
||||||
fn get_fn_like_arguments(&self, node: Node<'_>) -> (Span, Vec<ArgKind>) {
|
fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec<ArgKind>)> {
|
||||||
match node {
|
let sm = self.tcx.sess.source_map();
|
||||||
|
let hir = self.tcx.hir();
|
||||||
|
Some(match node {
|
||||||
Node::Expr(&hir::Expr {
|
Node::Expr(&hir::Expr {
|
||||||
kind: hir::ExprKind::Closure(_, ref _decl, id, span, _),
|
kind: hir::ExprKind::Closure(_, ref _decl, id, span, _),
|
||||||
..
|
..
|
||||||
}) => (
|
}) => (
|
||||||
self.tcx.sess.source_map().guess_head_span(span),
|
sm.guess_head_span(span),
|
||||||
self.tcx
|
hir.body(id)
|
||||||
.hir()
|
|
||||||
.body(id)
|
|
||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
.map(|arg| {
|
.map(|arg| {
|
||||||
if let hir::Pat { kind: hir::PatKind::Tuple(ref args, _), span, .. } =
|
if let hir::Pat { kind: hir::PatKind::Tuple(ref args, _), span, .. } =
|
||||||
*arg.pat
|
*arg.pat
|
||||||
{
|
{
|
||||||
ArgKind::Tuple(
|
Some(ArgKind::Tuple(
|
||||||
Some(span),
|
Some(span),
|
||||||
args.iter()
|
args.iter()
|
||||||
.map(|pat| {
|
.map(|pat| {
|
||||||
let snippet = self
|
sm.span_to_snippet(pat.span)
|
||||||
.tcx
|
.ok()
|
||||||
.sess
|
.map(|snippet| (snippet, "_".to_owned()))
|
||||||
.source_map()
|
|
||||||
.span_to_snippet(pat.span)
|
|
||||||
.unwrap();
|
|
||||||
(snippet, "_".to_owned())
|
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Option<Vec<_>>>()?,
|
||||||
)
|
))
|
||||||
} else {
|
} else {
|
||||||
let name =
|
let name = sm.span_to_snippet(arg.pat.span).ok()?;
|
||||||
self.tcx.sess.source_map().span_to_snippet(arg.pat.span).unwrap();
|
Some(ArgKind::Arg(name, "_".to_owned()))
|
||||||
ArgKind::Arg(name, "_".to_owned())
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Vec<ArgKind>>(),
|
.collect::<Option<Vec<ArgKind>>>()?,
|
||||||
),
|
),
|
||||||
Node::Item(&hir::Item { span, kind: hir::ItemKind::Fn(ref sig, ..), .. })
|
Node::Item(&hir::Item { span, kind: hir::ItemKind::Fn(ref sig, ..), .. })
|
||||||
| Node::ImplItem(&hir::ImplItem {
|
| Node::ImplItem(&hir::ImplItem {
|
||||||
|
@ -721,7 +716,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
kind: hir::TraitItemKind::Fn(ref sig, _),
|
kind: hir::TraitItemKind::Fn(ref sig, _),
|
||||||
..
|
..
|
||||||
}) => (
|
}) => (
|
||||||
self.tcx.sess.source_map().guess_head_span(span),
|
sm.guess_head_span(span),
|
||||||
sig.decl
|
sig.decl
|
||||||
.inputs
|
.inputs
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -735,16 +730,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
.collect::<Vec<ArgKind>>(),
|
.collect::<Vec<ArgKind>>(),
|
||||||
),
|
),
|
||||||
Node::Ctor(ref variant_data) => {
|
Node::Ctor(ref variant_data) => {
|
||||||
let span = variant_data
|
let span = variant_data.ctor_hir_id().map(|id| hir.span(id)).unwrap_or(DUMMY_SP);
|
||||||
.ctor_hir_id()
|
let span = sm.guess_head_span(span);
|
||||||
.map(|hir_id| self.tcx.hir().span(hir_id))
|
|
||||||
.unwrap_or(DUMMY_SP);
|
|
||||||
let span = self.tcx.sess.source_map().guess_head_span(span);
|
|
||||||
|
|
||||||
(span, vec![ArgKind::empty(); variant_data.fields().len()])
|
(span, vec![ArgKind::empty(); variant_data.fields().len()])
|
||||||
}
|
}
|
||||||
_ => panic!("non-FnLike node found: {:?}", node),
|
_ => panic!("non-FnLike node found: {:?}", node),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reports an error when the number of arguments needed by a
|
/// Reports an error when the number of arguments needed by a
|
||||||
|
|
|
@ -732,12 +732,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
true
|
true
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let sm = self.tcx.sess.source_map();
|
||||||
let (snippet, last_ty) =
|
let (snippet, last_ty) =
|
||||||
if let (true, hir::TyKind::TraitObject(..), Ok(snippet), true, Some(last_ty)) = (
|
if let (true, hir::TyKind::TraitObject(..), Ok(snippet), true, Some(last_ty)) = (
|
||||||
// Verify that we're dealing with a return `dyn Trait`
|
// Verify that we're dealing with a return `dyn Trait`
|
||||||
ret_ty.span.overlaps(span),
|
ret_ty.span.overlaps(span),
|
||||||
&ret_ty.kind,
|
&ret_ty.kind,
|
||||||
self.tcx.sess.source_map().span_to_snippet(ret_ty.span),
|
sm.span_to_snippet(ret_ty.span),
|
||||||
// If any of the return types does not conform to the trait, then we can't
|
// If any of the return types does not conform to the trait, then we can't
|
||||||
// suggest `impl Trait` nor trait objects, it is a type mismatch error.
|
// suggest `impl Trait` nor trait objects, it is a type mismatch error.
|
||||||
all_returns_conform_to_trait,
|
all_returns_conform_to_trait,
|
||||||
|
@ -775,19 +776,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
if is_object_safe {
|
if is_object_safe {
|
||||||
// Suggest `-> Box<dyn Trait>` and `Box::new(returned_value)`.
|
// Suggest `-> Box<dyn Trait>` and `Box::new(returned_value)`.
|
||||||
// Get all the return values and collect their span and suggestion.
|
// Get all the return values and collect their span and suggestion.
|
||||||
let mut suggestions = visitor
|
if let Some(mut suggestions) = visitor
|
||||||
.returns
|
.returns
|
||||||
.iter()
|
.iter()
|
||||||
.map(|expr| {
|
.map(|expr| {
|
||||||
(
|
let snip = sm.span_to_snippet(expr.span).ok()?;
|
||||||
expr.span,
|
Some((expr.span, format!("Box::new({})", snip)))
|
||||||
format!(
|
|
||||||
"Box::new({})",
|
|
||||||
self.tcx.sess.source_map().span_to_snippet(expr.span).unwrap()
|
|
||||||
),
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Option<Vec<_>>>()
|
||||||
|
{
|
||||||
// Add the suggestion for the return type.
|
// Add the suggestion for the return type.
|
||||||
suggestions.push((ret_ty.span, format!("Box<dyn {}>", trait_obj)));
|
suggestions.push((ret_ty.span, format!("Box<dyn {}>", trait_obj)));
|
||||||
err.multipart_suggestion(
|
err.multipart_suggestion(
|
||||||
|
@ -795,6 +792,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
suggestions,
|
suggestions,
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// This is currently not possible to trigger because E0038 takes precedence, but
|
// This is currently not possible to trigger because E0038 takes precedence, but
|
||||||
// leave it in for completeness in case anything changes in an earlier stage.
|
// leave it in for completeness in case anything changes in an earlier stage.
|
||||||
|
|
|
@ -432,18 +432,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
body: &hir::Body<'_>,
|
body: &hir::Body<'_>,
|
||||||
expected_sig: ExpectedSig<'tcx>,
|
expected_sig: ExpectedSig<'tcx>,
|
||||||
) -> ClosureSignatures<'tcx> {
|
) -> ClosureSignatures<'tcx> {
|
||||||
let expr_map_node = self.tcx.hir().get_if_local(expr_def_id).unwrap();
|
let hir = self.tcx.hir();
|
||||||
|
let expr_map_node = hir.get_if_local(expr_def_id).unwrap();
|
||||||
let expected_args: Vec<_> = expected_sig
|
let expected_args: Vec<_> = expected_sig
|
||||||
.sig
|
.sig
|
||||||
.inputs()
|
.inputs()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|ty| ArgKind::from_expected_ty(ty, None))
|
.map(|ty| ArgKind::from_expected_ty(ty, None))
|
||||||
.collect();
|
.collect();
|
||||||
let (closure_span, found_args) = self.get_fn_like_arguments(expr_map_node);
|
let (closure_span, found_args) = match self.get_fn_like_arguments(expr_map_node) {
|
||||||
let expected_span = expected_sig.cause_span.unwrap_or(closure_span);
|
Some((sp, args)) => (Some(sp), args),
|
||||||
|
None => (None, Vec::new()),
|
||||||
|
};
|
||||||
|
let expected_span =
|
||||||
|
expected_sig.cause_span.unwrap_or_else(|| hir.span_if_local(expr_def_id).unwrap());
|
||||||
self.report_arg_count_mismatch(
|
self.report_arg_count_mismatch(
|
||||||
expected_span,
|
expected_span,
|
||||||
Some(closure_span),
|
closure_span,
|
||||||
expected_args,
|
expected_args,
|
||||||
found_args,
|
found_args,
|
||||||
true,
|
true,
|
||||||
|
|
|
@ -481,7 +481,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If one of the types is an uncalled function and calling it would yield the other type,
|
/// If one of the types is an uncalled function and calling it would yield the other type,
|
||||||
/// suggest calling the function. Returns whether a suggestion was given.
|
/// suggest calling the function. Returns `true` if suggestion would apply (even if not given).
|
||||||
fn add_type_neq_err_label(
|
fn add_type_neq_err_label(
|
||||||
&self,
|
&self,
|
||||||
err: &mut rustc_errors::DiagnosticBuilder<'_>,
|
err: &mut rustc_errors::DiagnosticBuilder<'_>,
|
||||||
|
@ -514,16 +514,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
.lookup_op_method(fn_sig.output(), &[other_ty], Op::Binary(op, is_assign))
|
.lookup_op_method(fn_sig.output(), &[other_ty], Op::Binary(op, is_assign))
|
||||||
.is_ok()
|
.is_ok()
|
||||||
{
|
{
|
||||||
|
if let Ok(snippet) = source_map.span_to_snippet(span) {
|
||||||
let (variable_snippet, applicability) = if !fn_sig.inputs().is_empty() {
|
let (variable_snippet, applicability) = if !fn_sig.inputs().is_empty() {
|
||||||
(
|
(format!("{}( /* arguments */ )", snippet), Applicability::HasPlaceholders)
|
||||||
format!("{}( /* arguments */ )", source_map.span_to_snippet(span).unwrap()),
|
|
||||||
Applicability::HasPlaceholders,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
(
|
(format!("{}()", snippet), Applicability::MaybeIncorrect)
|
||||||
format!("{}()", source_map.span_to_snippet(span).unwrap()),
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
|
@ -532,6 +527,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
variable_snippet,
|
variable_snippet,
|
||||||
applicability,
|
applicability,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
fn a() -> i32 {
|
||||||
|
3
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
assert_eq!(a, 0);
|
||||||
|
//~^ ERROR binary operation `==` cannot
|
||||||
|
//~| ERROR mismatched types
|
||||||
|
//~| ERROR doesn't implement
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
error[E0369]: binary operation `==` cannot be applied to type `fn() -> i32 {a}`
|
||||||
|
--> $DIR/issue-70724-add_type_neq_err_label-unwrap.rs:6:5
|
||||||
|
|
|
||||||
|
LL | assert_eq!(a, 0);
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| fn() -> i32 {a}
|
||||||
|
| {integer}
|
||||||
|
| help: you might have forgotten to call this function: `*left_val()`
|
||||||
|
|
|
||||||
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/issue-70724-add_type_neq_err_label-unwrap.rs:6:5
|
||||||
|
|
|
||||||
|
LL | assert_eq!(a, 0);
|
||||||
|
| ^^^^^^^^^^^^^^^^^ expected fn item, found integer
|
||||||
|
|
|
||||||
|
= note: expected fn item `fn() -> i32 {a}`
|
||||||
|
found type `i32`
|
||||||
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error[E0277]: `fn() -> i32 {a}` doesn't implement `std::fmt::Debug`
|
||||||
|
--> $DIR/issue-70724-add_type_neq_err_label-unwrap.rs:6:5
|
||||||
|
|
|
||||||
|
LL | fn a() -> i32 {
|
||||||
|
| - consider calling this function
|
||||||
|
...
|
||||||
|
LL | assert_eq!(a, 0);
|
||||||
|
| ^^^^^^^^^^^^^^^^^ `fn() -> i32 {a}` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
|
||||||
|
|
|
||||||
|
= help: the trait `std::fmt::Debug` is not implemented for `fn() -> i32 {a}`
|
||||||
|
= help: use parentheses to call the function: `a()`
|
||||||
|
= note: required because of the requirements on the impl of `std::fmt::Debug` for `&fn() -> i32 {a}`
|
||||||
|
= note: required by `std::fmt::Debug::fmt`
|
||||||
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0277, E0308, E0369.
|
||||||
|
For more information about an error, try `rustc --explain E0277`.
|
Loading…
Add table
Add a link
Reference in a new issue