diff options
Diffstat (limited to 'compiler/rustc_hir_typeck/src/fn_ctxt')
6 files changed, 252 insertions, 187 deletions
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 750ed2c34..4bc237c23 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -72,7 +72,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { orig_span, custom_note .unwrap_or("any code following this expression is unreachable"), - ) + ); }, ) } @@ -83,7 +83,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// version (resolve_vars_if_possible), this version will /// also select obligations if it seems useful, in an effort /// to get more type information. - // FIXME(-Ztrait-solver=next): A lot of the calls to this method should + // FIXME(-Znext-solver): A lot of the calls to this method should // probably be `try_structurally_resolve_type` or `structurally_resolve_type` instead. #[instrument(skip(self), level = "debug", ret)] pub(in super::super) fn resolve_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { @@ -159,7 +159,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } #[instrument(level = "debug", skip(self))] - pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) { + pub fn write_method_call_and_enforce_effects( + &self, + hir_id: hir::HirId, + span: Span, + method: MethodCallee<'tcx>, + ) { + self.enforce_context_effects(span, method.def_id, method.args); self.write_resolution(hir_id, Ok((DefKind::AssocFn, method.def_id))); self.write_args(hir_id, method.args); } @@ -271,7 +277,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME: currently we never try to compose autoderefs // and ReifyFnPointer/UnsafeFnPointer, but we could. _ => { - self.tcx.sess.delay_span_bug( + self.tcx.sess.span_delayed_bug( expr.span, format!( "while adjusting {:?}, can't compose {:?} and {:?}", @@ -505,7 +511,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn resolve_rvalue_scopes(&self, def_id: DefId) { let scope_tree = self.tcx.region_scope_tree(def_id); - let rvalue_scopes = { rvalue_scopes::resolve_rvalue_scopes(self, &scope_tree, def_id) }; + let rvalue_scopes = { rvalue_scopes::resolve_rvalue_scopes(self, scope_tree, def_id) }; let mut typeck_results = self.inh.typeck_results.borrow_mut(); typeck_results.rvalue_scopes = rvalue_scopes; } @@ -651,20 +657,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::NormalizesTo(..) | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) - // N.B., this predicate is created by breaking down a - // `ClosureType: FnFoo()` predicate, where - // `ClosureType` represents some `Closure`. It can't - // possibly be referring to the current closure, - // because we haven't produced the `Closure` for - // this closure yet; this is exactly why the other - // code is looking for a self type of an unresolved - // inference variable. - | ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::Ambiguous - => None, + | ty::PredicateKind::Ambiguous => None, }, ) } @@ -754,7 +751,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lang_item: hir::LangItem, span: Span, hir_id: hir::HirId, - expr_hir_id: Option<hir::HirId>, ) -> (Res, Ty<'tcx>) { let def_id = self.tcx.require_lang_item(lang_item, Some(span)); let def_kind = self.tcx.def_kind(def_id); @@ -767,11 +763,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let args = self.fresh_args_for_item(span, def_id); let ty = item_ty.instantiate(self.tcx, args); + self.write_args(hir_id, args); self.write_resolution(hir_id, Ok((def_kind, def_id))); let code = match lang_item { hir::LangItem::IntoFutureIntoFuture => { - Some(ObligationCauseCode::AwaitableExpr(expr_hir_id)) + if let hir::Node::Expr(into_future_call) = self.tcx.hir().get_parent(hir_id) + && let hir::ExprKind::Call(_, [arg0]) = &into_future_call.kind + { + Some(ObligationCauseCode::AwaitableExpr(arg0.hir_id)) + } else { + None + } } hir::LangItem::IteratorNext | hir::LangItem::IntoIterIntoIter => { Some(ObligationCauseCode::ForLoopIterator) @@ -804,7 +807,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { qpath, hir_id, span ); let (ty, qself, item_segment) = match *qpath { - QPath::Resolved(ref opt_qself, ref path) => { + QPath::Resolved(ref opt_qself, path) => { return ( path.res, opt_qself.as_ref().map(|qself| self.to_ty(qself)), @@ -845,7 +848,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let Some(mut diag) = self .tcx .sess - .diagnostic() + .dcx() .steal_diagnostic(qself.span, StashKey::TraitMissingMethod) { diag.emit(); @@ -856,7 +859,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let guar = self .tcx .sess - .delay_span_bug(span, "method resolution should've emitted an error"); + .span_delayed_bug(span, "method resolution should've emitted an error"); let result = match error { method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)), _ => Err(guar), @@ -881,7 +884,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let Some(mut diag) = self .tcx .sess - .diagnostic() + .dcx() .steal_diagnostic(qself.span, StashKey::TraitMissingMethod) { if trait_missing_method { @@ -991,7 +994,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or // `while` before reaching it, as block tail returns are not available in them. self.tcx.hir().get_return_block(blk_id).and_then(|blk_id| { - let parent = self.tcx.hir().get(blk_id); + let parent = self.tcx.hir_node(blk_id); self.get_node_fn_decl(parent) .map(|(fn_id, fn_decl, _, is_main)| (fn_id, fn_decl, is_main)) }) @@ -1186,7 +1189,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx, span, def_id, - &generics, + generics, seg, IsMethodCall::No, ); @@ -1278,7 +1281,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // going to infer the arguments for better error messages. if !self.infer_args_for_err.contains(&index) { // Check whether the user has provided generic arguments. - if let Some(ref data) = self.segments[index].args { + if let Some(data) = self.segments[index].args { return (Some(data), self.segments[index].infer_args); } } @@ -1406,7 +1409,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Normalize only after registering type annotations. let args = self.normalize(span, args_raw); - self.add_required_obligations_for_hir(span, def_id, &args, hir_id); + self.add_required_obligations_for_hir(span, def_id, args, hir_id); // Substitute the values for the type parameters into the type of // the referenced item. @@ -1430,7 +1433,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { Ok(ok) => self.register_infer_ok_obligations(ok), Err(_) => { - self.tcx.sess.delay_span_bug( + self.tcx.sess.span_delayed_bug( span, format!( "instantiate_value_path: (UFCS) {self_ty:?} was a subtype of {impl_ty:?} but now is not?", @@ -1473,7 +1476,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { let param_env = self.param_env; - let bounds = self.instantiate_bounds(span, def_id, &args); + let bounds = self.instantiate_bounds(span, def_id, args); for obligation in traits::predicates_for_generics( |idx, predicate_span| { @@ -1495,7 +1498,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = self.resolve_vars_with_obligations(ty); if self.next_trait_solver() - && let ty::Alias(ty::Projection | ty::Inherent | ty::Weak, _) = ty.kind() + && let ty::Alias(..) = ty.kind() { match self .at(&self.misc(sp), self.param_env) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index facbeb8ba..76360239c 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -4,7 +4,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_infer::{infer::type_variable::TypeVariableOriginKind, traits::ObligationCauseCode}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; -use rustc_span::{self, symbol::kw, Span}; +use rustc_span::{symbol::kw, Span}; use rustc_trait_selection::traits; use std::ops::ControlFlow; @@ -94,7 +94,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let hir = self.tcx.hir(); - let (expr, qpath) = match hir.get(hir_id) { + let (expr, qpath) = match self.tcx.hir_node(hir_id) { hir::Node::Expr(expr) => { if self.closure_span_overlaps_error(error, expr.span) { return false; @@ -454,7 +454,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .find_ancestor_in_same_ctxt(error.obligation.cause.span) .unwrap_or(arg.span); - if let hir::Node::Expr(arg_expr) = self.tcx.hir().get(arg.hir_id) { + if let hir::Node::Expr(arg_expr) = self.tcx.hir_node(arg.hir_id) { // This is more specific than pointing at the entire argument. self.blame_specific_expr_if_possible(error, arg_expr) } @@ -495,7 +495,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Whether it succeeded or failed, it likely made some amount of progress. // In the very worst case, it's just the same `expr` we originally passed in. let expr = match self.blame_specific_expr_if_possible_for_obligation_cause_code( - &error.obligation.cause.code(), + error.obligation.cause.code(), expr, ) { Ok(expr) => expr, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs index 7aadb95d9..566d407d2 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs @@ -4,11 +4,13 @@ use rustc_middle::ty::error::TypeError; use std::cmp; rustc_index::newtype_index! { + #[orderable] #[debug_format = "ExpectedIdx({})"] pub(crate) struct ExpectedIdx {} } rustc_index::newtype_index! { + #[orderable] #[debug_format = "ProvidedIdx({})"] pub(crate) struct ProvidedIdx {} } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 33dfa16a6..4caa0df58 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -33,7 +33,7 @@ use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt}; use rustc_session::Session; use rustc_span::symbol::{kw, Ident}; -use rustc_span::{self, sym, BytePos, Span}; +use rustc_span::{sym, BytePos, Span}; use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext}; use std::iter; @@ -230,11 +230,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let minimum_input_count = expected_input_tys.len(); let provided_arg_count = provided_args.len(); - let is_const_eval_select = matches!(fn_def_id, Some(def_id) if - self.tcx.def_kind(def_id) == hir::def::DefKind::Fn - && self.tcx.is_intrinsic(def_id) - && self.tcx.item_name(def_id) == sym::const_eval_select); - // We introduce a helper function to demand that a given argument satisfy a given input // This is more complicated than just checking type equality, as arguments could be coerced // This version writes those types back so further type checking uses the narrowed types @@ -269,35 +264,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return Compatibility::Incompatible(coerce_error); } - // Check that second and third argument of `const_eval_select` must be `FnDef`, and additionally that - // the second argument must be `const fn`. The first argument must be a tuple, but this is already expressed - // in the function signature (`F: FnOnce<ARG>`), so I did not bother to add another check here. - // - // This check is here because there is currently no way to express a trait bound for `FnDef` types only. - if is_const_eval_select && (1..=2).contains(&idx) { - if let ty::FnDef(def_id, args) = *checked_ty.kind() { - if idx == 1 { - if !self.tcx.is_const_fn_raw(def_id) { - self.tcx.sess.emit_err(errors::ConstSelectMustBeConst { - span: provided_arg.span, - }); - } else { - self.enforce_context_effects( - provided_arg.hir_id, - provided_arg.span, - def_id, - args, - ) - } - } - } else { - self.tcx.sess.emit_err(errors::ConstSelectMustBeFn { - span: provided_arg.span, - ty: checked_ty, - }); - } - } - // 3. Check if the formal type is a supertype of the checked one // and register any such obligations for future type checks let supertype_error = self.at(&self.misc(provided_arg.span), self.param_env).sup( @@ -397,7 +363,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for arg in provided_args.iter().skip(minimum_input_count) { // Make sure we've checked this expr at least once. - let arg_ty = self.check_expr(&arg); + let arg_ty = self.check_expr(arg); // If the function is c-style variadic, we skipped a bunch of arguments // so we need to check those, and write out the types @@ -522,7 +488,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx; // FIXME: taint after emitting errors and pass through an `ErrorGuaranteed` self.set_tainted_by_errors( - tcx.sess.delay_span_bug(call_span, "no errors reported for args"), + tcx.sess.span_delayed_bug(call_span, "no errors reported for args"), ); // Get the argument span in the context of the call span so that @@ -796,7 +762,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut err = self.err_ctxt().report_and_explain_type_error(trace, *err); self.emit_coerce_suggestions( &mut err, - &provided_args[*provided_idx], + provided_args[*provided_idx], provided_ty, Expectation::rvalue_hint(self, expected_ty) .only_has_type(self) @@ -925,7 +891,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.emit_coerce_suggestions( &mut err, - &provided_args[provided_idx], + provided_args[provided_idx], provided_ty, Expectation::rvalue_hint(self, expected_ty) .only_has_type(self) @@ -998,7 +964,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) { match e { Error::Missing(expected_idx) => missing_idxs.push(expected_idx), - _ => unreachable!(), + _ => unreachable!( + "control flow ensures that we should always get an `Error::Missing`" + ), } } @@ -1366,7 +1334,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let variant = match def { Res::Err => { let guar = - self.tcx.sess.delay_span_bug(path_span, "`Res::Err` but no error emitted"); + self.tcx.sess.span_delayed_bug(path_span, "`Res::Err` but no error emitted"); self.set_tainted_by_errors(guar); return Err(guar); } @@ -1469,7 +1437,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Type check the initializer. if let Some(ref init) = decl.init { - let init_ty = self.check_decl_initializer(decl.hir_id, decl.pat, &init); + let init_ty = self.check_decl_initializer(decl.hir_id, decl.pat, init); self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, init_ty); } @@ -1483,7 +1451,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Type check the pattern. Override if necessary to avoid knock-on errors. - self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr, Some(decl.origin)); + self.check_pat_top(decl.pat, decl_ty, ty_span, origin_expr, Some(decl.origin)); let pat_ty = self.node_ty(decl.pat.hir_id); self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, pat_ty); @@ -1525,13 +1493,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::StmtKind::Item(_) => {} hir::StmtKind::Expr(ref expr) => { // Check with expected type of `()`. - self.check_expr_has_type_or_error(&expr, Ty::new_unit(self.tcx), |err| { + self.check_expr_has_type_or_error(expr, Ty::new_unit(self.tcx), |err| { if expr.can_have_side_effects() { self.suggest_semicolon_at_end(expr.span, err); } }); } - hir::StmtKind::Semi(ref expr) => { + hir::StmtKind::Semi(expr) => { self.check_expr(expr); } } @@ -1739,7 +1707,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } fn parent_item_span(&self, id: hir::HirId) -> Option<Span> { - let node = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(id).def_id); + let node = self.tcx.hir_node_by_def_id(self.tcx.hir().get_parent_item(id).def_id); match node { Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. }) | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body_id), .. }) => { @@ -1755,7 +1723,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise. fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> { - let parent = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(blk_id).def_id); + let parent = self.tcx.hir_node_by_def_id(self.tcx.hir().get_parent_item(blk_id).def_id); self.get_node_fn_decl(parent).map(|(_, fn_decl, ident, _)| (fn_decl, ident)) } @@ -1820,12 +1788,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir_id: hir::HirId, ) -> (Res, RawTy<'tcx>) { match *qpath { - QPath::Resolved(ref maybe_qself, ref path) => { + QPath::Resolved(ref maybe_qself, path) => { let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself).raw); let ty = self.astconv().res_to_ty(self_ty, path, hir_id, true); (path.res, self.handle_raw_ty(path_span, ty)) } - QPath::TypeRelative(ref qself, ref segment) => { + QPath::TypeRelative(qself, segment) => { let ty = self.to_ty(qself); let result = self @@ -1842,8 +1810,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), ty) } - QPath::LangItem(lang_item, span, id) => { - let (res, ty) = self.resolve_lang_item_path(lang_item, span, hir_id, id); + QPath::LangItem(lang_item, span) => { + let (res, ty) = self.resolve_lang_item_path(lang_item, span, hir_id); (res, self.handle_raw_ty(path_span, ty)) } } @@ -1855,7 +1823,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { for (span, code) in errors_causecode { let Some(mut diag) = - self.tcx.sess.diagnostic().steal_diagnostic(span, StashKey::MaybeForgetReturn) + self.tcx.sess.dcx().steal_diagnostic(span, StashKey::MaybeForgetReturn) else { continue; }; @@ -1864,35 +1832,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let ExprBindingObligation(_, _, hir_id, ..) = code && !fn_sig.output().is_unit() { - let mut block_num = 0; - let mut found_semi = false; - for (_, node) in self.tcx.hir().parent_iter(hir_id) { - match node { - hir::Node::Stmt(stmt) => if let hir::StmtKind::Semi(ref expr) = stmt.kind { + let mut block_num = 0; + let mut found_semi = false; + for (_, node) in self.tcx.hir().parent_iter(hir_id) { + match node { + hir::Node::Stmt(stmt) => { + if let hir::StmtKind::Semi(expr) = stmt.kind { let expr_ty = self.typeck_results.borrow().expr_ty(expr); let return_ty = fn_sig.output(); - if !matches!(expr.kind, hir::ExprKind::Ret(..)) && - self.can_coerce(expr_ty, return_ty) { + if !matches!(expr.kind, hir::ExprKind::Ret(..)) + && self.can_coerce(expr_ty, return_ty) + { found_semi = true; } - }, - hir::Node::Block(_block) => if found_semi { + } + } + hir::Node::Block(_block) => { + if found_semi { block_num += 1; } - hir::Node::Item(item) => if let hir::ItemKind::Fn(..) = item.kind { + } + hir::Node::Item(item) => { + if let hir::ItemKind::Fn(..) = item.kind { break; } - _ => {} } + _ => {} } - if block_num > 1 && found_semi { - diag.span_suggestion_verbose( - span.shrink_to_lo(), - "you might have meant to return this to infer its type parameters", - "return ", - Applicability::MaybeIncorrect, - ); - } + } + if block_num > 1 && found_semi { + diag.span_suggestion_verbose( + span.shrink_to_lo(), + "you might have meant to return this to infer its type parameters", + "return ", + Applicability::MaybeIncorrect, + ); + } } diag.emit(); } @@ -2016,7 +1991,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let new_def_id = self.probe(|_| { let trait_ref = ty::TraitRef::new( self.tcx, - call_kind.to_def_id(self.tcx), + self.tcx.fn_trait_kind_to_def_id(call_kind)?, [ callee_ty, self.next_ty_var(TypeVariableOrigin { @@ -2031,7 +2006,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.param_env, trait_ref, ); - match SelectionContext::new(&self).select(&obligation) { + match SelectionContext::new(self).select(&obligation) { Ok(Some(traits::ImplSource::UserDefined(impl_source))) => { Some(impl_source.impl_def_id) } @@ -2082,7 +2057,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let node = self .tcx .opt_local_def_id_to_hir_id(self.tcx.hir().get_parent_item(call_expr.hir_id)) - .and_then(|hir_id| self.tcx.hir().find(hir_id)); + .and_then(|hir_id| self.tcx.opt_hir_node(hir_id)); match node { Some(hir::Node::Item(item)) => call_finder.visit_item(item), Some(hir::Node::TraitItem(item)) => call_finder.visit_trait_item(item), diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index e93d180fc..072df1343 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -143,7 +143,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub fn sess(&self) -> &Session { - &self.tcx.sess + self.tcx.sess } /// Creates an `TypeErrCtxt` with a reference to the in-progress @@ -196,7 +196,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> { type Target = Inherited<'tcx>; fn deref(&self) -> &Self::Target { - &self.inh + self.inh } } @@ -238,7 +238,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option<ty::Region<'tcx>> { let v = match def { - Some(def) => infer::EarlyBoundRegion(span, def.name), + Some(def) => infer::RegionParameterDefinition(span, def.name), None => infer::MiscVariable(span), }; Some(self.next_region_var(v)) @@ -289,7 +289,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { ) -> Ty<'tcx> { let trait_ref = self.instantiate_binder_with_fresh_vars( span, - infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id), + infer::BoundRegionConversionTime::AssocTypeProjection(item_def_id), poly_trait_ref, ); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index c43d4932f..668e54757 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -43,7 +43,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.typeck_results .borrow() .liberated_fn_sigs() - .get(self.tcx.hir().local_def_id_to_hir_id(self.body_id)) + .get(self.tcx.local_def_id_to_hir_id(self.body_id)) .copied() } @@ -72,23 +72,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { blk_id: hir::HirId, ) -> bool { let expr = expr.peel_drop_temps(); - self.suggest_missing_semicolon(err, expr, expected, false); let mut pointing_at_return_type = false; if let hir::ExprKind::Break(..) = expr.kind { // `break` type mismatches provide better context for tail `loop` expressions. return false; } if let Some((fn_id, fn_decl, can_suggest)) = self.get_fn_decl(blk_id) { - pointing_at_return_type = self.suggest_missing_return_type( - err, - &fn_decl, - expected, - found, - can_suggest, - fn_id, - ); + pointing_at_return_type = + self.suggest_missing_return_type(err, fn_decl, expected, found, can_suggest, fn_id); self.suggest_missing_break_or_return_expr( - err, expr, &fn_decl, expected, found, blk_id, fn_id, + err, expr, fn_decl, expected, found, blk_id, fn_id, ); } pointing_at_return_type @@ -449,12 +442,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected, ) }); + + let prefix_wrap = |sugg: &str| { + if let Some(name) = self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) { + format!(": {}{}", name, sugg) + } else { + sugg.to_string() + } + }; + // FIXME: This could/should be extended to suggest `as_mut` and `as_deref_mut`, // but those checks need to be a bit more delicate and the benefit is diminishing. if self.can_eq(self.param_env, found_ty_inner, peeled) && error_tys_equate_as_ref { + let sugg = prefix_wrap(".as_ref()"); err.subdiagnostic(errors::SuggestConvertViaMethod { span: expr.span.shrink_to_hi(), - sugg: ".as_ref()", + sugg, expected, found, borrow_removal_span, @@ -465,9 +468,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && self.can_eq(self.param_env, deref_ty, peeled) && error_tys_equate_as_ref { + let sugg = prefix_wrap(".as_deref()"); err.subdiagnostic(errors::SuggestConvertViaMethod { span: expr.span.shrink_to_hi(), - sugg: ".as_deref()", + sugg, expected, found, borrow_removal_span, @@ -481,10 +485,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.can_eq(self.param_env, found, expected) }) { + let sugg = prefix_wrap(".map(|x| x.as_str())"); err.span_suggestion_verbose( expr.span.shrink_to_hi(), fluent::hir_typeck_convert_to_str, - ".map(|x| x.as_str())", + sugg, Applicability::MachineApplicable, ); return true; @@ -615,7 +620,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return false; } let pin_did = self.tcx.lang_items().pin_type(); - // This guards the `unwrap` and `mk_box` below. + // This guards the `new_box` below. if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() { return false; } @@ -635,12 +640,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.help("use `Box::pin`"); } _ => { + let prefix = if let Some(name) = + self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) + { + format!("{}: ", name) + } else { + String::new() + }; + let suggestion = vec![ + (expr.span.shrink_to_lo(), format!("{prefix}Box::pin(")), + (expr.span.shrink_to_hi(), ")".to_string()), + ]; err.multipart_suggestion( "you need to pin and box this expression", - vec![ - (expr.span.shrink_to_lo(), "Box::pin(".to_string()), - (expr.span.shrink_to_hi(), ")".to_string()), - ], + suggestion, Applicability::MaybeIncorrect, ); } @@ -664,7 +677,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // can suggest Box::pin. let parent = self.tcx.hir().parent_id(expr.hir_id); let Some(Node::Expr(Expr { kind: ExprKind::Call(fn_name, _), .. })) = - self.tcx.hir().find(parent) + self.tcx.opt_hir_node(parent) else { return false; }; @@ -811,10 +824,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let hir::TyKind::OpaqueDef(item_id, ..) = hir_ty.kind && let hir::Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(op_ty), .. - }) = self.tcx.hir().get(item_id.hir_id()) - && let [ - hir::GenericBound::LangItemTrait(hir::LangItem::Future, _, _, generic_args), - ] = op_ty.bounds + }) = self.tcx.hir_node(item_id.hir_id()) + && let [hir::GenericBound::Trait(trait_ref, _)] = op_ty.bounds + && let Some(hir::PathSegment { args: Some(generic_args), .. }) = + trait_ref.trait_ref.path.segments.last() && let hir::GenericArgs { bindings: [ty_binding], .. } = generic_args && let hir::TypeBindingKind::Equality { term: hir::Term::Ty(term) } = ty_binding.kind @@ -846,7 +859,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let bound_vars = self.tcx.late_bound_vars(hir_ty.hir_id.owner.into()); let ty = Binder::bind_with_vars(ty, bound_vars); let ty = self.normalize(hir_ty.span, ty); - let ty = self.tcx.erase_late_bound_regions(ty); + let ty = self.tcx.instantiate_bound_regions_with_erased(ty); if self.can_coerce(expected, ty) { err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other { span: hir_ty.span, @@ -889,7 +902,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty::Param(expected_ty_as_param) = expected.kind() else { return }; - let fn_node = self.tcx.hir().find(fn_id); + let fn_node = self.tcx.opt_hir_node(fn_id); let Some(hir::Node::Item(hir::Item { kind: @@ -1023,7 +1036,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let hir::FnRetTy::Return(ty) = fn_decl.output { let ty = self.astconv().ast_ty_to_ty(ty); let bound_vars = self.tcx.late_bound_vars(fn_id); - let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars)); + let ty = self + .tcx + .instantiate_bound_regions_with_erased(Binder::bind_with_vars(ty, bound_vars)); let ty = match self.tcx.asyncness(fn_id.owner) { 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") @@ -1032,7 +1047,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let ty = self.normalize(expr.span, ty); if self.can_coerce(found, ty) { - if let Some(node) = self.tcx.hir().find(fn_id) + if let Some(node) = self.tcx.opt_hir_node(fn_id) && let Some(owner_node) = node.as_owner() && let Some(span) = expr.span.find_ancestor_inside(owner_node.span()) { @@ -1219,7 +1234,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span = parent_callsite; } - let sugg = if expr.precedence().order() >= PREC_POSTFIX { + let mut sugg = if expr.precedence().order() >= PREC_POSTFIX { vec![(span.shrink_to_hi(), ".into()".to_owned())] } else { vec![ @@ -1227,6 +1242,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (span.shrink_to_hi(), ").into()".to_owned()), ] }; + if let Some(name) = self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) { + sugg.insert(0, (expr.span.shrink_to_lo(), format!("{}: ", name))); + } diag.multipart_suggestion( format!("call `Into::into` on this expression to convert `{expr_ty}` into `{expected_ty}`"), sugg, @@ -1527,12 +1545,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } fn is_loop(&self, id: hir::HirId) -> bool { - let node = self.tcx.hir().get(id); + let node = self.tcx.hir_node(id); matches!(node, Node::Expr(Expr { kind: ExprKind::Loop(..), .. })) } fn is_local_statement(&self, id: hir::HirId) -> bool { - let node = self.tcx.hir().get(id); + let node = self.tcx.hir_node(id); matches!(node, Node::Stmt(Stmt { kind: StmtKind::Local(..), .. })) } @@ -1601,6 +1619,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None, ); } else { + if let Some(errors) = + self.could_impl_trait(clone_trait_did, expected_ty, self.param_env) + { + match &errors[..] { + [] => {} + [error] => { + diag.help(format!( + "`Clone` is not implemented because the trait bound `{}` is \ + not satisfied", + error.obligation.predicate, + )); + } + [errors @ .., last] => { + diag.help(format!( + "`Clone` is not implemented because the following trait bounds \ + could not be satisfied: {} and `{}`", + errors + .iter() + .map(|e| format!("`{}`", e.obligation.predicate)) + .collect::<Vec<_>>() + .join(", "), + last.obligation.predicate, + )); + } + } + for error in errors { + if let traits::FulfillmentErrorCode::CodeSelectionError( + traits::SelectionError::Unimplemented, + ) = error.code + && let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = + error.obligation.predicate.kind().skip_binder() + { + self.infcx.err_ctxt().suggest_derive( + &error.obligation, + diag, + error.obligation.predicate.kind().rebind(pred), + ); + } + } + } self.suggest_derive(diag, &[(trait_ref.to_predicate(self.tcx), None, None)]); } } @@ -1619,11 +1677,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None, hir::Path { segments: [_], res: crate::Res::Local(binding), .. }, )) => { - let Some(hir::Node::Pat(hir::Pat { hir_id, .. })) = self.tcx.hir().find(*binding) + let Some(hir::Node::Pat(hir::Pat { hir_id, .. })) = self.tcx.opt_hir_node(*binding) else { return expr; }; - let Some(parent) = self.tcx.hir().find(self.tcx.hir().parent_id(*hir_id)) else { + let Some(parent) = self.tcx.opt_hir_node(self.tcx.hir().parent_id(*hir_id)) else { return expr; }; @@ -1639,7 +1697,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .. }) => { let Some(hir::Node::Local(hir::Local { init: Some(init), .. })) = - self.tcx.hir().find(self.tcx.hir().parent_id(*pat_hir_id)) + self.tcx.opt_hir_node(self.tcx.hir().parent_id(*pat_hir_id)) else { return expr; }; @@ -1672,8 +1730,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let hir::Path { segments: [_], res: crate::Res::Local(binding), .. } = call_expr_path && let Some(hir::Node::Pat(hir::Pat { hir_id, .. })) = - self.tcx.hir().find(*binding) - && let Some(closure) = self.tcx.hir().find(self.tcx.hir().parent_id(*hir_id)) + self.tcx.opt_hir_node(*binding) + && let Some(closure) = self.tcx.opt_hir_node(self.tcx.hir().parent_id(*hir_id)) && let hir::Node::Local(hir::Local { init: Some(init), .. }) = closure && let Expr { kind: hir::ExprKind::Closure(hir::Closure { body: body_id, .. }), @@ -1816,6 +1874,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ".expect(\"REASON\")", ) }; + + let sugg = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) { + Some(ident) => format!(": {ident}{sugg}"), + None => sugg.to_string(), + }; + err.span_suggestion_verbose( expr.span.shrink_to_hi(), msg, @@ -1921,7 +1985,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(hir::Node::Block(&hir::Block { span: block_span, expr: Some(e), .. - })) = self.tcx.hir().find(parent) + })) = self.tcx.opt_hir_node(parent) { if e.hir_id == id { if let Some(span) = expr.span.find_ancestor_inside(block_span) { @@ -2008,8 +2072,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(CtorKind::Fn) => ("(".to_owned(), ")"), None => (format!(" {{ {field_name}: "), " }"), - // unit variants don't have fields - Some(CtorKind::Const) => unreachable!(), + Some(CtorKind::Const) => unreachable!("unit variants don't have fields"), }; // Suggest constructor as deep into the block tree as possible. @@ -2137,7 +2200,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// opt.map(|param| { takes_ref(param) }); /// ``` fn can_use_as_ref(&self, expr: &hir::Expr<'_>) -> Option<(Vec<(Span, String)>, &'static str)> { - let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = expr.kind else { + let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = expr.kind else { return None; }; @@ -2147,7 +2210,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let local_parent = self.tcx.hir().parent_id(local_id); let Some(Node::Param(hir::Param { hir_id: param_hir_id, .. })) = - self.tcx.hir().find(local_parent) + self.tcx.opt_hir_node(local_parent) else { return None; }; @@ -2157,13 +2220,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir_id: expr_hir_id, kind: hir::ExprKind::Closure(hir::Closure { fn_decl: closure_fn_decl, .. }), .. - })) = self.tcx.hir().find(param_parent) + })) = self.tcx.opt_hir_node(param_parent) else { return None; }; let expr_parent = self.tcx.hir().parent_id(*expr_hir_id); - let hir = self.tcx.hir().find(expr_parent); + let hir = self.tcx.opt_hir_node(expr_parent); let closure_params_len = closure_fn_decl.inputs.len(); let ( Some(Node::Expr(hir::Expr { @@ -2293,16 +2356,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if self.can_coerce(ref_ty, expected) { let mut sugg_sp = sp; - if let hir::ExprKind::MethodCall(ref segment, receiver, args, _) = expr.kind { + if let hir::ExprKind::MethodCall(segment, receiver, args, _) = expr.kind { let clone_trait = self.tcx.require_lang_item(LangItem::Clone, Some(segment.ident.span)); if args.is_empty() - && self.typeck_results.borrow().type_dependent_def_id(expr.hir_id).map( - |did| { + && self + .typeck_results + .borrow() + .type_dependent_def_id(expr.hir_id) + .is_some_and(|did| { let ai = self.tcx.associated_item(did); ai.trait_container(self.tcx) == Some(clone_trait) - }, - ) == Some(true) + }) && segment.ident.name == sym::clone { // If this expression had a clone call when suggesting borrowing @@ -2311,7 +2376,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner) = expr.kind + if let hir::ExprKind::Unary(hir::UnOp::Deref, inner) = expr.kind && let Some(1) = self.deref_steps(expected, checked_ty) { // We have `*&T`, check if what was expected was `&T`. @@ -2326,14 +2391,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); } - let needs_parens = match expr.kind { - // parenthesize if needed (Issue #46756) - hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true, - // parenthesize borrows of range literals (Issue #54505) - _ if is_range_literal(expr) => true, - _ => false, - }; - if let Some((sugg, msg)) = self.can_use_as_ref(expr) { return Some(( sugg, @@ -2361,18 +2418,48 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - let sugg = mutability.ref_prefix_str(); - let (sugg, verbose) = if needs_parens { - ( - vec![ - (sp.shrink_to_lo(), format!("{prefix}{sugg}(")), - (sp.shrink_to_hi(), ")".to_string()), - ], - false, - ) - } else { - (vec![(sp.shrink_to_lo(), format!("{prefix}{sugg}"))], true) + let make_sugg = |expr: &Expr<'_>, span: Span, sugg: &str| { + let needs_parens = match expr.kind { + // parenthesize if needed (Issue #46756) + hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true, + // parenthesize borrows of range literals (Issue #54505) + _ if is_range_literal(expr) => true, + _ => false, + }; + + if needs_parens { + ( + vec![ + (span.shrink_to_lo(), format!("{prefix}{sugg}(")), + (span.shrink_to_hi(), ")".to_string()), + ], + false, + ) + } else { + (vec![(span.shrink_to_lo(), format!("{prefix}{sugg}"))], true) + } }; + + // Suggest dereferencing the lhs for expressions such as `&T == T` + if let Some(hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Binary(_, lhs, ..), + .. + })) = self.tcx.hir().find_parent(expr.hir_id) + && let &ty::Ref(..) = self.check_expr(lhs).kind() + { + let (sugg, verbose) = make_sugg(lhs, lhs.span, "*"); + + return Some(( + sugg, + "consider dereferencing the borrow".to_string(), + Applicability::MachineApplicable, + verbose, + false, + )); + } + + let sugg = mutability.ref_prefix_str(); + let (sugg, verbose) = make_sugg(expr, sp, sugg); return Some(( sugg, format!("consider {}borrowing here", mutability.mutably_str()), @@ -2382,11 +2469,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); } } - ( - hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, ref expr), - _, - &ty::Ref(_, checked, _), - ) if self.can_sub(self.param_env, checked, expected) => { + (hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr), _, &ty::Ref(_, checked, _)) + if self.can_sub(self.param_env, checked, expected) => + { let make_sugg = |start: Span, end: BytePos| { // skip `(` for tuples such as `(c) = (&123)`. // make sure we won't suggest like `(c) = 123)` which is incorrect. @@ -2581,7 +2666,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(Node::Expr(hir::Expr { kind: hir::ExprKind::If(_, _, Some(else_expr)), .. - })) = self.tcx.hir().find(parent_id) + })) = self.tcx.opt_hir_node(parent_id) { return else_expr.hir_id == expr.hir_id; } @@ -2971,7 +3056,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; }; let parent = self.tcx.hir().parent_id(expr.hir_id); - if let Some(hir::Node::ExprField(_)) = self.tcx.hir().find(parent) { + if let Some(hir::Node::ExprField(_)) = self.tcx.opt_hir_node(parent) { // Ignore `Foo { field: a..Default::default() }` return; } @@ -3050,7 +3135,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let hir::def::Res::Local(hir_id) = path.res else { return; }; - let Some(hir::Node::Pat(pat)) = self.tcx.hir().find(hir_id) else { + let Some(hir::Node::Pat(pat)) = self.tcx.opt_hir_node(hir_id) else { return; }; let Some(hir::Node::Local(hir::Local { ty: None, init: Some(init), .. })) = |