From 852ee94f9cc96e11744299c5b0ba16bb52bf0e48 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 8 Jul 2024 22:12:07 -0400 Subject: [PATCH 1/2] Move some diagnostic-relevant methods from InferCtxt to TypeErrCtxt --- .../src/diagnostics/region_name.rs | 14 +- compiler/rustc_hir_typeck/src/_match.rs | 4 +- compiler/rustc_hir_typeck/src/closure.rs | 6 +- compiler/rustc_hir_typeck/src/coercion.rs | 4 +- compiler/rustc_hir_typeck/src/expr.rs | 2 +- .../src/fn_ctxt/suggestions.rs | 14 +- .../rustc_hir_typeck/src/method/suggest.rs | 2 +- .../src/infer/error_reporting/mod.rs | 8 +- .../infer/error_reporting/need_type_info.rs | 8 +- .../src/infer/error_reporting/note.rs | 2 +- .../src/traits/error_reporting/mod.rs | 8 +- .../traits/error_reporting/infer_ctxt_ext.rs | 244 ------------------ .../src/traits/error_reporting/mod.rs | 2 - .../error_reporting/on_unimplemented.rs | 2 +- .../src/traits/error_reporting/suggestions.rs | 2 +- .../error_reporting/type_err_ctxt_ext.rs | 234 ++++++++++++++++- 16 files changed, 273 insertions(+), 283 deletions(-) delete mode 100644 compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 356416d1a7563..e09925eb33595 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -457,8 +457,11 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { ) -> RegionNameHighlight { let mut highlight = RegionHighlightMode::default(); highlight.highlighting_region_vid(self.infcx.tcx, needle_fr, counter); - let type_name = - self.infcx.extract_inference_diagnostics_data(ty.into(), Some(highlight)).name; + let type_name = self + .infcx + .err_ctxt() + .extract_inference_diagnostics_data(ty.into(), Some(highlight)) + .name; debug!( "highlight_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}", @@ -872,8 +875,11 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { let mut highlight = RegionHighlightMode::default(); highlight.highlighting_region_vid(tcx, fr, *self.next_region_name.try_borrow().unwrap()); - let type_name = - self.infcx.extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)).name; + let type_name = self + .infcx + .err_ctxt() + .extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)) + .name; let yield_span = match tcx.hir_node(self.mir_hir_id()) { hir::Node::Expr(hir::Expr { diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 4e2104ff56155..2a148287b6ad3 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -87,7 +87,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.return_position_impl_trait_from_match_expectation(orig_expected); let (arm_block_id, arm_span) = if let hir::ExprKind::Block(blk, _) = arm.body.kind { - (Some(blk.hir_id), self.find_block_span(blk)) + (Some(blk.hir_id), self.err_ctxt().find_block_span(blk)) } else { (None, arm.body.span) }; @@ -477,7 +477,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { *outer_span = outer_span.with_hi(cond_span.hi()) } - (self.find_block_span(block), block.hir_id) + (self.err_ctxt().find_block_span(block), block.hir_id) } else { (else_expr.span, else_expr.hir_id) }; diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index ac7ed3e26f976..a44d3836b3b8d 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -18,8 +18,7 @@ use rustc_span::def_id::LocalDefId; use rustc_span::Span; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits; -use rustc_trait_selection::traits::error_reporting::ArgKind; -use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; +use rustc_trait_selection::traits::error_reporting::{ArgKind, TypeErrCtxtExt}; use rustc_type_ir::ClosureKind; use std::iter; use std::ops::ControlFlow; @@ -648,13 +647,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .map(|ty| ArgKind::from_expected_ty(*ty, None)) .collect(); let (closure_span, closure_arg_span, found_args) = - match self.get_fn_like_arguments(expr_map_node) { + match self.err_ctxt().get_fn_like_arguments(expr_map_node) { Some((sp, arg_sp, args)) => (Some(sp), arg_sp, args), None => (None, None, Vec::new()), }; let expected_span = expected_sig.cause_span.unwrap_or_else(|| self.tcx.def_span(expr_def_id)); let guar = self + .err_ctxt() .report_arg_count_mismatch( expected_span, closure_span, diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 4f0a089ee956f..90e054d6c799a 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1665,8 +1665,8 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { found, coercion_error, ); - let then_span = fcx.find_block_span_from_hir_id(then_id); - let else_span = fcx.find_block_span_from_hir_id(else_id); + let then_span = fcx.err_ctxt().find_block_span_from_hir_id(then_id); + let else_span = fcx.err_ctxt().find_block_span_from_hir_id(else_id); // don't suggest wrapping either blocks in `if .. {} else {}` let is_empty_arm = |id| { let hir::Node::Block(blk) = fcx.tcx.hir_node(id) else { diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index bd5e5294983d2..99e098e397d23 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2507,7 +2507,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base: &'tcx hir::Expr<'tcx>, ty: Ty<'tcx>, ) { - let Some(output_ty) = self.get_impl_future_output_ty(ty) else { + let Some(output_ty) = self.err_ctxt().get_impl_future_output_ty(ty) else { err.span_label(field_ident.span, "unknown field"); return; }; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index fca0a3e195d77..60df868ca008f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1085,12 +1085,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .tcx .instantiate_bound_regions_with_erased(Binder::bind_with_vars(ty, bound_vars)); let ty = match self.tcx.asyncness(fn_id) { - ty::Asyncness::Yes => self.get_impl_future_output_ty(ty).unwrap_or_else(|| { - span_bug!( - fn_decl.output.span(), - "failed to get output type of async function" - ) - }), + ty::Asyncness::Yes => { + self.err_ctxt().get_impl_future_output_ty(ty).unwrap_or_else(|| { + span_bug!( + fn_decl.output.span(), + "failed to get output type of async function" + ) + }) + } ty::Asyncness::No => ty, }; let ty = self.normalize(expr.span, ty); diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index dba3edbc1d722..95e5038c238cf 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -3165,7 +3165,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, return_type: Option>, ) { - let output_ty = match self.get_impl_future_output_ty(ty) { + let output_ty = match self.err_ctxt().get_impl_future_output_ty(ty) { Some(output_ty) => self.resolve_vars_if_possible(output_ty), _ => return, }; diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index cebb9d09a4798..451c70ed3c947 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -398,7 +398,7 @@ pub fn unexpected_hidden_region_diagnostic<'a, 'tcx>( err } -impl<'tcx> InferCtxt<'tcx> { +impl<'tcx> TypeErrCtxt<'_, 'tcx> { pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option> { let (def_id, args) = match *ty.kind() { ty::Alias(_, ty::AliasTy { def_id, args, .. }) @@ -2367,7 +2367,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trait_item_def_id, }) = origin { - return self.infcx.report_extra_impl_obligation( + return self.report_extra_impl_obligation( span, impl_item_def_id, trait_item_def_id, @@ -2792,7 +2792,7 @@ impl<'tcx> TypeRelation> for SameTypeModuloInfer<'_, 'tcx> { } } -impl<'tcx> InferCtxt<'tcx> { +impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn report_inference_failure(&self, var_origin: RegionVariableOrigin) -> Diag<'_> { let br_string = |br: ty::BoundRegionKind| { let mut s = match br { @@ -3031,7 +3031,7 @@ impl TyCategory { } } -impl<'tcx> InferCtxt<'tcx> { +impl<'tcx> TypeErrCtxt<'_, '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 { diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 084aebc296f86..b1aaf7a433099 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -289,7 +289,7 @@ fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>) -> String { format!("fn({args}){ret}") } -impl<'tcx> InferCtxt<'tcx> { +impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// Extracts data used by diagnostic for either types or constants /// which were stuck during inference. pub fn extract_inference_diagnostics_data( @@ -391,7 +391,7 @@ impl<'tcx> InferCtxt<'tcx> { span: Span, arg_data: InferenceDiagnosticsData, error_code: TypeAnnotationNeeded, - ) -> Diag<'_> { + ) -> Diag<'a> { let source_kind = "other"; let source_name = ""; let failure_span = None; @@ -453,7 +453,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // If we don't have any typeck results we're outside // of a body, so we won't be able to get better info // here. - return self.infcx.bad_inference_failure_err(failure_span, arg_data, error_code); + return self.bad_inference_failure_err(failure_span, arg_data, error_code); }; let mut local_visitor = FindInferSourceVisitor::new(self, typeck_results, arg); @@ -465,7 +465,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } let Some(InferSource { span, kind }) = local_visitor.infer_source else { - return self.infcx.bad_inference_failure_err(failure_span, arg_data, error_code); + return self.bad_inference_failure_err(failure_span, arg_data, error_code); }; let (source_kind, name, path) = kind.ty_localized_msg(self); diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index d1fc9c9f140b1..e37b0b83f4d00 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -245,7 +245,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) } infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => { - let mut err = self.infcx.report_extra_impl_obligation( + let mut err = self.report_extra_impl_obligation( span, impl_item_def_id, trait_item_def_id, diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs index 7730fe29e0933..268a48d2b2f71 100644 --- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs @@ -1,6 +1,6 @@ use super::ObjectSafetyViolation; +use crate::infer::error_reporting::TypeErrCtxt; -use crate::infer::InferCtxt; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag, MultiSpan}; use rustc_hir as hir; @@ -11,9 +11,9 @@ use rustc_span::Span; use std::fmt; use std::iter; -impl<'tcx> InferCtxt<'tcx> { - pub fn report_extra_impl_obligation<'a>( - &'a self, +impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { + pub fn report_extra_impl_obligation( + &self, error_span: Span, impl_item_def_id: LocalDefId, trait_item_def_id: DefId, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs deleted file mode 100644 index 34da8e576ce86..0000000000000 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs +++ /dev/null @@ -1,244 +0,0 @@ -use crate::infer::InferCtxt; -use crate::traits::{Obligation, ObligationCause, ObligationCtxt}; -use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, Diag}; -use rustc_hir as hir; -use rustc_hir::Node; -use rustc_macros::extension; -use rustc_middle::ty::{self, Ty}; -use rustc_span::{Span, DUMMY_SP}; - -use super::ArgKind; - -pub use rustc_infer::traits::error_reporting::*; - -#[extension(pub trait InferCtxtExt<'tcx>)] -impl<'tcx> InferCtxt<'tcx> { - /// Given some node representing a fn-like thing in the HIR map, - /// returns a span and `ArgKind` information that describes the - /// arguments it expects. This can be supplied to - /// `report_arg_count_mismatch`. - fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Option, Vec)> { - let sm = self.tcx.sess.source_map(); - let hir = self.tcx.hir(); - Some(match node { - Node::Expr(&hir::Expr { - kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, fn_arg_span, .. }), - .. - }) => ( - fn_decl_span, - fn_arg_span, - hir.body(body) - .params - .iter() - .map(|arg| { - if let hir::Pat { kind: hir::PatKind::Tuple(args, _), span, .. } = *arg.pat - { - Some(ArgKind::Tuple( - Some(span), - args.iter() - .map(|pat| { - sm.span_to_snippet(pat.span) - .ok() - .map(|snippet| (snippet, "_".to_owned())) - }) - .collect::>>()?, - )) - } else { - let name = sm.span_to_snippet(arg.pat.span).ok()?; - Some(ArgKind::Arg(name, "_".to_owned())) - } - }) - .collect::>>()?, - ), - Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref sig, ..), .. }) - | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(ref sig, _), .. }) - | Node::TraitItem(&hir::TraitItem { - kind: hir::TraitItemKind::Fn(ref sig, _), .. - }) => ( - sig.span, - None, - sig.decl - .inputs - .iter() - .map(|arg| match arg.kind { - hir::TyKind::Tup(tys) => ArgKind::Tuple( - Some(arg.span), - vec![("_".to_owned(), "_".to_owned()); tys.len()], - ), - _ => ArgKind::empty(), - }) - .collect::>(), - ), - Node::Ctor(variant_data) => { - let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id)); - (span, None, vec![ArgKind::empty(); variant_data.fields().len()]) - } - _ => panic!("non-FnLike node found: {node:?}"), - }) - } - - /// Reports an error when the number of arguments needed by a - /// trait match doesn't match the number that the expression - /// provides. - fn report_arg_count_mismatch( - &self, - span: Span, - found_span: Option, - expected_args: Vec, - found_args: Vec, - is_closure: bool, - closure_arg_span: Option, - ) -> Diag<'_> { - let kind = if is_closure { "closure" } else { "function" }; - - let args_str = |arguments: &[ArgKind], other: &[ArgKind]| { - let arg_length = arguments.len(); - let distinct = matches!(other, &[ArgKind::Tuple(..)]); - match (arg_length, arguments.get(0)) { - (1, Some(ArgKind::Tuple(_, fields))) => { - format!("a single {}-tuple as argument", fields.len()) - } - _ => format!( - "{} {}argument{}", - arg_length, - if distinct && arg_length > 1 { "distinct " } else { "" }, - pluralize!(arg_length) - ), - } - }; - - let expected_str = args_str(&expected_args, &found_args); - let found_str = args_str(&found_args, &expected_args); - - let mut err = struct_span_code_err!( - self.dcx(), - span, - E0593, - "{} is expected to take {}, but it takes {}", - kind, - expected_str, - found_str, - ); - - err.span_label(span, format!("expected {kind} that takes {expected_str}")); - - if let Some(found_span) = found_span { - err.span_label(found_span, format!("takes {found_str}")); - - // Suggest to take and ignore the arguments with expected_args_length `_`s if - // found arguments is empty (assume the user just wants to ignore args in this case). - // For example, if `expected_args_length` is 2, suggest `|_, _|`. - if found_args.is_empty() && is_closure { - let underscores = vec!["_"; expected_args.len()].join(", "); - err.span_suggestion_verbose( - closure_arg_span.unwrap_or(found_span), - format!( - "consider changing the closure to take and ignore the expected argument{}", - pluralize!(expected_args.len()) - ), - format!("|{underscores}|"), - Applicability::MachineApplicable, - ); - } - - if let &[ArgKind::Tuple(_, ref fields)] = &found_args[..] { - if fields.len() == expected_args.len() { - let sugg = fields - .iter() - .map(|(name, _)| name.to_owned()) - .collect::>() - .join(", "); - err.span_suggestion_verbose( - found_span, - "change the closure to take multiple arguments instead of a single tuple", - format!("|{sugg}|"), - Applicability::MachineApplicable, - ); - } - } - if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..] - && fields.len() == found_args.len() - && is_closure - { - let sugg = format!( - "|({}){}|", - found_args - .iter() - .map(|arg| match arg { - ArgKind::Arg(name, _) => name.to_owned(), - _ => "_".to_owned(), - }) - .collect::>() - .join(", "), - // add type annotations if available - if found_args.iter().any(|arg| match arg { - ArgKind::Arg(_, ty) => ty != "_", - _ => false, - }) { - format!( - ": ({})", - fields - .iter() - .map(|(_, ty)| ty.to_owned()) - .collect::>() - .join(", ") - ) - } else { - String::new() - }, - ); - err.span_suggestion_verbose( - found_span, - "change the closure to accept a tuple instead of individual arguments", - sugg, - Applicability::MachineApplicable, - ); - } - } - - err - } - - /// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce` - /// in that order, and returns the generic type corresponding to the - /// argument of that trait (corresponding to the closure arguments). - fn type_implements_fn_trait( - &self, - param_env: ty::ParamEnv<'tcx>, - ty: ty::Binder<'tcx, Ty<'tcx>>, - polarity: ty::PredicatePolarity, - ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()> { - self.commit_if_ok(|_| { - for trait_def_id in [ - self.tcx.lang_items().fn_trait(), - self.tcx.lang_items().fn_mut_trait(), - self.tcx.lang_items().fn_once_trait(), - ] { - let Some(trait_def_id) = trait_def_id else { continue }; - // Make a fresh inference variable so we can determine what the generic parameters - // of the trait are. - let var = self.next_ty_var(DUMMY_SP); - // FIXME(effects) - let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, [ty.skip_binder(), var]); - let obligation = Obligation::new( - self.tcx, - ObligationCause::dummy(), - param_env, - ty.rebind(ty::TraitPredicate { trait_ref, polarity }), - ); - let ocx = ObligationCtxt::new(self); - ocx.register_obligation(obligation); - if ocx.select_all_or_error().is_empty() { - return Ok(( - self.tcx - .fn_trait_kind_from_def_id(trait_def_id) - .expect("expected to map DefId to ClosureKind"), - ty.rebind(self.resolve_vars_if_possible(var)), - )); - } - } - - Err(()) - }) - } -} diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 633d488f7be5f..ef57ada67f7f9 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1,7 +1,6 @@ // ignore-tidy-filelength :( pub mod ambiguity; -mod infer_ctxt_ext; pub mod on_unimplemented; pub mod suggestions; mod type_err_ctxt_ext; @@ -14,7 +13,6 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; use std::ops::ControlFlow; -pub use self::infer_ctxt_ext::*; pub use self::type_err_ctxt_ext::*; // When outputting impl candidates, prefer showing those that are more similar. diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 94b28426f43b6..f4ffd35678dae 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -4,7 +4,7 @@ use crate::errors::{ }; use crate::infer::error_reporting::TypeErrCtxt; use crate::infer::InferCtxtExt; -use crate::traits::error_reporting::type_err_ctxt_ext::InferCtxtPrivExt; +use crate::traits::error_reporting::type_err_ctxt_ext::TypeErrCtxtPrivExt; use rustc_ast::AttrArgs; use rustc_ast::AttrArgsEq; use rustc_ast::AttrKind; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 52edffce61459..0bf8de0708918 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -45,7 +45,7 @@ use std::borrow::Cow; use std::iter; use crate::infer::InferCtxtExt as _; -use crate::traits::error_reporting::type_err_ctxt_ext::InferCtxtPrivExt; +use crate::traits::error_reporting::type_err_ctxt_ext::TypeErrCtxtPrivExt; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_middle::ty::print::{ with_forced_trimmed_paths, with_no_trimmed_paths, PrintPolyTraitPredicateExt as _, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 5461f9e65affe..83557945a5de3 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -8,7 +8,6 @@ use crate::errors::{ use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode}; use crate::infer::InferCtxtExt as _; use crate::infer::{self, InferCtxt}; -use crate::traits::error_reporting::infer_ctxt_ext::InferCtxtExt; use crate::traits::error_reporting::{ambiguity, ambiguity::CandidateSource::*}; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::specialize::to_pretty_impl_header; @@ -1443,9 +1442,195 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { diag } + + /// Given some node representing a fn-like thing in the HIR map, + /// returns a span and `ArgKind` information that describes the + /// arguments it expects. This can be supplied to + /// `report_arg_count_mismatch`. + fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Option, Vec)> { + let sm = self.tcx.sess.source_map(); + let hir = self.tcx.hir(); + Some(match node { + Node::Expr(&hir::Expr { + kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, fn_arg_span, .. }), + .. + }) => ( + fn_decl_span, + fn_arg_span, + hir.body(body) + .params + .iter() + .map(|arg| { + if let hir::Pat { kind: hir::PatKind::Tuple(args, _), span, .. } = *arg.pat + { + Some(ArgKind::Tuple( + Some(span), + args.iter() + .map(|pat| { + sm.span_to_snippet(pat.span) + .ok() + .map(|snippet| (snippet, "_".to_owned())) + }) + .collect::>>()?, + )) + } else { + let name = sm.span_to_snippet(arg.pat.span).ok()?; + Some(ArgKind::Arg(name, "_".to_owned())) + } + }) + .collect::>>()?, + ), + Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref sig, ..), .. }) + | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(ref sig, _), .. }) + | Node::TraitItem(&hir::TraitItem { + kind: hir::TraitItemKind::Fn(ref sig, _), .. + }) => ( + sig.span, + None, + sig.decl + .inputs + .iter() + .map(|arg| match arg.kind { + hir::TyKind::Tup(tys) => ArgKind::Tuple( + Some(arg.span), + vec![("_".to_owned(), "_".to_owned()); tys.len()], + ), + _ => ArgKind::empty(), + }) + .collect::>(), + ), + Node::Ctor(variant_data) => { + let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id)); + (span, None, vec![ArgKind::empty(); variant_data.fields().len()]) + } + _ => panic!("non-FnLike node found: {node:?}"), + }) + } + + /// Reports an error when the number of arguments needed by a + /// trait match doesn't match the number that the expression + /// provides. + fn report_arg_count_mismatch( + &self, + span: Span, + found_span: Option, + expected_args: Vec, + found_args: Vec, + is_closure: bool, + closure_arg_span: Option, + ) -> Diag<'a> { + let kind = if is_closure { "closure" } else { "function" }; + + let args_str = |arguments: &[ArgKind], other: &[ArgKind]| { + let arg_length = arguments.len(); + let distinct = matches!(other, &[ArgKind::Tuple(..)]); + match (arg_length, arguments.get(0)) { + (1, Some(ArgKind::Tuple(_, fields))) => { + format!("a single {}-tuple as argument", fields.len()) + } + _ => format!( + "{} {}argument{}", + arg_length, + if distinct && arg_length > 1 { "distinct " } else { "" }, + pluralize!(arg_length) + ), + } + }; + + let expected_str = args_str(&expected_args, &found_args); + let found_str = args_str(&found_args, &expected_args); + + let mut err = struct_span_code_err!( + self.dcx(), + span, + E0593, + "{} is expected to take {}, but it takes {}", + kind, + expected_str, + found_str, + ); + + err.span_label(span, format!("expected {kind} that takes {expected_str}")); + + if let Some(found_span) = found_span { + err.span_label(found_span, format!("takes {found_str}")); + + // Suggest to take and ignore the arguments with expected_args_length `_`s if + // found arguments is empty (assume the user just wants to ignore args in this case). + // For example, if `expected_args_length` is 2, suggest `|_, _|`. + if found_args.is_empty() && is_closure { + let underscores = vec!["_"; expected_args.len()].join(", "); + err.span_suggestion_verbose( + closure_arg_span.unwrap_or(found_span), + format!( + "consider changing the closure to take and ignore the expected argument{}", + pluralize!(expected_args.len()) + ), + format!("|{underscores}|"), + Applicability::MachineApplicable, + ); + } + + if let &[ArgKind::Tuple(_, ref fields)] = &found_args[..] { + if fields.len() == expected_args.len() { + let sugg = fields + .iter() + .map(|(name, _)| name.to_owned()) + .collect::>() + .join(", "); + err.span_suggestion_verbose( + found_span, + "change the closure to take multiple arguments instead of a single tuple", + format!("|{sugg}|"), + Applicability::MachineApplicable, + ); + } + } + if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..] + && fields.len() == found_args.len() + && is_closure + { + let sugg = format!( + "|({}){}|", + found_args + .iter() + .map(|arg| match arg { + ArgKind::Arg(name, _) => name.to_owned(), + _ => "_".to_owned(), + }) + .collect::>() + .join(", "), + // add type annotations if available + if found_args.iter().any(|arg| match arg { + ArgKind::Arg(_, ty) => ty != "_", + _ => false, + }) { + format!( + ": ({})", + fields + .iter() + .map(|(_, ty)| ty.to_owned()) + .collect::>() + .join(", ") + ) + } else { + String::new() + }, + ); + err.span_suggestion_verbose( + found_span, + "change the closure to accept a tuple instead of individual arguments", + sugg, + Applicability::MachineApplicable, + ); + } + } + + err + } } -#[extension(pub(super) trait InferCtxtPrivExt<'a, 'tcx>)] +#[extension(pub(super) trait TypeErrCtxtPrivExt<'a, 'tcx>)] impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn can_match_trait( &self, @@ -3606,7 +3791,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) .unwrap_or((found_span, None, found)); - self.infcx.report_arg_count_mismatch( + self.report_arg_count_mismatch( span, closure_span, expected, @@ -3697,4 +3882,47 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } } + + /// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce` + /// in that order, and returns the generic type corresponding to the + /// argument of that trait (corresponding to the closure arguments). + fn type_implements_fn_trait( + &self, + param_env: ty::ParamEnv<'tcx>, + ty: ty::Binder<'tcx, Ty<'tcx>>, + polarity: ty::PredicatePolarity, + ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()> { + self.commit_if_ok(|_| { + for trait_def_id in [ + self.tcx.lang_items().fn_trait(), + self.tcx.lang_items().fn_mut_trait(), + self.tcx.lang_items().fn_once_trait(), + ] { + let Some(trait_def_id) = trait_def_id else { continue }; + // Make a fresh inference variable so we can determine what the generic parameters + // of the trait are. + let var = self.next_ty_var(DUMMY_SP); + // FIXME(effects) + let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, [ty.skip_binder(), var]); + let obligation = Obligation::new( + self.tcx, + ObligationCause::dummy(), + param_env, + ty.rebind(ty::TraitPredicate { trait_ref, polarity }), + ); + let ocx = ObligationCtxt::new(self); + ocx.register_obligation(obligation); + if ocx.select_all_or_error().is_empty() { + return Ok(( + self.tcx + .fn_trait_kind_from_def_id(trait_def_id) + .expect("expected to map DefId to ClosureKind"), + ty.rebind(self.resolve_vars_if_possible(var)), + )); + } + } + + Err(()) + }) + } } From 1da0e5c0d2c43f75063185b1c998e27c1e51d585 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 8 Jul 2024 22:42:34 -0400 Subject: [PATCH 2/2] Fix clippy, move a couple more methods --- .../src/diagnostics/conflict_errors.rs | 8 +- .../rustc_borrowck/src/diagnostics/mod.rs | 11 +- .../src/diagnostics/mutability_errors.rs | 3 +- .../src/fn_ctxt/suggestions.rs | 9 +- compiler/rustc_trait_selection/src/infer.rs | 37 +----- .../error_reporting/type_err_ctxt_ext.rs | 123 +++++++++++------- .../clippy/clippy_lints/src/eta_reduction.rs | 4 +- .../clippy_lints/src/functions/must_use.rs | 8 +- .../clippy/clippy_lints/src/no_effect.rs | 2 +- 9 files changed, 109 insertions(+), 96 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index c2c3f5bc79ed1..8bc2c65a676b7 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -36,7 +36,7 @@ use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{BytePos, Span, Symbol}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt; -use rustc_trait_selection::traits::error_reporting::FindExprBySpan; +use rustc_trait_selection::traits::error_reporting::{FindExprBySpan, TypeErrCtxtExt as _}; use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt}; use std::iter; use std::ops::ControlFlow; @@ -1860,7 +1860,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { && let ty::Ref(_, inner, _) = rcvr_ty.kind() && let inner = inner.peel_refs() && (Holds { ty: inner }).visit_ty(local_ty).is_break() - && let None = self.infcx.type_implements_trait_shallow(clone, inner, self.param_env) + && let None = self.infcx.err_ctxt().type_implements_trait_shallow( + clone, + inner, + self.param_env, + ) { err.span_label( span, diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 4567a014fe83d..44facd47b726f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -29,6 +29,7 @@ use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP}; use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; use rustc_trait_selection::traits::{ type_known_to_meet_bound_modulo_regions, FulfillmentErrorCode, }; @@ -1255,11 +1256,11 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { } else { vec![(move_span.shrink_to_hi(), ".clone()".to_string())] }; - if let Some(errors) = self.infcx.type_implements_trait_shallow( - clone_trait, - ty, - self.param_env, - ) && !has_sugg + if let Some(errors) = self + .infcx + .err_ctxt() + .type_implements_trait_shallow(clone_trait, ty, self.param_env) + && !has_sugg { let msg = match &errors[..] { [] => "you can `clone` the value and consume it, but this \ diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 677029f9d3f95..09df494b211c4 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -16,9 +16,9 @@ use rustc_middle::{ use rustc_span::symbol::{kw, Symbol}; use rustc_span::{sym, BytePos, DesugaringKind, Span}; use rustc_target::abi::FieldIdx; -use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits; use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; use crate::diagnostics::BorrowedContentSource; use crate::util::FindAssignments; @@ -1233,6 +1233,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { { match self .infcx + .err_ctxt() .type_implements_trait_shallow( clone_trait, ty.peel_refs(), diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 60df868ca008f..11b4bad1c5322 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -36,6 +36,7 @@ use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits; use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt; use rustc_trait_selection::traits::error_reporting::DefIdOrName; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -1717,9 +1718,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None, ); } else { - if let Some(errors) = - self.type_implements_trait_shallow(clone_trait_did, expected_ty, self.param_env) - { + if let Some(errors) = self.err_ctxt().type_implements_trait_shallow( + clone_trait_did, + expected_ty, + self.param_env, + ) { match &errors[..] { [] => {} [error] => { diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index ad087620ae06d..b1b7016a2eff8 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -1,6 +1,6 @@ use crate::infer::at::ToTrace; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; -use crate::traits::{self, Obligation, ObligationCause, ObligationCtxt, SelectionContext}; +use crate::traits::{self, ObligationCause, ObligationCtxt}; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; @@ -76,41 +76,6 @@ impl<'tcx> InferCtxt<'tcx> { }; self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr) } - - /// Returns `Some` if a type implements a trait shallowly, without side-effects, - /// along with any errors that would have been reported upon further obligation - /// processing. - /// - /// - If this returns `Some([])`, then the trait holds modulo regions. - /// - If this returns `Some([errors..])`, then the trait has an impl for - /// the self type, but some nested obligations do not hold. - /// - If this returns `None`, no implementation that applies could be found. - /// - /// FIXME(-Znext-solver): Due to the recursive nature of the new solver, - /// this will probably only ever return `Some([])` or `None`. - fn type_implements_trait_shallow( - &self, - trait_def_id: DefId, - ty: Ty<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> Option>> { - self.probe(|_snapshot| { - let mut selcx = SelectionContext::new(self); - match selcx.select(&Obligation::new( - self.tcx, - ObligationCause::dummy(), - param_env, - ty::TraitRef::new(self.tcx, trait_def_id, [ty]), - )) { - Ok(Some(selection)) => { - let ocx = ObligationCtxt::new_with_diagnostics(self); - ocx.register_obligations(selection.nested_obligations()); - Some(ocx.select_all_or_error()) - } - Ok(None) | Err(_) => None, - } - }) - } } #[extension(pub trait InferCtxtBuilderExt<'tcx>)] diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 83557945a5de3..872ee37516b2e 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -11,12 +11,12 @@ use crate::infer::{self, InferCtxt}; use crate::traits::error_reporting::{ambiguity, ambiguity::CandidateSource::*}; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::specialize::to_pretty_impl_header; -use crate::traits::NormalizeExt; use crate::traits::{ elaborate, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, Obligation, ObligationCause, ObligationCauseCode, ObligationCtxt, Overflow, PredicateObligation, SelectionError, SignatureMismatch, TraitNotObjectSafe, }; +use crate::traits::{NormalizeExt, SelectionContext}; use core::ops::ControlFlow; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::unord::UnordSet; @@ -1628,6 +1628,84 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err } + + /// Returns `Some` if a type implements a trait shallowly, without side-effects, + /// along with any errors that would have been reported upon further obligation + /// processing. + /// + /// - If this returns `Some([])`, then the trait holds modulo regions. + /// - If this returns `Some([errors..])`, then the trait has an impl for + /// the self type, but some nested obligations do not hold. + /// - If this returns `None`, no implementation that applies could be found. + /// + /// FIXME(-Znext-solver): Due to the recursive nature of the new solver, + /// this will probably only ever return `Some([])` or `None`. + fn type_implements_trait_shallow( + &self, + trait_def_id: DefId, + ty: Ty<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> Option>> { + self.probe(|_snapshot| { + let mut selcx = SelectionContext::new(self); + match selcx.select(&Obligation::new( + self.tcx, + ObligationCause::dummy(), + param_env, + ty::TraitRef::new(self.tcx, trait_def_id, [ty]), + )) { + Ok(Some(selection)) => { + let ocx = ObligationCtxt::new_with_diagnostics(self); + ocx.register_obligations(selection.nested_obligations()); + Some(ocx.select_all_or_error()) + } + Ok(None) | Err(_) => None, + } + }) + } + + /// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce` + /// in that order, and returns the generic type corresponding to the + /// argument of that trait (corresponding to the closure arguments). + fn type_implements_fn_trait( + &self, + param_env: ty::ParamEnv<'tcx>, + ty: ty::Binder<'tcx, Ty<'tcx>>, + polarity: ty::PredicatePolarity, + ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()> { + self.commit_if_ok(|_| { + for trait_def_id in [ + self.tcx.lang_items().fn_trait(), + self.tcx.lang_items().fn_mut_trait(), + self.tcx.lang_items().fn_once_trait(), + ] { + let Some(trait_def_id) = trait_def_id else { continue }; + // Make a fresh inference variable so we can determine what the generic parameters + // of the trait are. + let var = self.next_ty_var(DUMMY_SP); + // FIXME(effects) + let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, [ty.skip_binder(), var]); + let obligation = Obligation::new( + self.tcx, + ObligationCause::dummy(), + param_env, + ty.rebind(ty::TraitPredicate { trait_ref, polarity }), + ); + let ocx = ObligationCtxt::new(self); + ocx.register_obligation(obligation); + if ocx.select_all_or_error().is_empty() { + return Ok(( + self.tcx + .fn_trait_kind_from_def_id(trait_def_id) + .expect("expected to map DefId to ClosureKind"), + ty.rebind(self.resolve_vars_if_possible(var)), + )); + } + } + + Err(()) + }) + } } #[extension(pub(super) trait TypeErrCtxtPrivExt<'a, 'tcx>)] @@ -3882,47 +3960,4 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } } - - /// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce` - /// in that order, and returns the generic type corresponding to the - /// argument of that trait (corresponding to the closure arguments). - fn type_implements_fn_trait( - &self, - param_env: ty::ParamEnv<'tcx>, - ty: ty::Binder<'tcx, Ty<'tcx>>, - polarity: ty::PredicatePolarity, - ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()> { - self.commit_if_ok(|_| { - for trait_def_id in [ - self.tcx.lang_items().fn_trait(), - self.tcx.lang_items().fn_mut_trait(), - self.tcx.lang_items().fn_once_trait(), - ] { - let Some(trait_def_id) = trait_def_id else { continue }; - // Make a fresh inference variable so we can determine what the generic parameters - // of the trait are. - let var = self.next_ty_var(DUMMY_SP); - // FIXME(effects) - let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, [ty.skip_binder(), var]); - let obligation = Obligation::new( - self.tcx, - ObligationCause::dummy(), - param_env, - ty.rebind(ty::TraitPredicate { trait_ref, polarity }), - ); - let ocx = ObligationCtxt::new(self); - ocx.register_obligation(obligation); - if ocx.select_all_or_error().is_empty() { - return Ok(( - self.tcx - .fn_trait_kind_from_def_id(trait_def_id) - .expect("expected to map DefId to ClosureKind"), - ty.rebind(self.resolve_vars_if_possible(var)), - )); - } - } - - Err(()) - }) - } } diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index 42ec2c00823c8..9d5bfe75ddfee 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::{ use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; use rustc_target::spec::abi::Abi; -use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; declare_clippy_lint! { /// ### What it does @@ -178,7 +178,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { // 'cuz currently nothing changes after deleting this check. local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr) }) { - match cx.tcx.infer_ctxt().build().type_implements_fn_trait( + match cx.tcx.infer_ctxt().build().err_ctxt().type_implements_fn_trait( cx.param_env, Binder::bind_with_vars(callee_ty_adjusted, List::empty()), ty::PredicatePolarity::Positive, diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index cce8617821e2c..1f0ed3039527e 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -116,8 +116,12 @@ fn check_needless_must_use( } else if attr.value_str().is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) { // Ignore async functions unless Future::Output type is a must_use type if sig.header.is_async() { - let infcx = cx.tcx.infer_ctxt().build(); - if let Some(future_ty) = infcx.get_impl_future_output_ty(return_ty(cx, item_id)) + if let Some(future_ty) = cx + .tcx + .infer_ctxt() + .build() + .err_ctxt() + .get_impl_future_output_ty(return_ty(cx, item_id)) && !is_must_use_ty(cx, future_ty) { return; diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index 87f886b1128d8..5b097df691e53 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -157,7 +157,7 @@ impl NoEffect { // Remove `impl Future` to get `T` if cx.tcx.ty_is_opaque_future(ret_ty) && let Some(true_ret_ty) = - cx.tcx.infer_ctxt().build().get_impl_future_output_ty(ret_ty) + cx.tcx.infer_ctxt().build().err_ctxt().get_impl_future_output_ty(ret_ty) { ret_ty = true_ret_ty; }