Remove some totally duplicated files
This commit is contained in:
parent
739d68a76e
commit
605ad65f6a
2 changed files with 0 additions and 630 deletions
|
@ -1,427 +0,0 @@
|
|||
use crate::errors::RegionOriginNote;
|
||||
use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt};
|
||||
use crate::infer::{self, SubregionOrigin};
|
||||
use rustc_errors::{
|
||||
fluent, struct_span_err, AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
|
||||
};
|
||||
use rustc_middle::traits::ObligationCauseCode;
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::{self, Region};
|
||||
|
||||
use super::ObligationCauseAsDiagArg;
|
||||
|
||||
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>) {
|
||||
match *origin {
|
||||
infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
|
||||
span: trace.cause.span,
|
||||
requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
|
||||
expected_found: self.values_str(trace.values),
|
||||
}
|
||||
.add_to_diagnostic(err),
|
||||
infer::Reborrow(span) => {
|
||||
RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diagnostic(err)
|
||||
}
|
||||
infer::ReborrowUpvar(span, ref upvar_id) => {
|
||||
let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
|
||||
RegionOriginNote::WithName {
|
||||
span,
|
||||
msg: fluent::infer_reborrow,
|
||||
name: &var_name.to_string(),
|
||||
continues: false,
|
||||
}
|
||||
.add_to_diagnostic(err);
|
||||
}
|
||||
infer::RelateObjectBound(span) => {
|
||||
RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound }
|
||||
.add_to_diagnostic(err);
|
||||
}
|
||||
infer::DataBorrowed(ty, span) => {
|
||||
RegionOriginNote::WithName {
|
||||
span,
|
||||
msg: fluent::infer_data_borrowed,
|
||||
name: &self.ty_to_string(ty),
|
||||
continues: false,
|
||||
}
|
||||
.add_to_diagnostic(err);
|
||||
}
|
||||
infer::ReferenceOutlivesReferent(ty, span) => {
|
||||
RegionOriginNote::WithName {
|
||||
span,
|
||||
msg: fluent::infer_reference_outlives_referent,
|
||||
name: &self.ty_to_string(ty),
|
||||
continues: false,
|
||||
}
|
||||
.add_to_diagnostic(err);
|
||||
}
|
||||
infer::RelateParamBound(span, ty, opt_span) => {
|
||||
RegionOriginNote::WithName {
|
||||
span,
|
||||
msg: fluent::infer_relate_param_bound,
|
||||
name: &self.ty_to_string(ty),
|
||||
continues: opt_span.is_some(),
|
||||
}
|
||||
.add_to_diagnostic(err);
|
||||
if let Some(span) = opt_span {
|
||||
RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 }
|
||||
.add_to_diagnostic(err);
|
||||
}
|
||||
}
|
||||
infer::RelateRegionParamBound(span) => {
|
||||
RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound }
|
||||
.add_to_diagnostic(err);
|
||||
}
|
||||
infer::CompareImplItemObligation { span, .. } => {
|
||||
RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation }
|
||||
.add_to_diagnostic(err);
|
||||
}
|
||||
infer::CheckAssociatedTypeBounds { ref parent, .. } => {
|
||||
self.note_region_origin(err, &parent);
|
||||
}
|
||||
infer::AscribeUserTypeProvePredicate(span) => {
|
||||
RegionOriginNote::Plain {
|
||||
span,
|
||||
msg: fluent::infer_ascribe_user_type_prove_predicate,
|
||||
}
|
||||
.add_to_diagnostic(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn report_concrete_failure(
|
||||
&self,
|
||||
origin: SubregionOrigin<'tcx>,
|
||||
sub: Region<'tcx>,
|
||||
sup: Region<'tcx>,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
match origin {
|
||||
infer::Subtype(box trace) => {
|
||||
let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
|
||||
let mut err = self.report_and_explain_type_error(trace, terr);
|
||||
match (*sub, *sup) {
|
||||
(ty::RePlaceholder(_), ty::RePlaceholder(_)) => {}
|
||||
(ty::RePlaceholder(_), _) => {
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"",
|
||||
sup,
|
||||
" doesn't meet the lifetime requirements",
|
||||
None,
|
||||
);
|
||||
}
|
||||
(_, ty::RePlaceholder(_)) => {
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"the required lifetime does not necessarily outlive ",
|
||||
sub,
|
||||
"",
|
||||
None,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
note_and_explain_region(self.tcx, &mut err, "", sup, "...", None);
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"...does not necessarily outlive ",
|
||||
sub,
|
||||
"",
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
err
|
||||
}
|
||||
infer::Reborrow(span) => {
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
E0312,
|
||||
"lifetime of reference outlives lifetime of borrowed content..."
|
||||
);
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"...the reference is valid for ",
|
||||
sub,
|
||||
"...",
|
||||
None,
|
||||
);
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"...but the borrowed content is only valid for ",
|
||||
sup,
|
||||
"",
|
||||
None,
|
||||
);
|
||||
err
|
||||
}
|
||||
infer::ReborrowUpvar(span, ref upvar_id) => {
|
||||
let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
E0313,
|
||||
"lifetime of borrowed pointer outlives lifetime of captured variable `{}`...",
|
||||
var_name
|
||||
);
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"...the borrowed pointer is valid for ",
|
||||
sub,
|
||||
"...",
|
||||
None,
|
||||
);
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
&format!("...but `{}` is only valid for ", var_name),
|
||||
sup,
|
||||
"",
|
||||
None,
|
||||
);
|
||||
err
|
||||
}
|
||||
infer::RelateObjectBound(span) => {
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
E0476,
|
||||
"lifetime of the source pointer does not outlive lifetime bound of the \
|
||||
object type"
|
||||
);
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"object type is valid for ",
|
||||
sub,
|
||||
"",
|
||||
None,
|
||||
);
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"source pointer is only valid for ",
|
||||
sup,
|
||||
"",
|
||||
None,
|
||||
);
|
||||
err
|
||||
}
|
||||
infer::RelateParamBound(span, ty, opt_span) => {
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
E0477,
|
||||
"the type `{}` does not fulfill the required lifetime",
|
||||
self.ty_to_string(ty)
|
||||
);
|
||||
match *sub {
|
||||
ty::ReStatic => note_and_explain_region(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"type must satisfy ",
|
||||
sub,
|
||||
if opt_span.is_some() { " as required by this binding" } else { "" },
|
||||
opt_span,
|
||||
),
|
||||
_ => note_and_explain_region(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"type must outlive ",
|
||||
sub,
|
||||
if opt_span.is_some() { " as required by this binding" } else { "" },
|
||||
opt_span,
|
||||
),
|
||||
}
|
||||
err
|
||||
}
|
||||
infer::RelateRegionParamBound(span) => {
|
||||
let mut err =
|
||||
struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied");
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"lifetime parameter instantiated with ",
|
||||
sup,
|
||||
"",
|
||||
None,
|
||||
);
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"but lifetime parameter must outlive ",
|
||||
sub,
|
||||
"",
|
||||
None,
|
||||
);
|
||||
err
|
||||
}
|
||||
infer::DataBorrowed(ty, span) => {
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
E0490,
|
||||
"a value of type `{}` is borrowed for too long",
|
||||
self.ty_to_string(ty)
|
||||
);
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"the type is valid for ",
|
||||
sub,
|
||||
"",
|
||||
None,
|
||||
);
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"but the borrow lasts for ",
|
||||
sup,
|
||||
"",
|
||||
None,
|
||||
);
|
||||
err
|
||||
}
|
||||
infer::ReferenceOutlivesReferent(ty, span) => {
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
E0491,
|
||||
"in type `{}`, reference has a longer lifetime than the data it references",
|
||||
self.ty_to_string(ty)
|
||||
);
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"the pointer is valid for ",
|
||||
sub,
|
||||
"",
|
||||
None,
|
||||
);
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"but the referenced data is only valid for ",
|
||||
sup,
|
||||
"",
|
||||
None,
|
||||
);
|
||||
err
|
||||
}
|
||||
infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => self
|
||||
.report_extra_impl_obligation(
|
||||
span,
|
||||
impl_item_def_id,
|
||||
trait_item_def_id,
|
||||
&format!("`{}: {}`", sup, sub),
|
||||
),
|
||||
infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
|
||||
let mut err = self.report_concrete_failure(*parent, sub, sup);
|
||||
|
||||
let trait_item_span = self.tcx.def_span(trait_item_def_id);
|
||||
let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
|
||||
err.span_label(
|
||||
trait_item_span,
|
||||
format!("definition of `{}` from trait", item_name),
|
||||
);
|
||||
|
||||
let trait_predicates = self.tcx.explicit_predicates_of(trait_item_def_id);
|
||||
let impl_predicates = self.tcx.explicit_predicates_of(impl_item_def_id);
|
||||
|
||||
let impl_predicates: rustc_data_structures::fx::FxHashSet<_> =
|
||||
impl_predicates.predicates.into_iter().map(|(pred, _)| pred).collect();
|
||||
let clauses: Vec<_> = trait_predicates
|
||||
.predicates
|
||||
.into_iter()
|
||||
.filter(|&(pred, _)| !impl_predicates.contains(pred))
|
||||
.map(|(pred, _)| format!("{}", pred))
|
||||
.collect();
|
||||
|
||||
if !clauses.is_empty() {
|
||||
let generics = self.tcx.hir().get_generics(impl_item_def_id).unwrap();
|
||||
let where_clause_span = generics.tail_span_for_predicate_suggestion();
|
||||
|
||||
let suggestion = format!(
|
||||
"{} {}",
|
||||
generics.add_where_or_trailing_comma(),
|
||||
clauses.join(", "),
|
||||
);
|
||||
err.span_suggestion(
|
||||
where_clause_span,
|
||||
&format!(
|
||||
"try copying {} from the trait",
|
||||
if clauses.len() > 1 { "these clauses" } else { "this clause" }
|
||||
),
|
||||
suggestion,
|
||||
rustc_errors::Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
infer::AscribeUserTypeProvePredicate(span) => {
|
||||
let mut err =
|
||||
struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied");
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"lifetime instantiated with ",
|
||||
sup,
|
||||
"",
|
||||
None,
|
||||
);
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"but lifetime must outlive ",
|
||||
sub,
|
||||
"",
|
||||
None,
|
||||
);
|
||||
err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn report_placeholder_failure(
|
||||
&self,
|
||||
placeholder_origin: SubregionOrigin<'tcx>,
|
||||
sub: Region<'tcx>,
|
||||
sup: Region<'tcx>,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
// I can't think how to do better than this right now. -nikomatsakis
|
||||
debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure");
|
||||
match placeholder_origin {
|
||||
infer::Subtype(box ref trace)
|
||||
if matches!(
|
||||
&trace.cause.code().peel_derives(),
|
||||
ObligationCauseCode::BindingObligation(..)
|
||||
| ObligationCauseCode::ExprBindingObligation(..)
|
||||
) =>
|
||||
{
|
||||
// Hack to get around the borrow checker because trace.cause has an `Rc`.
|
||||
if let ObligationCauseCode::BindingObligation(_, span)
|
||||
| ObligationCauseCode::ExprBindingObligation(_, span, ..) =
|
||||
&trace.cause.code().peel_derives()
|
||||
{
|
||||
let span = *span;
|
||||
let mut err = self.report_concrete_failure(placeholder_origin, sub, sup);
|
||||
err.span_note(span, "the lifetime requirement is introduced here");
|
||||
err
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
infer::Subtype(box trace) => {
|
||||
let terr = TypeError::RegionsPlaceholderMismatch;
|
||||
return self.report_and_explain_type_error(trace, terr);
|
||||
}
|
||||
_ => return self.report_concrete_failure(placeholder_origin, sub, sup),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,203 +0,0 @@
|
|||
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
fn note_error_origin(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>,
|
||||
terr: TypeError<'tcx>,
|
||||
) {
|
||||
match *cause.code() {
|
||||
ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => {
|
||||
let ty = self.resolve_vars_if_possible(root_ty);
|
||||
if !matches!(ty.kind(), ty::Infer(ty::InferTy::TyVar(_) | ty::InferTy::FreshTy(_)))
|
||||
{
|
||||
// don't show type `_`
|
||||
if span.desugaring_kind() == Some(DesugaringKind::ForLoop)
|
||||
&& let ty::Adt(def, substs) = ty.kind()
|
||||
&& Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option)
|
||||
{
|
||||
err.span_label(span, format!("this is an iterator with items of type `{}`", substs.type_at(0)));
|
||||
} else {
|
||||
err.span_label(span, format!("this expression has type `{}`", ty));
|
||||
}
|
||||
}
|
||||
if let Some(ty::error::ExpectedFound { found, .. }) = exp_found
|
||||
&& ty.is_box() && ty.boxed_ty() == found
|
||||
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
|
||||
{
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"consider dereferencing the boxed value",
|
||||
format!("*{}", snippet),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
ObligationCauseCode::Pattern { origin_expr: false, span: Some(span), .. } => {
|
||||
err.span_label(span, "expected due to this");
|
||||
}
|
||||
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
|
||||
arm_block_id,
|
||||
arm_span,
|
||||
arm_ty,
|
||||
prior_arm_block_id,
|
||||
prior_arm_span,
|
||||
prior_arm_ty,
|
||||
source,
|
||||
ref prior_arms,
|
||||
scrut_hir_id,
|
||||
opt_suggest_box_span,
|
||||
scrut_span,
|
||||
..
|
||||
}) => match source {
|
||||
hir::MatchSource::TryDesugar => {
|
||||
if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found {
|
||||
let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id);
|
||||
let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind {
|
||||
let arg_expr = args.first().expect("try desugaring call w/out arg");
|
||||
self.typeck_results.as_ref().and_then(|typeck_results| {
|
||||
typeck_results.expr_ty_opt(arg_expr)
|
||||
})
|
||||
} else {
|
||||
bug!("try desugaring w/out call expr as scrutinee");
|
||||
};
|
||||
|
||||
match scrut_ty {
|
||||
Some(ty) if expected == ty => {
|
||||
let source_map = self.tcx.sess.source_map();
|
||||
err.span_suggestion(
|
||||
source_map.end_point(cause.span),
|
||||
"try removing this `?`",
|
||||
"",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// `prior_arm_ty` can be `!`, `expected` will have better info when present.
|
||||
let t = self.resolve_vars_if_possible(match exp_found {
|
||||
Some(ty::error::ExpectedFound { expected, .. }) => expected,
|
||||
_ => prior_arm_ty,
|
||||
});
|
||||
let source_map = self.tcx.sess.source_map();
|
||||
let mut any_multiline_arm = source_map.is_multiline(arm_span);
|
||||
if prior_arms.len() <= 4 {
|
||||
for sp in prior_arms {
|
||||
any_multiline_arm |= source_map.is_multiline(*sp);
|
||||
err.span_label(*sp, format!("this is found to be of type `{}`", t));
|
||||
}
|
||||
} else if let Some(sp) = prior_arms.last() {
|
||||
any_multiline_arm |= source_map.is_multiline(*sp);
|
||||
err.span_label(
|
||||
*sp,
|
||||
format!("this and all prior arms are found to be of type `{}`", t),
|
||||
);
|
||||
}
|
||||
let outer_error_span = if any_multiline_arm {
|
||||
// Cover just `match` and the scrutinee expression, not
|
||||
// the entire match body, to reduce diagram noise.
|
||||
cause.span.shrink_to_lo().to(scrut_span)
|
||||
} else {
|
||||
cause.span
|
||||
};
|
||||
let msg = "`match` arms have incompatible types";
|
||||
err.span_label(outer_error_span, msg);
|
||||
self.suggest_remove_semi_or_return_binding(
|
||||
err,
|
||||
prior_arm_block_id,
|
||||
prior_arm_ty,
|
||||
prior_arm_span,
|
||||
arm_block_id,
|
||||
arm_ty,
|
||||
arm_span,
|
||||
);
|
||||
if let Some(ret_sp) = opt_suggest_box_span {
|
||||
// Get return type span and point to it.
|
||||
self.suggest_boxing_for_return_impl_trait(
|
||||
err,
|
||||
ret_sp,
|
||||
prior_arms.iter().chain(std::iter::once(&arm_span)).map(|s| *s),
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
ObligationCauseCode::IfExpression(box IfExpressionCause {
|
||||
then_id,
|
||||
else_id,
|
||||
then_ty,
|
||||
else_ty,
|
||||
outer_span,
|
||||
opt_suggest_box_span,
|
||||
}) => {
|
||||
let then_span = self.find_block_span_from_hir_id(then_id);
|
||||
let else_span = self.find_block_span_from_hir_id(else_id);
|
||||
err.span_label(then_span, "expected because of this");
|
||||
if let Some(sp) = outer_span {
|
||||
err.span_label(sp, "`if` and `else` have incompatible types");
|
||||
}
|
||||
self.suggest_remove_semi_or_return_binding(
|
||||
err,
|
||||
Some(then_id),
|
||||
then_ty,
|
||||
then_span,
|
||||
Some(else_id),
|
||||
else_ty,
|
||||
else_span,
|
||||
);
|
||||
if let Some(ret_sp) = opt_suggest_box_span {
|
||||
self.suggest_boxing_for_return_impl_trait(
|
||||
err,
|
||||
ret_sp,
|
||||
[then_span, else_span].into_iter(),
|
||||
);
|
||||
}
|
||||
}
|
||||
ObligationCauseCode::LetElse => {
|
||||
err.help("try adding a diverging expression, such as `return` or `panic!(..)`");
|
||||
err.help("...or use `match` instead of `let...else`");
|
||||
}
|
||||
_ => {
|
||||
if let ObligationCauseCode::BindingObligation(_, span)
|
||||
| ObligationCauseCode::ExprBindingObligation(_, span, ..)
|
||||
= cause.code().peel_derives()
|
||||
&& let TypeError::RegionsPlaceholderMismatch = terr
|
||||
{
|
||||
err.span_note( * span,
|
||||
"the lifetime requirement is introduced here");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
/// Given a [`hir::Block`], get the span of its last expression or
|
||||
/// statement, peeling off any inner blocks.
|
||||
pub fn find_block_span(&self, block: &'tcx hir::Block<'tcx>) -> Span {
|
||||
let block = block.innermost_block();
|
||||
if let Some(expr) = &block.expr {
|
||||
expr.span
|
||||
} else if let Some(stmt) = block.stmts.last() {
|
||||
// possibly incorrect trailing `;` in the else arm
|
||||
stmt.span
|
||||
} else {
|
||||
// empty block; point at its entirety
|
||||
block.span
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a [`hir::HirId`] for a block, get the span of its last expression
|
||||
/// or statement, peeling off any inner blocks.
|
||||
pub fn find_block_span_from_hir_id(&self, hir_id: hir::HirId) -> Span {
|
||||
match self.tcx.hir().get(hir_id) {
|
||||
hir::Node::Block(blk) => self.find_block_span(blk),
|
||||
// The parser was in a weird state if either of these happen, but
|
||||
// it's better not to panic.
|
||||
hir::Node::Expr(e) => e.span,
|
||||
_ => rustc_span::DUMMY_SP,
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue