diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-19 09:26:03 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-19 09:26:03 +0000 |
commit | 9918693037dce8aa4bb6f08741b6812923486c18 (patch) | |
tree | 21d2b40bec7e6a7ea664acee056eb3d08e15a1cf /compiler/rustc_hir_typeck | |
parent | Releasing progress-linux version 1.75.0+dfsg1-5~progress7.99u1. (diff) | |
download | rustc-9918693037dce8aa4bb6f08741b6812923486c18.tar.xz rustc-9918693037dce8aa4bb6f08741b6812923486c18.zip |
Merging upstream version 1.76.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_hir_typeck')
36 files changed, 1390 insertions, 981 deletions
diff --git a/compiler/rustc_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml index 0062889d2..b0c603044 100644 --- a/compiler/rustc_hir_typeck/Cargo.toml +++ b/compiler/rustc_hir_typeck/Cargo.toml @@ -19,7 +19,6 @@ rustc_infer = { path = "../rustc_infer" } rustc_lint = { path = "../rustc_lint" } rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } -rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 84e986488..181de3728 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -42,7 +42,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // #55810: Type check patterns first so we get types for all bindings. let scrut_span = scrut.span.find_ancestor_inside(expr.span).unwrap_or(scrut.span); for arm in arms { - self.check_pat_top(&arm.pat, scrutinee_ty, Some(scrut_span), Some(scrut), None); + self.check_pat_top(arm.pat, scrutinee_ty, Some(scrut_span), Some(scrut), None); } // Now typecheck the blocks. @@ -92,7 +92,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.diverges.set(Diverges::Maybe); - let arm_ty = self.check_expr_with_expectation(&arm.body, expected); + let arm_ty = self.check_expr_with_expectation(arm.body, expected); all_arms_diverge &= self.diverges.get(); let opt_suggest_box_span = prior_arm.and_then(|(_, prior_arm_ty, _)| { @@ -137,9 +137,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { coercion.coerce_inner( self, &cause, - Some(&arm.body), + Some(arm.body), arm_ty, - |err| self.suggest_removing_semicolon_for_coerce(err, expr, arm_ty, prior_arm), + |err| { + self.explain_never_type_coerced_to_unit(err, arm, arm_ty, prior_arm, expr); + }, false, ); @@ -177,6 +179,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { coercion.complete(self) } + fn explain_never_type_coerced_to_unit( + &self, + err: &mut Diagnostic, + arm: &hir::Arm<'tcx>, + arm_ty: Ty<'tcx>, + prior_arm: Option<(Option<hir::HirId>, Ty<'tcx>, Span)>, + expr: &hir::Expr<'tcx>, + ) { + if let hir::ExprKind::Block(block, _) = arm.body.kind + && let Some(expr) = block.expr + && let arm_tail_ty = self.node_ty(expr.hir_id) + && arm_tail_ty.is_never() + && !arm_ty.is_never() + { + err.span_label( + expr.span, + format!( + "this expression is of type `!`, but it is coerced to `{arm_ty}` due to its \ + surrounding expression", + ), + ); + self.suggest_mismatched_types_on_tail( + err, + expr, + arm_ty, + prior_arm.map_or(arm_tail_ty, |(_, ty, _)| ty), + expr.hir_id, + ); + } + self.suggest_removing_semicolon_for_coerce(err, expr, arm_ty, prior_arm) + } + fn suggest_removing_semicolon_for_coerce( &self, diag: &mut Diagnostic, @@ -204,8 +238,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // Next, make sure that we have no type expectation. - let Some(ret) = hir - .find_by_def_id(self.body_id) + let Some(ret) = self + .tcx + .opt_hir_node_by_def_id(self.body_id) .and_then(|owner| owner.fn_decl()) .map(|decl| decl.output.span()) else { @@ -283,7 +318,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir_id: hir::HirId, sp: Span, ) -> Option<(Span, String)> { - let node = self.tcx.hir().get(hir_id); + let node = self.tcx.hir_node(hir_id); if let hir::Node::Block(block) = node { // check that the body's parent is an fn let parent = self.tcx.hir().get_parent(self.tcx.hir().parent_id(block.hir_id)); diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 6b6d1574b..5e6b54950 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -6,9 +6,8 @@ use crate::errors; use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, StashKey}; use rustc_hir as hir; -use rustc_hir::def::{self, CtorKind, DefKind, Namespace, Res}; +use rustc_hir::def::{self, CtorKind, Namespace, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::HirId; use rustc_hir_analysis::autoderef::Autoderef; use rustc_infer::{ infer, @@ -245,7 +244,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { // Check for `self` receiver on the method, otherwise we can't use this as a `Fn*` trait. if !self.tcx.associated_item(ok.value.def_id).fn_has_self_parameter { - self.tcx.sess.delay_span_bug( + self.tcx.sess.span_delayed_bug( call_expr.span, "input to overloaded call fn is not a self receiver", ); @@ -260,9 +259,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty::Ref(region, _, mutbl) = method.sig.inputs()[0].kind() else { // The `fn`/`fn_mut` lang item is ill-formed, which should have // caused an error elsewhere. - self.tcx - .sess - .delay_span_bug(call_expr.span, "input to call/call_mut is not a ref"); + self.tcx.sess.span_delayed_bug( + call_expr.span, + "input to call/call_mut is not a ref", + ); return None; }; @@ -295,7 +295,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { let hir = self.tcx.hir(); let parent_hir_id = hir.parent_id(hir_id); - let parent_node = hir.get(parent_hir_id); + let parent_node = self.tcx.hir_node(parent_hir_id); if let ( hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, body, .. }), @@ -313,7 +313,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }), .. - }) = hir.get(async_closure) + }) = self.tcx.hir_node(async_closure) { fn_decl_span } else { @@ -343,7 +343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { callee_expr: &'tcx hir::Expr<'tcx>, ) -> bool { let hir_id = self.tcx.hir().parent_id(call_expr.hir_id); - let parent_node = self.tcx.hir().get(hir_id); + let parent_node = self.tcx.hir_node(hir_id); if let ( hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Array(_), .. }), hir::ExprKind::Tup(exp), @@ -373,7 +373,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Ty<'tcx> { let (fn_sig, def_id) = match *callee_ty.kind() { ty::FnDef(def_id, args) => { - self.enforce_context_effects(call_expr.hir_id, call_expr.span, def_id, args); + self.enforce_context_effects(call_expr.span, def_id, args); let fn_sig = self.tcx.fn_sig(def_id).instantiate(self.tcx, args); // Unit testing: function items annotated with @@ -417,7 +417,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let Some(mut diag) = self .tcx .sess - .diagnostic() + .dcx() .steal_diagnostic(segment.ident.span, StashKey::CallIntoMethod) { // Try suggesting `foo(a)` -> `a.foo()` if possible. @@ -471,6 +471,65 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + if let Some(def_id) = def_id + && 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 + { + let fn_sig = self.resolve_vars_if_possible(fn_sig); + for idx in 0..=1 { + let arg_ty = fn_sig.inputs()[idx + 1]; + let span = arg_exprs.get(idx + 1).map_or(call_expr.span, |arg| arg.span); + // 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 let ty::FnDef(def_id, _args) = *arg_ty.kind() { + let fn_once_def_id = + self.tcx.require_lang_item(hir::LangItem::FnOnce, Some(span)); + let fn_once_output_def_id = + self.tcx.require_lang_item(hir::LangItem::FnOnceOutput, Some(span)); + if self.tcx.generics_of(fn_once_def_id).host_effect_index.is_none() { + if idx == 0 && !self.tcx.is_const_fn_raw(def_id) { + self.tcx.sess.emit_err(errors::ConstSelectMustBeConst { span }); + } + } else { + let const_param: ty::GenericArg<'tcx> = + ([self.tcx.consts.false_, self.tcx.consts.true_])[idx].into(); + self.register_predicate(traits::Obligation::new( + self.tcx, + self.misc(span), + self.param_env, + ty::TraitRef::new( + self.tcx, + fn_once_def_id, + [arg_ty.into(), fn_sig.inputs()[0].into(), const_param], + ), + )); + + self.register_predicate(traits::Obligation::new( + self.tcx, + self.misc(span), + self.param_env, + ty::ProjectionPredicate { + projection_ty: ty::AliasTy::new( + self.tcx, + fn_once_output_def_id, + [arg_ty.into(), fn_sig.inputs()[0].into(), const_param], + ), + term: fn_sig.output().into(), + }, + )); + + self.select_obligations_where_possible(|_| {}); + } + } else { + self.tcx.sess.emit_err(errors::ConstSelectMustBeFn { span, ty: arg_ty }); + } + } + } + fn_sig.output() } @@ -625,12 +684,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } + if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = callee_expr.kind + && let Res::Local(_) = path.res + && let [segment] = &path.segments[..] + { + for id in self.tcx.hir().items() { + if let Some(node) = self.tcx.hir().get_if_local(id.owner_id.into()) + && let hir::Node::Item(item) = node + && let hir::ItemKind::Fn(..) = item.kind + && item.ident.name == segment.ident.name + { + err.span_label( + self.tcx.def_span(id.owner_id), + "this function of the same name is available here, but it's shadowed by \ + the local binding", + ); + } + } + } + let mut inner_callee_path = None; let def = match callee_expr.kind { hir::ExprKind::Path(ref qpath) => { self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id) } - hir::ExprKind::Call(ref inner_callee, _) => { + hir::ExprKind::Call(inner_callee, _) => { if let hir::ExprKind::Path(ref inner_qpath) = inner_callee.kind { inner_callee_path = Some(inner_qpath); self.typeck_results.borrow().qpath_res(inner_qpath, inner_callee.hir_id) @@ -751,7 +829,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[tracing::instrument(level = "debug", skip(self, span))] pub(super) fn enforce_context_effects( &self, - call_expr_hir: HirId, span: Span, callee_did: DefId, callee_args: GenericArgsRef<'tcx>, @@ -762,38 +839,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let generics = tcx.generics_of(callee_did); let Some(host_effect_index) = generics.host_effect_index else { return }; - // if the callee does have the param, we need to equate the param to some const - // value no matter whether the effects feature is enabled in the local crate, - // because inference will fail if we don't. - let mut host_always_on = - !tcx.features().effects || tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you; - - // Compute the constness required by the context. - let context = tcx.hir().enclosing_body_owner(call_expr_hir); - let const_context = tcx.hir().body_const_context(context); - - let kind = tcx.def_kind(context.to_def_id()); - debug_assert_ne!(kind, DefKind::ConstParam); - - if tcx.has_attr(context.to_def_id(), sym::rustc_do_not_const_check) { - trace!("do not const check this context"); - host_always_on = true; - } - - let effect = match const_context { - _ if host_always_on => tcx.consts.true_, - Some(hir::ConstContext::Static(_) | hir::ConstContext::Const { .. }) => { - tcx.consts.false_ - } - Some(hir::ConstContext::ConstFn) => { - let host_idx = tcx - .generics_of(context) - .host_effect_index - .expect("ConstContext::Maybe must have host effect param"); - ty::GenericArgs::identity_for_item(tcx, context).const_at(host_idx) - } - None => tcx.consts.true_, - }; + let effect = tcx.expected_host_effect_param_for_body(self.body_id); trace!(?effect, ?generics, ?callee_args); @@ -826,7 +872,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected, ); - self.write_method_call(call_expr.hir_id, method_callee); + self.write_method_call_and_enforce_effects(call_expr.hir_id, call_expr.span, method_callee); output_type } } @@ -876,7 +922,11 @@ impl<'a, 'tcx> DeferredCallResolution<'tcx> { adjustments.extend(autoref); fcx.apply_adjustments(self.callee_expr, adjustments); - fcx.write_method_call(self.call_expr.hir_id, method_callee); + fcx.write_method_call_and_enforce_effects( + self.call_expr.hir_id, + self.call_expr.span, + method_callee, + ); } None => { // This can happen if `#![no_core]` is used and the `fn/fn_mut/fn_once` diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index ee23f47c2..0de036536 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -101,7 +101,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(match *t.kind() { ty::Slice(_) | ty::Str => Some(PointerKind::Length), - ty::Dynamic(ref tty, _, ty::Dyn) => Some(PointerKind::VTable(tty.principal_def_id())), + ty::Dynamic(tty, _, ty::Dyn) => Some(PointerKind::VTable(tty.principal_def_id())), ty::Adt(def, args) if def.is_struct() => match def.non_enum_variant().tail_opt() { None => Some(PointerKind::Thin), Some(f) => { @@ -142,14 +142,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let reported = self .tcx .sess - .delay_span_bug(span, format!("`{t:?}` should be sized but is not?")); + .span_delayed_bug(span, format!("`{t:?}` should be sized but is not?")); return Err(reported); } }) } } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub enum CastError { ErrorGuaranteed(ErrorGuaranteed), @@ -271,7 +271,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { match e { CastError::NeedViaPtr => "a raw pointer", CastError::NeedViaThinPtr => "a thin pointer", - _ => bug!(), + e => unreachable!("control flow means we should never encounter a {e:?}"), } )); } @@ -288,13 +288,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { self.cast_ty, fcx, ) - .help(format!( - "cast through {} first", - match e { - CastError::NeedViaInt => "an integer", - _ => bug!(), - } - )) + .help("cast through an integer first") .emit(); } CastError::IllegalCast => { @@ -506,7 +500,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { }; SizedUnsizedCast { - sess: &fcx.tcx.sess, + sess: fcx.tcx.sess, span: self.span, expr_ty: self.expr_ty, cast_ty: fcx.ty_to_string(self.cast_ty), @@ -534,7 +528,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { let unknown_cast_to = match e { CastError::UnknownCastPtrKind => true, CastError::UnknownExprPtrKind => false, - _ => bug!(), + e => unreachable!("control flow means we should never encounter a {e:?}"), }; let (span, sub) = if unknown_cast_to { (self.cast_span, errors::CastUnknownPointerSub::To(self.cast_span)) diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index b8a265d49..2855cea80 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -8,7 +8,7 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; -use rustc_hir_analysis::check::{check_function_signature, fn_maybe_err}; +use rustc_hir_analysis::check::{check_function_signature, forbid_intrinsic_abi}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::RegionVariableOrigin; use rustc_middle::ty::{self, Binder, Ty, TyCtxt}; @@ -34,7 +34,7 @@ pub(super) fn check_fn<'a, 'tcx>( can_be_coroutine: Option<hir::Movability>, params_can_be_unsized: bool, ) -> Option<CoroutineTypes<'tcx>> { - let fn_id = fcx.tcx.hir().local_def_id_to_hir_id(fn_def_id); + let fn_id = fcx.tcx.local_def_id_to_hir_id(fn_def_id); let tcx = fcx.tcx; let hir = tcx.hir(); @@ -53,7 +53,7 @@ pub(super) fn check_fn<'a, 'tcx>( let span = body.value.span; - fn_maybe_err(tcx, span, fn_sig.abi); + forbid_intrinsic_abi(tcx, span, fn_sig.abi); if let Some(kind) = body.coroutine_kind && can_be_coroutine.is_some() @@ -67,6 +67,28 @@ pub(super) fn check_fn<'a, 'tcx>( fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType); yield_ty } + // HACK(-Ztrait-solver=next): In the *old* trait solver, we must eagerly + // guide inference on the yield type so that we can handle `AsyncIterator` + // in this block in projection correctly. In the new trait solver, it is + // not a problem. + hir::CoroutineKind::AsyncGen(..) => { + let yield_ty = fcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span, + }); + fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType); + + Ty::new_adt( + tcx, + tcx.adt_def(tcx.require_lang_item(hir::LangItem::Poll, Some(span))), + tcx.mk_args(&[Ty::new_adt( + tcx, + tcx.adt_def(tcx.require_lang_item(hir::LangItem::Option, Some(span))), + tcx.mk_args(&[yield_ty.into()]), + ) + .into()]), + ) + } hir::CoroutineKind::Async(..) => Ty::new_unit(tcx), }; @@ -76,7 +98,7 @@ pub(super) fn check_fn<'a, 'tcx>( fcx.resume_yield_tys = Some((resume_ty, yield_ty)); } - GatherLocalsVisitor::new(&fcx).visit_body(body); + GatherLocalsVisitor::new(fcx).visit_body(body); // C-variadic fns also have a `VaList` input that's not listed in `fn_sig` // (as it's created inside the body itself, not passed in from outside). @@ -94,7 +116,7 @@ pub(super) fn check_fn<'a, 'tcx>( for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() { // Check the pattern. let ty_span = try { inputs_hir?.get(idx)?.span }; - fcx.check_pat_top(¶m.pat, param_ty, ty_span, None, None); + fcx.check_pat_top(param.pat, param_ty, ty_span, None, None); // Check that argument is Sized. if !params_can_be_unsized { @@ -123,7 +145,7 @@ pub(super) fn check_fn<'a, 'tcx>( hir::FnRetTy::Return(ty) => ty.span, }; fcx.require_type_is_sized(declared_ret_ty, return_or_body_span, traits::SizedReturnType); - fcx.check_return_expr(&body.value, false); + fcx.check_return_expr(body.value, false); // We insert the deferred_coroutine_interiors entry after visiting the body. // This ensures that all nested coroutines appear before the entry of this coroutine. @@ -156,7 +178,7 @@ pub(super) fn check_fn<'a, 'tcx>( // really expected to fail, since the coercions would have failed // earlier when trying to find a LUB. let coercion = fcx.ret_coercion.take().unwrap().into_inner(); - let mut actual_return_ty = coercion.complete(&fcx); + let mut actual_return_ty = coercion.complete(fcx); debug!("actual_return_ty = {:?}", actual_return_ty); if let ty::Dynamic(..) = declared_ret_ty.kind() { // We have special-cased the case where the function is declared @@ -214,7 +236,7 @@ fn check_panic_info_fn(tcx: TyCtxt<'_>, fn_id: LocalDefId, fn_sig: ty::FnSig<'_> // build type `for<'a, 'b> fn(&'a PanicInfo<'b>) -> !` let panic_info_ty = tcx.type_of(panic_info_did).instantiate( tcx, - &[ty::GenericArg::from(ty::Region::new_late_bound( + &[ty::GenericArg::from(ty::Region::new_bound( tcx, ty::INNERMOST, ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BrAnon }, @@ -222,7 +244,7 @@ fn check_panic_info_fn(tcx: TyCtxt<'_>, fn_id: LocalDefId, fn_sig: ty::FnSig<'_> ); let panic_info_ref_ty = Ty::new_imm_ref( tcx, - ty::Region::new_late_bound( + ty::Region::new_bound( tcx, ty::INNERMOST, ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon }, @@ -239,7 +261,7 @@ fn check_panic_info_fn(tcx: TyCtxt<'_>, fn_id: LocalDefId, fn_sig: ty::FnSig<'_> bounds, ); - check_function_signature( + let _ = check_function_signature( tcx, ObligationCause::new( tcx.def_span(fn_id), @@ -278,7 +300,7 @@ fn check_lang_start_fn<'tcx>(tcx: TyCtxt<'tcx>, fn_sig: ty::FnSig<'tcx>, def_id: Abi::Rust, )); - check_function_signature( + let _ = check_function_signature( tcx, ObligationCause::new( tcx.def_span(def_id), diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index a70ead8e5..d19d30412 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -7,7 +7,7 @@ use rustc_hir as hir; use rustc_hir::lang_items::LangItem; use rustc_hir_analysis::astconv::AstConv; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::{DefineOpaqueTypes, LateBoundRegionConversionTime}; +use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes}; use rustc_infer::infer::{InferOk, InferResult}; use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; @@ -141,7 +141,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!(?sig, ?opt_kind); let closure_kind_ty = match opt_kind { - Some(kind) => kind.to_ty(self.tcx), + Some(kind) => Ty::from_closure_kind(self.tcx, kind), // Create a type variable (for now) to represent the closure kind. // It will be unified during the upvar inference phase (`upvar.rs`) @@ -181,7 +181,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter_instantiated_copied(self.tcx, args) .map(|(c, s)| (c.as_predicate(), s)), ), - ty::Dynamic(ref object_type, ..) => { + ty::Dynamic(object_type, ..) => { let sig = object_type.projection_bounds().find_map(|pb| { let pb = pb.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self); self.deduce_sig_from_projection(None, pb) @@ -483,8 +483,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { body: &hir::Body<'_>, expected_sig: ExpectedSig<'tcx>, ) -> ClosureSignatures<'tcx> { - let hir = self.tcx.hir(); - let expr_map_node = hir.get_by_def_id(expr_def_id); + let expr_map_node = self.tcx.hir_node_by_def_id(expr_def_id); let expected_args: Vec<_> = expected_sig .sig .skip_binder() @@ -558,7 +557,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Instantiate (this part of..) S to S', i.e., with fresh variables. self.instantiate_binder_with_fresh_vars( hir_ty.span, - LateBoundRegionConversionTime::FnCall, + BoundRegionConversionTime::FnCall, // (*) binder moved to here supplied_sig.inputs().rebind(supplied_ty), ) @@ -583,7 +582,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let supplied_output_ty = self.instantiate_binder_with_fresh_vars( decl.output.span(), - LateBoundRegionConversionTime::FnCall, + BoundRegionConversionTime::FnCall, supplied_sig.output(), ); let cause = &self.misc(decl.output.span()); @@ -624,13 +623,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { trace!("decl = {:#?}", decl); debug!(?body.coroutine_kind); - let hir_id = self.tcx.hir().local_def_id_to_hir_id(expr_def_id); + let hir_id = self.tcx.local_def_id_to_hir_id(expr_def_id); let bound_vars = self.tcx.late_bound_vars(hir_id); // First, convert the types that the user supplied (if any). let supplied_arguments = decl.inputs.iter().map(|a| astconv.ast_ty_to_ty(a)); let supplied_return = match decl.output { - hir::FnRetTy::Return(ref output) => astconv.ast_ty_to_ty(&output), + hir::FnRetTy::Return(ref output) => astconv.ast_ty_to_ty(output), hir::FnRetTy::DefaultReturn(_) => match body.coroutine_kind { // In the case of the async block that we create for a function body, // we expect the return type of the block to match that of the enclosing @@ -651,8 +650,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, ) } - Some(hir::CoroutineKind::Gen(hir::CoroutineSource::Fn)) => { - todo!("gen closures do not exist yet") + // All `gen {}` and `async gen {}` must return unit. + Some(hir::CoroutineKind::Gen(_) | hir::CoroutineKind::AsyncGen(_)) => { + self.tcx.types.unit } _ => astconv.ty_infer(None, decl.output.span()), @@ -819,7 +819,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); if let hir::FnRetTy::Return(ref output) = decl.output { - astconv.ast_ty_to_ty(&output); + astconv.ast_ty_to_ty(output); } let result = ty::Binder::dummy(self.tcx.mk_fn_sig( diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 6c03bc3b5..f08af9edc 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -36,7 +36,9 @@ //! ``` use crate::FnCtxt; -use rustc_errors::{struct_span_err, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan}; +use rustc_errors::{ + struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, +}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, Visitor}; @@ -53,11 +55,10 @@ use rustc_middle::ty::adjustment::{ use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::RelateResult; use rustc_middle::ty::visit::TypeVisitableExt; -use rustc_middle::ty::GenericArgsRef; -use rustc_middle::ty::{self, Ty, TypeAndMut}; +use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeAndMut}; use rustc_session::parse::feature_err; use rustc_span::symbol::sym; -use rustc_span::{self, DesugaringKind}; +use rustc_span::DesugaringKind; use rustc_target::spec::abi::Abi; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; @@ -85,7 +86,7 @@ struct Coerce<'a, 'tcx> { impl<'a, 'tcx> Deref for Coerce<'a, 'tcx> { type Target = FnCtxt<'a, 'tcx>; fn deref(&self) -> &Self::Target { - &self.fcx + self.fcx } } @@ -158,7 +159,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { if self.next_trait_solver() { if let Ok(res) = &res { for obligation in &res.obligations { - if !self.predicate_may_hold(&obligation) { + if !self.predicate_may_hold(obligation) { return Err(TypeError::Mismatch); } } @@ -1041,7 +1042,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Returns false if the coercion creates any obligations that result in /// errors. pub fn can_coerce(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> bool { - // FIXME(-Ztrait-solver=next): We need to structurally resolve both types here. + // FIXME(-Znext-solver): We need to structurally resolve both types here. let source = self.resolve_vars_with_obligations(expr_ty); debug!("coercion::can_with_predicates({:?} -> {:?})", source, target); @@ -1204,14 +1205,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Adjust::Pointer(PointerCoercion::ClosureFnPointer(a_sig.unsafety())) } ty::FnDef(..) => Adjust::Pointer(PointerCoercion::ReifyFnPointer), - _ => unreachable!(), + _ => span_bug!(cause.span, "should not try to coerce a {prev_ty} to a fn pointer"), }; let next_adjustment = match new_ty.kind() { ty::Closure(..) => { Adjust::Pointer(PointerCoercion::ClosureFnPointer(b_sig.unsafety())) } ty::FnDef(..) => Adjust::Pointer(PointerCoercion::ReifyFnPointer), - _ => unreachable!(), + _ => span_bug!(new.span, "should not try to coerce a {new_ty} to a fn pointer"), }; for expr in exprs.iter().map(|e| e.as_coercion_site()) { self.apply_adjustments( @@ -1510,7 +1511,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { expression, expression_ty, ), - Expressions::UpFront(ref coercion_sites) => fcx.try_find_coercion_lub( + Expressions::UpFront(coercion_sites) => fcx.try_find_coercion_lub( cause, &coercion_sites[0..self.pushed], self.merged_ty(), @@ -1572,7 +1573,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { // any superfluous errors we might encounter while trying to // emit or provide suggestions on how to fix the initial error. fcx.set_tainted_by_errors( - fcx.tcx.sess.delay_span_bug(cause.span, "coercion error but no error emitted"), + fcx.tcx + .sess + .span_delayed_bug(cause.span, "coercion error but no error emitted"), ); let (expected, found) = if label_expression_as_expected { // In the case where this is a "forced unit", like @@ -1660,12 +1663,15 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { None, Some(coercion_error), ); - } - - if visitor.ret_exprs.len() > 0 - && let Some(expr) = expression - { - self.note_unreachable_loop_return(&mut err, &expr, &visitor.ret_exprs); + if visitor.ret_exprs.len() > 0 { + self.note_unreachable_loop_return( + &mut err, + fcx.tcx, + &expr, + &visitor.ret_exprs, + expected, + ); + } } let reported = err.emit_unless(unsized_return); @@ -1678,8 +1684,10 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { fn note_unreachable_loop_return( &self, err: &mut Diagnostic, + tcx: TyCtxt<'tcx>, expr: &hir::Expr<'tcx>, ret_exprs: &Vec<&'tcx hir::Expr<'tcx>>, + ty: Ty<'tcx>, ) { let hir::ExprKind::Loop(_, _, _, loop_span) = expr.kind else { return; @@ -1704,10 +1712,77 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { ret_exprs.len() - MAXITER )); } - err.help( - "return a value for the case when the loop has zero elements to iterate on, or \ - consider changing the return type to account for that possibility", - ); + let hir = tcx.hir(); + let item = hir.get_parent_item(expr.hir_id); + let ret_msg = "return a value for the case when the loop has zero elements to iterate on"; + let ret_ty_msg = + "otherwise consider changing the return type to account for that possibility"; + if let Some(node) = tcx.opt_hir_node(item.into()) + && let Some(body_id) = node.body_id() + && let Some(sig) = node.fn_sig() + && let hir::ExprKind::Block(block, _) = hir.body(body_id).value.kind + && !ty.is_never() + { + let indentation = if let None = block.expr + && let [.., last] = &block.stmts + { + tcx.sess.source_map().indentation_before(last.span).unwrap_or_else(String::new) + } else if let Some(expr) = block.expr { + tcx.sess.source_map().indentation_before(expr.span).unwrap_or_else(String::new) + } else { + String::new() + }; + if let None = block.expr + && let [.., last] = &block.stmts + { + err.span_suggestion_verbose( + last.span.shrink_to_hi(), + ret_msg, + format!("\n{indentation}/* `{ty}` value */"), + Applicability::MaybeIncorrect, + ); + } else if let Some(expr) = block.expr { + err.span_suggestion_verbose( + expr.span.shrink_to_hi(), + ret_msg, + format!("\n{indentation}/* `{ty}` value */"), + Applicability::MaybeIncorrect, + ); + } + let mut sugg = match sig.decl.output { + hir::FnRetTy::DefaultReturn(span) => { + vec![(span, " -> Option<()>".to_string())] + } + hir::FnRetTy::Return(ty) => { + vec![ + (ty.span.shrink_to_lo(), "Option<".to_string()), + (ty.span.shrink_to_hi(), ">".to_string()), + ] + } + }; + for ret_expr in ret_exprs { + match ret_expr.kind { + hir::ExprKind::Ret(Some(expr)) => { + sugg.push((expr.span.shrink_to_lo(), "Some(".to_string())); + sugg.push((expr.span.shrink_to_hi(), ")".to_string())); + } + hir::ExprKind::Ret(None) => { + sugg.push((ret_expr.span.shrink_to_hi(), " Some(())".to_string())); + } + _ => {} + } + } + if let None = block.expr + && let [.., last] = &block.stmts + { + sugg.push((last.span.shrink_to_hi(), format!("\n{indentation}None"))); + } else if let Some(expr) = block.expr { + sugg.push((expr.span.shrink_to_hi(), format!("\n{indentation}None"))); + } + err.multipart_suggestion(ret_ty_msg, sugg, Applicability::MaybeIncorrect); + } else { + err.help(format!("{ret_msg}, {ret_ty_msg}")); + } } fn report_return_mismatched_types<'a>( @@ -1724,7 +1799,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { let mut err = fcx.err_ctxt().report_mismatched_types(cause, expected, found, ty_err); let parent_id = fcx.tcx.hir().parent_id(id); - let parent = fcx.tcx.hir().get(parent_id); + let parent = fcx.tcx.hir_node(parent_id); if let Some(expr) = expression && let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { body, .. }), @@ -1738,6 +1813,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { // label pointing out the cause for the type coercion will be wrong // as prior return coercions would not be relevant (#57664). let fn_decl = if let (Some(expr), Some(blk_id)) = (expression, blk_id) { + fcx.suggest_missing_semicolon(&mut err, expr, expected, false); let pointing_at_return_type = fcx.suggest_mismatched_types_on_tail(&mut err, expr, expected, found, blk_id); if let (Some(cond_expr), true, false) = ( @@ -1772,7 +1848,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { if blk_id.is_none() { fcx.suggest_missing_return_type( &mut err, - &fn_decl, + fn_decl, expected, found, can_suggest, @@ -1782,7 +1858,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { } let parent_id = fcx.tcx.hir().get_parent_item(id); - let parent_item = fcx.tcx.hir().get_by_def_id(parent_id.def_id); + let parent_item = fcx.tcx.hir_node_by_def_id(parent_id.def_id); if let (Some(expr), Some(_), Some((fn_id, fn_decl, _, _))) = (expression, blk_id, fcx.get_node_fn_decl(parent_item)) @@ -1865,12 +1941,12 @@ where impl AsCoercionSite for ! { fn as_coercion_site(&self) -> &hir::Expr<'_> { - unreachable!() + *self } } impl AsCoercionSite for hir::Arm<'_> { fn as_coercion_site(&self) -> &hir::Expr<'_> { - &self.body + self.body } } diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index acaa3e02f..8b666c634 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -31,9 +31,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } self.annotate_alternative_method_deref(err, expr, error); + self.explain_self_literal(err, expr, expected, expr_ty); // Use `||` to give these suggestions a precedence let suggested = self.suggest_missing_parentheses(err, expr) + || self.suggest_missing_unwrap_expect(err, expr, expected, expr_ty) || self.suggest_remove_last_method_call(err, expr, expected) || self.suggest_associated_const(err, expr, expected) || self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr) @@ -49,8 +51,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { || self.suggest_into(err, expr, expr_ty, expected) || self.suggest_floating_point_literal(err, expr, expected) || self.suggest_null_ptr_for_literal_zero_given_to_ptr_arg(err, expr, expected) - || self.suggest_coercing_result_via_try_operator(err, expr, expected, expr_ty) - || self.suggest_missing_unwrap_expect(err, expr, expected, expr_ty); + || self.suggest_coercing_result_via_try_operator(err, expr, expected, expr_ty); if !suggested { self.note_source_of_type_mismatch_constraint( @@ -183,7 +184,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.register_predicates(obligations); None } - Err(e) => Some(self.err_ctxt().report_mismatched_types(&cause, expected, actual, e)), + Err(e) => Some(self.err_ctxt().report_mismatched_types(cause, expected, actual, e)), } } @@ -255,7 +256,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.adjust_expr_for_assert_eq_macro(&mut expr, &mut expected_ty_expr); - self.set_tainted_by_errors(self.tcx.sess.delay_span_bug( + self.set_tainted_by_errors(self.tcx.sess.span_delayed_bug( expr.span, "`TypeError` when attempting coercion but no error emitted", )); @@ -288,7 +289,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let hir::def::Res::Local(local_hir_id) = p.res else { return false; }; - let hir::Node::Pat(pat) = hir.get(local_hir_id) else { + let hir::Node::Pat(pat) = self.tcx.hir_node(local_hir_id) else { return false; }; let (init_ty_hir_id, init) = match hir.get_parent(pat.hir_id) { @@ -330,13 +331,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty_op: |ty| { if let ty::Infer(infer) = ty.kind() { match infer { - ty::InferTy::TyVar(_) => self.next_ty_var(TypeVariableOrigin { + ty::TyVar(_) => self.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span: DUMMY_SP, }), - ty::InferTy::IntVar(_) => self.next_int_var(), - ty::InferTy::FloatVar(_) => self.next_float_var(), - _ => bug!(), + ty::IntVar(_) => self.next_int_var(), + ty::FloatVar(_) => self.next_float_var(), + ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => { + bug!("unexpected fresh ty outside of the trait solver") + } } } else { ty @@ -556,7 +559,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Semi(&ref p), .. }) | hir::Node::Block(hir::Block { expr: Some(&ref p), .. }) | hir::Node::Expr(&ref p), - ) = self.tcx.hir().find(parent_id) + ) = self.tcx.opt_hir_node(parent_id) else { break; }; @@ -569,7 +572,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut direct = false; loop { // Climb the HIR tree to find the (desugared) `loop` this `break` corresponds to. - let parent = match self.tcx.hir().find(parent_id) { + let parent = match self.tcx.opt_hir_node(parent_id) { Some(hir::Node::Expr(&ref parent)) => { parent_id = self.tcx.hir().parent_id(parent.hir_id); parent @@ -671,7 +674,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { error: Option<TypeError<'tcx>>, ) { let parent = self.tcx.hir().parent_id(expr.hir_id); - match (self.tcx.hir().find(parent), error) { + match (self.tcx.opt_hir_node(parent), error) { (Some(hir::Node::Local(hir::Local { ty: Some(ty), init: Some(init), .. })), _) if init.hir_id == expr.hir_id => { @@ -716,7 +719,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None, hir::Path { res: hir::def::Res::Local(hir_id), .. }, )) => { - if let Some(hir::Node::Pat(pat)) = self.tcx.hir().find(*hir_id) { + if let Some(hir::Node::Pat(pat)) = self.tcx.opt_hir_node(*hir_id) { primary_span = pat.span; secondary_span = pat.span; match self.tcx.hir().find_parent(pat.hir_id) { @@ -789,7 +792,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; }; let Some(hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(lhs, rhs, _), .. })) = - self.tcx.hir().find(parent) + self.tcx.opt_hir_node(parent) else { return; }; @@ -861,7 +864,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { mutability, ), ), - match &args[..] { + match &args { [] => (base.span.shrink_to_hi().with_hi(deref.span.hi()), ")".to_string()), [first, ..] => (base.span.between(first.span), ", ".to_string()), }, @@ -882,7 +885,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let container_id = pick.item.container_id(self.tcx); let container = with_no_trimmed_paths!(self.tcx.def_path_str(container_id)); for def_id in pick.import_ids { - let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = self.tcx.local_def_id_to_hir_id(def_id); path_span.push_span_label( self.tcx.hir().span(hir_id), format!("`{container}` imported here"), @@ -1013,8 +1016,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::Path { res: hir::def::Res::Local(bind_hir_id), .. }, )) = expr.kind { - let bind = self.tcx.hir().find(*bind_hir_id); - let parent = self.tcx.hir().find(self.tcx.hir().parent_id(*bind_hir_id)); + let bind = self.tcx.opt_hir_node(*bind_hir_id); + let parent = self.tcx.opt_hir_node(self.tcx.hir().parent_id(*bind_hir_id)); if let Some(hir::Node::Pat(hir::Pat { kind: hir::PatKind::Binding(_, _hir_id, _, _), .. @@ -1027,6 +1030,59 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return false; } + fn explain_self_literal( + &self, + err: &mut Diagnostic, + expr: &hir::Expr<'tcx>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) { + match expr.peel_drop_temps().kind { + hir::ExprKind::Struct( + hir::QPath::Resolved( + None, + hir::Path { res: hir::def::Res::SelfTyAlias { alias_to, .. }, span, .. }, + ), + .., + ) + | hir::ExprKind::Call( + hir::Expr { + kind: + hir::ExprKind::Path(hir::QPath::Resolved( + None, + hir::Path { + res: hir::def::Res::SelfTyAlias { alias_to, .. }, + span, + .. + }, + )), + .. + }, + .., + ) => { + if let Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Impl(hir::Impl { self_ty, .. }), + .. + })) = self.tcx.hir().get_if_local(*alias_to) + { + err.span_label(self_ty.span, "this is the type of the `Self` literal"); + } + if let ty::Adt(e_def, e_args) = expected.kind() + && let ty::Adt(f_def, _f_args) = found.kind() + && e_def == f_def + { + err.span_suggestion_verbose( + *span, + "use the type name directly", + self.tcx.value_path_str_with_args(*alias_to, e_args), + Applicability::MaybeIncorrect, + ); + } + } + _ => {} + } + } + fn note_wrong_return_ty_due_to_generic_arg( &self, err: &mut Diagnostic, diff --git a/compiler/rustc_hir_typeck/src/diverges.rs b/compiler/rustc_hir_typeck/src/diverges.rs index 29fcc61cb..0b559a085 100644 --- a/compiler/rustc_hir_typeck/src/diverges.rs +++ b/compiler/rustc_hir_typeck/src/diverges.rs @@ -1,4 +1,4 @@ -use rustc_span::{self, Span, DUMMY_SP}; +use rustc_span::{Span, DUMMY_SP}; use std::{cmp, ops}; /// Tracks whether executing a node may exit normally (versus diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index aff1baa19..ff03cf16a 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -573,13 +573,13 @@ impl rustc_errors::AddToDiagnostic for CastUnknownPointerSub { { match self { CastUnknownPointerSub::To(span) => { - let msg = f(diag, crate::fluent_generated::hir_typeck_label_to.into()); + let msg = f(diag, crate::fluent_generated::hir_typeck_label_to); diag.span_label(span, msg); - let msg = f(diag, crate::fluent_generated::hir_typeck_note.into()); + let msg = f(diag, crate::fluent_generated::hir_typeck_note); diag.note(msg); } CastUnknownPointerSub::From(span) => { - let msg = f(diag, crate::fluent_generated::hir_typeck_label_from.into()); + let msg = f(diag, crate::fluent_generated::hir_typeck_label_from); diag.span_label(span, msg); } } @@ -626,7 +626,7 @@ pub struct SuggestConvertViaMethod<'tcx> { pub span: Span, #[suggestion_part(code = "")] pub borrow_removal_span: Option<Span>, - pub sugg: &'static str, + pub sugg: String, pub expected: Ty<'tcx>, pub found: Ty<'tcx>, } diff --git a/compiler/rustc_hir_typeck/src/expectation.rs b/compiler/rustc_hir_typeck/src/expectation.rs index 35e5fb769..ff84e753d 100644 --- a/compiler/rustc_hir_typeck/src/expectation.rs +++ b/compiler/rustc_hir_typeck/src/expectation.rs @@ -1,6 +1,6 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::ty::{self, Ty}; -use rustc_span::{self, Span}; +use rustc_span::Span; use super::Expectation::*; use super::FnCtxt; diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 9f439a2b3..7bd2c3f8b 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -21,7 +21,7 @@ use crate::{ TupleArgumentsFlag::DontTupleArguments, }; use rustc_ast as ast; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ pluralize, struct_span_err, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, @@ -75,7 +75,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // coercions from ! to `expected`. if ty.is_never() { if let Some(adjustments) = self.typeck_results.borrow().adjustments().get(expr.hir_id) { - let reported = self.tcx().sess.delay_span_bug( + let reported = self.tcx().sess.span_delayed_bug( expr.span, "expression with never type wound up being adjusted", ); @@ -277,7 +277,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx; match expr.kind { - ExprKind::Lit(ref lit) => self.check_lit(&lit, expected), + ExprKind::Lit(ref lit) => self.check_lit(lit, expected), ExprKind::Binary(op, lhs, rhs) => self.check_binop(expr, op, lhs, rhs, expected), ExprKind::Assign(lhs, rhs, span) => { self.check_expr_assign(expr, expected, lhs, rhs, span) @@ -289,8 +289,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::AddrOf(kind, mutbl, oprnd) => { self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr) } - ExprKind::Path(QPath::LangItem(lang_item, _, hir_id)) => { - self.check_lang_item_path(lang_item, expr, hir_id) + ExprKind::Path(QPath::LangItem(lang_item, _)) => { + self.check_lang_item_path(lang_item, expr) } ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, &[]), ExprKind::InlineAsm(asm) => { @@ -298,9 +298,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.deferred_asm_checks.borrow_mut().push((asm, expr.hir_id)); self.check_expr_asm(asm) } - ExprKind::OffsetOf(container, ref fields) => { - self.check_offset_of(container, fields, expr) - } + ExprKind::OffsetOf(container, fields) => self.check_offset_of(container, fields, expr), ExprKind::Break(destination, ref expr_opt) => { self.check_expr_break(destination, expr_opt.as_deref(), expr) } @@ -319,17 +317,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_expr_loop(body, source, expected, expr) } ExprKind::Match(discrim, arms, match_src) => { - self.check_match(expr, &discrim, arms, expected, match_src) + self.check_match(expr, discrim, arms, expected, match_src) } ExprKind::Closure(closure) => self.check_expr_closure(closure, expr.span, expected), - ExprKind::Block(body, _) => self.check_block_with_expected(&body, expected), - ExprKind::Call(callee, args) => self.check_call(expr, &callee, args, expected), + ExprKind::Block(body, _) => self.check_block_with_expected(body, expected), + ExprKind::Call(callee, args) => self.check_call(expr, callee, args, expected), ExprKind::MethodCall(segment, receiver, args, _) => { self.check_method_call(expr, segment, receiver, args, expected) } ExprKind::Cast(e, t) => self.check_expr_cast(e, t, expr), ExprKind::Type(e, t) => { - let ascribed_ty = self.to_ty_saving_user_provided_ty(&t); + let ascribed_ty = self.to_ty_saving_user_provided_ty(t); let ty = self.check_expr_with_hint(e, ascribed_ty); self.demand_eqtype(e.span, ascribed_ty, ty); ascribed_ty @@ -347,7 +345,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::Struct(qpath, fields, ref base_expr) => { self.check_expr_struct(expr, expected, qpath, fields, base_expr) } - ExprKind::Field(base, field) => self.check_field(expr, &base, field, expected), + ExprKind::Field(base, field) => self.check_field(expr, base, field, expected), ExprKind::Index(base, idx, brackets_span) => { self.check_expr_index(base, idx, expr, brackets_span) } @@ -368,7 +366,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::UnOp::Not | hir::UnOp::Neg => expected, hir::UnOp::Deref => NoExpectation, }; - let mut oprnd_t = self.check_expr_with_expectation(&oprnd, expected_inner); + let mut oprnd_t = self.check_expr_with_expectation(oprnd, expected_inner); if !oprnd_t.references_error() { oprnd_t = self.structurally_resolve_type(expr.span, oprnd_t); @@ -436,7 +434,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }); let ty = - self.check_expr_with_expectation_and_needs(&oprnd, hint, Needs::maybe_mut_place(mutbl)); + self.check_expr_with_expectation_and_needs(oprnd, hint, Needs::maybe_mut_place(mutbl)); let tm = ty::TypeAndMut { ty, mutbl }; match kind { @@ -499,9 +497,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, lang_item: hir::LangItem, expr: &'tcx hir::Expr<'tcx>, - hir_id: Option<hir::HirId>, ) -> Ty<'tcx> { - self.resolve_lang_item_path(lang_item, expr.span, expr.hir_id, hir_id).1 + self.resolve_lang_item_path(lang_item, expr.span, expr.hir_id).1 } pub(crate) fn check_expr_path( @@ -517,7 +514,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Res::Err => { self.suggest_assoc_method_call(segs); let e = - self.tcx.sess.delay_span_bug(qpath.span(), "`Res::Err` but no error emitted"); + self.tcx.sess.span_delayed_bug(qpath.span(), "`Res::Err` but no error emitted"); self.set_tainted_by_errors(e); Ty::new_error(tcx, e) } @@ -528,14 +525,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => self.instantiate_value_path(segs, opt_ty, res, expr.span, expr.hir_id).0, }; - if let ty::FnDef(did, callee_args) = *ty.kind() { + if let ty::FnDef(did, _) = *ty.kind() { let fn_sig = ty.fn_sig(tcx); - // HACK: whenever we get a FnDef in a non-const context, enforce effects to get the - // default `host = true` to avoid inference errors later. - if tcx.hir().body_const_context(self.body_id).is_none() { - self.enforce_context_effects(expr.hir_id, qpath.span(), did, callee_args); - } if tcx.fn_sig(did).skip_binder().abi() == RustIntrinsic && tcx.item_name(did) == sym::transmute { @@ -564,7 +556,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let span = args.get(i).map(|a| a.span).unwrap_or(expr.span); let input = self.instantiate_binder_with_fresh_vars( span, - infer::LateBoundRegionConversionTime::FnCall, + infer::BoundRegionConversionTime::FnCall, fn_sig.input(i), ); self.require_type_is_sized_deferred( @@ -582,7 +574,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // with fresh vars. let output = self.instantiate_binder_with_fresh_vars( expr.span, - infer::LateBoundRegionConversionTime::FnCall, + infer::BoundRegionConversionTime::FnCall, fn_sig.output(), ); self.require_type_is_sized_deferred(output, expr.span, traits::SizedReturnType); @@ -626,15 +618,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; - let coerce_to = match opt_coerce_to { - Some(c) => c, - None => { - // If the loop context is not a `loop { }`, then break with - // a value is illegal, and `opt_coerce_to` will be `None`. - // Return error in that case (#114529). - return Ty::new_misc_error(tcx); - } - }; + // If the loop context is not a `loop { }`, then break with + // a value is illegal, and `opt_coerce_to` will be `None`. + // Set expectation to error in that case and set tainted + // by error (#114529) + let coerce_to = opt_coerce_to.unwrap_or_else(|| { + let guar = tcx.sess.span_delayed_bug( + expr.span, + "illegal break with value found but no error reported", + ); + self.set_tainted_by_errors(guar); + Ty::new_error(tcx, guar) + }); // Recurse without `enclosing_breakables` borrowed. e_ty = self.check_expr_with_hint(e, coerce_to); @@ -660,7 +655,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if let Some(ref mut coerce) = ctxt.coerce { - if let Some(ref e) = expr_opt { + if let Some(e) = expr_opt { coerce.coerce(self, &cause, e, e_ty); } else { assert!(e_ty.is_unit()); @@ -669,11 +664,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self, &cause, |mut err| { + self.suggest_missing_semicolon(&mut err, expr, e_ty, false); self.suggest_mismatched_types_on_tail( &mut err, expr, ty, e_ty, target_id, ); let error = Some(Sorts(ExpectedFound { expected: ty, found: e_ty })); - self.annotate_loop_expected_due_to_inference(&mut err, expr, error); + self.annotate_loop_expected_due_to_inference(err, expr, error); if let Some(val) = ty_kind_suggestion(ty) { err.span_suggestion_verbose( expr.span.shrink_to_hi(), @@ -887,7 +883,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { kind: hir::ImplItemKind::Fn(..), span: encl_fn_span, .. - })) = self.tcx.hir().find_by_def_id(encl_item_id.def_id) + })) = self.tcx.opt_hir_node_by_def_id(encl_item_id.def_id) { // We are inside a function body, so reporting "return statement // outside of function body" needs an explanation. @@ -1001,7 +997,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { then: impl FnOnce(&hir::Expr<'_>), ) { let mut parent = self.tcx.hir().parent_id(original_expr_id); - while let Some(node) = self.tcx.hir().find(parent) { + while let Some(node) = self.tcx.opt_hir_node(parent) { match node { hir::Node::Expr(hir::Expr { kind: @@ -1133,8 +1129,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // The likely cause of this is `if foo = bar { .. }`. let actual_ty = Ty::new_unit(self.tcx); let mut err = self.demand_suptype_diag(expr.span, expected_ty, actual_ty).unwrap(); - let lhs_ty = self.check_expr(&lhs); - let rhs_ty = self.check_expr(&rhs); + let lhs_ty = self.check_expr(lhs); + let rhs_ty = self.check_expr(rhs); let (applicability, eq) = if self.can_coerce(rhs_ty, lhs_ty) { (Applicability::MachineApplicable, true) } else if let ExprKind::Binary( @@ -1145,7 +1141,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { // if x == 1 && y == 2 { .. } // + - let actual_lhs_ty = self.check_expr(&rhs_expr); + let actual_lhs_ty = self.check_expr(rhs_expr); (Applicability::MaybeIncorrect, self.can_coerce(rhs_ty, actual_lhs_ty)) } else if let ExprKind::Binary( Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. }, @@ -1155,7 +1151,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { // if x == 1 && y == 2 { .. } // + - let actual_rhs_ty = self.check_expr(&lhs_expr); + let actual_rhs_ty = self.check_expr(lhs_expr); (Applicability::MaybeIncorrect, self.can_coerce(actual_rhs_ty, lhs_ty)) } else { (Applicability::MaybeIncorrect, false) @@ -1192,7 +1188,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return Ty::new_error(self.tcx, reported); } - let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace); + let lhs_ty = self.check_expr_with_needs(lhs, Needs::MutPlace); let suggest_deref_binop = |err: &mut Diagnostic, rhs_ty: Ty<'tcx>| { if let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) { @@ -1219,7 +1215,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This is (basically) inlined `check_expr_coercible_to_type`, but we want // to suggest an additional fixup here in `suggest_deref_binop`. - let rhs_ty = self.check_expr_with_hint(&rhs, lhs_ty); + let rhs_ty = self.check_expr_with_hint(rhs, lhs_ty); if let (_, Some(mut diag)) = self.demand_coerce_diag(rhs, rhs_ty, lhs_ty, Some(lhs), AllowTwoPhase::No) { @@ -1280,7 +1276,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let (ctxt, ()) = self.with_breakable_ctxt(expr.hir_id, ctxt, || { - self.check_block_no_value(&body); + self.check_block_no_value(body); }); if ctxt.may_break { @@ -1296,7 +1292,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // permit break with a value [1]. if ctxt.coerce.is_none() && !ctxt.may_break { // [1] - self.tcx.sess.delay_span_bug(body.span, "no coercion, but loop may not break"); + self.tcx.sess.span_delayed_bug(body.span, "no coercion, but loop may not break"); } ctxt.coerce.map(|c| c.complete(self)).unwrap_or_else(|| Ty::new_unit(self.tcx)) } @@ -1310,7 +1306,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { args: &'tcx [hir::Expr<'tcx>], expected: Expectation<'tcx>, ) -> Ty<'tcx> { - let rcvr_t = self.check_expr(&rcvr); + let rcvr_t = self.check_expr(rcvr); // no need to check for bot/err -- callee does that let rcvr_t = self.structurally_resolve_type(rcvr.span, rcvr_t); let span = segment.ident.span; @@ -1319,9 +1315,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(method) => { // We could add a "consider `foo::<params>`" suggestion here, but I wasn't able to // trigger this codepath causing `structurally_resolve_type` to emit an error. - - self.enforce_context_effects(expr.hir_id, expr.span, method.def_id, method.args); - self.write_method_call(expr.hir_id, method); + self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method); Ok(method) } Err(error) => { @@ -1344,7 +1338,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Call the generic checker. - self.check_method_argument_types(span, expr, method, &args, DontTupleArguments, expected) + self.check_method_argument_types(span, expr, method, args, DontTupleArguments, expected) } fn check_expr_cast( @@ -1442,12 +1436,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length && let Some(span) = self.tcx.hir().opt_span(hir_id) { - match self - .tcx - .sess - .diagnostic() - .steal_diagnostic(span, StashKey::UnderscoreForArrayLengths) - { + match self.tcx.sess.dcx().steal_diagnostic(span, StashKey::UnderscoreForArrayLengths) { Some(mut err) => { err.span_suggestion( span, @@ -1475,7 +1464,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let fcx = FnCtxt::new(self, self.param_env, def_id); crate::GatherLocalsVisitor::new(&fcx).visit_body(body); - let ty = fcx.check_expr_with_expectation(&body.value, expected); + let ty = fcx.check_expr_with_expectation(body.value, expected); fcx.require_type_is_sized(ty, body.value.span, traits::ConstSized); fcx.write_ty(block.hir_id, ty); ty @@ -1504,7 +1493,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (element_ty, t) = match uty { Some(uty) => { - self.check_expr_coercible_to_type(&element, uty, None); + self.check_expr_coercible_to_type(element, uty, None); (uty, uty) } None => { @@ -1512,7 +1501,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { kind: TypeVariableOriginKind::MiscVariable, span: element.span, }); - let element_ty = self.check_expr_has_type_or_error(&element, ty, |_| {}); + let element_ty = self.check_expr_has_type_or_error(element, ty, |_| {}); (element_ty, ty) } }; @@ -1608,10 +1597,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let elt_ts_iter = elts.iter().enumerate().map(|(i, e)| match flds { Some(fs) if i < fs.len() => { let ety = fs[i]; - self.check_expr_coercible_to_type(&e, ety, None); + self.check_expr_coercible_to_type(e, ety, None); ety } - _ => self.check_expr_with_expectation(&e, NoExpectation), + _ => self.check_expr_with_expectation(e, NoExpectation), }); let tuple = Ty::new_tup_from_iter(self.tcx, elt_ts_iter); if let Err(guar) = tuple.error_reported() { @@ -1737,9 +1726,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Make sure to give a type to the field even if there's // an error, so we can continue type-checking. - let ty = self.check_expr_with_hint(&field.expr, field_type); + let ty = self.check_expr_with_hint(field.expr, field_type); let (_, diag) = - self.demand_coerce_diag(&field.expr, ty, field_type, None, AllowTwoPhase::No); + self.demand_coerce_diag(field.expr, ty, field_type, None, AllowTwoPhase::No); if let Some(mut diag) = diag { if idx == ast_fields.len() - 1 { @@ -1897,7 +1886,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .collect(); if !private_fields.is_empty() { - self.report_private_fields(adt_ty, span, private_fields, ast_fields); + self.report_private_fields(adt_ty, span, expr.span, private_fields, ast_fields); } else { self.report_missing_fields( adt_ty, @@ -1917,10 +1906,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base_expr: &'tcx Option<&'tcx hir::Expr<'tcx>>, ) { for field in fields { - self.check_expr(&field.expr); + self.check_expr(field.expr); } if let Some(base) = *base_expr { - self.check_expr(&base); + self.check_expr(base); } } @@ -1933,7 +1922,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// 8 | foo::Foo {}; /// | ^^^^^^^^ missing `you_can_use_this_field` /// - /// error: aborting due to previous error + /// error: aborting due to 1 previous error /// ``` fn report_missing_fields( &self, @@ -2008,11 +1997,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { != range_def_id { // Suppress any range expr type mismatches - if let Some(mut diag) = self - .tcx - .sess - .diagnostic() - .steal_diagnostic(last_expr_field.span, StashKey::MaybeFruTypo) + if let Some(mut diag) = + self.tcx.sess.dcx().steal_diagnostic(last_expr_field.span, StashKey::MaybeFruTypo) { diag.delay_as_bug(); } @@ -2050,12 +2036,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// 8 | foo::Foo {}; /// | ^^^^^^^^ /// - /// error: aborting due to previous error + /// error: aborting due to 1 previous error /// ``` fn report_private_fields( &self, adt_ty: Ty<'tcx>, span: Span, + expr_span: Span, private_fields: Vec<&ty::FieldDef>, used_fields: &'tcx [hir::ExprField<'tcx>], ) { @@ -2092,14 +2079,90 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let names = names.iter().map(|name| format!("`{name}`")).collect::<Vec<_>>(); format!("{} and `{last}` ", names.join(", ")) } - [] => unreachable!(), + [] => bug!("expected at least one private field to report"), }; err.note(format!( - "... and other private field{s} {names}that {were} not provided", + "{}private field{s} {names}that {were} not provided", + if used_fields.is_empty() { "" } else { "...and other " }, s = pluralize!(remaining_private_fields_len), were = pluralize!("was", remaining_private_fields_len), )); } + + if let ty::Adt(def, _) = adt_ty.kind() { + let def_id = def.did(); + let mut items = self + .tcx + .inherent_impls(def_id) + .iter() + .flat_map(|i| self.tcx.associated_items(i).in_definition_order()) + // Only assoc fn with no receivers. + .filter(|item| { + matches!(item.kind, ty::AssocKind::Fn) && !item.fn_has_self_parameter + }) + .filter_map(|item| { + // Only assoc fns that return `Self` + let fn_sig = self.tcx.fn_sig(item.def_id).skip_binder(); + let ret_ty = fn_sig.output(); + let ret_ty = + self.tcx.normalize_erasing_late_bound_regions(self.param_env, ret_ty); + if !self.can_eq(self.param_env, ret_ty, adt_ty) { + return None; + } + let input_len = fn_sig.inputs().skip_binder().len(); + let order = !item.name.as_str().starts_with("new"); + Some((order, item.name, input_len)) + }) + .collect::<Vec<_>>(); + items.sort_by_key(|(order, _, _)| *order); + let suggestion = |name, args| { + format!( + "::{name}({})", + std::iter::repeat("_").take(args).collect::<Vec<_>>().join(", ") + ) + }; + match &items[..] { + [] => {} + [(_, name, args)] => { + err.span_suggestion_verbose( + span.shrink_to_hi().with_hi(expr_span.hi()), + format!("you might have meant to use the `{name}` associated function"), + suggestion(name, *args), + Applicability::MaybeIncorrect, + ); + } + _ => { + err.span_suggestions( + span.shrink_to_hi().with_hi(expr_span.hi()), + "you might have meant to use an associated function to build this type", + items + .iter() + .map(|(_, name, args)| suggestion(name, *args)) + .collect::<Vec<String>>(), + Applicability::MaybeIncorrect, + ); + } + } + if let Some(default_trait) = self.tcx.get_diagnostic_item(sym::Default) + && self + .infcx + .type_implements_trait(default_trait, [adt_ty], self.param_env) + .may_apply() + { + err.multipart_suggestion( + "consider using the `Default` trait", + vec![ + (span.shrink_to_lo(), "<".to_string()), + ( + span.shrink_to_hi().with_hi(expr_span.hi()), + " as std::default::Default>::default()".to_string(), + ), + ], + Applicability::MaybeIncorrect, + ); + } + } + err.emit(); } @@ -2116,7 +2179,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let guar = self .tcx .sess - .delay_span_bug(expr.span, "parser recovered but no error was emitted"); + .span_delayed_bug(expr.span, "parser recovered but no error was emitted"); self.set_tainted_by_errors(guar); return guar; } @@ -2191,7 +2254,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(field_name) = find_best_match_for_name(&available_field_names, field.ident.name, None) { - err.span_suggestion( + err.span_label(field.ident.span, "unknown field"); + err.span_suggestion_verbose( field.ident.span, "a field with a similar name exists", field_name, @@ -2274,7 +2338,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match deref_base_ty.kind() { ty::Adt(base_def, args) if !base_def.is_enum() => { debug!("struct named {:?}", deref_base_ty); - let body_hir_id = self.tcx.hir().local_def_id_to_hir_id(self.body_id); + let body_hir_id = self.tcx.local_def_id_to_hir_id(self.body_id); let (ident, def_scope) = self.tcx.adjust_ident_and_get_scope(field, base_def.did(), body_hir_id); let fields = &base_def.non_enum_variant().fields; @@ -2331,7 +2395,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let guar = if field.name == kw::Empty { - self.tcx.sess.delay_span_bug(field.span, "field name with no name") + self.tcx.sess.span_delayed_bug(field.span, "field name with no name") } else if self.method_exists(field, base_ty, expr.hir_id, expected.only_has_type(self)) { self.ban_take_value_of_method(expr, base_ty, field) } else if !base_ty.is_primitive_ty() { @@ -2420,35 +2484,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty: Ty<'tcx>, ) { let Some(output_ty) = self.get_impl_future_output_ty(ty) else { + err.span_label(field_ident.span, "unknown field"); return; }; - let mut add_label = true; - if let ty::Adt(def, _) = output_ty.kind() { - // no field access on enum type - if !def.is_enum() { - if def - .non_enum_variant() - .fields - .iter() - .any(|field| field.ident(self.tcx) == field_ident) - { - add_label = false; - err.span_label( - field_ident.span, - "field not available in `impl Future`, but it is available in its `Output`", - ); - err.span_suggestion_verbose( - base.span.shrink_to_hi(), - "consider `await`ing on the `Future` and access the field of its `Output`", - ".await", - Applicability::MaybeIncorrect, - ); - } - } + let ty::Adt(def, _) = output_ty.kind() else { + err.span_label(field_ident.span, "unknown field"); + return; + }; + // no field access on enum type + if def.is_enum() { + err.span_label(field_ident.span, "unknown field"); + return; } - if add_label { - err.span_label(field_ident.span, format!("field not found in `{ty}`")); + if !def.non_enum_variant().fields.iter().any(|field| field.ident(self.tcx) == field_ident) { + err.span_label(field_ident.span, "unknown field"); + return; } + err.span_label( + field_ident.span, + "field not available in `impl Future`, but it is available in its `Output`", + ); + err.span_suggestion_verbose( + base.span.shrink_to_hi(), + "consider `await`ing on the `Future` and access the field of its `Output`", + ".await", + Applicability::MaybeIncorrect, + ); } fn ban_nonexisting_field( @@ -2471,16 +2532,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::RawPtr(..) => { self.suggest_first_deref_field(&mut err, expr, base, ident); } - ty::Adt(def, _) if !def.is_enum() => { - self.suggest_fields_on_recordish(&mut err, expr, def, ident); - } ty::Param(param_ty) => { + err.span_label(ident.span, "unknown field"); self.point_at_param_definition(&mut err, param_ty); } ty::Alias(ty::Opaque, _) => { self.suggest_await_on_field_access(&mut err, ident, base, base_ty.peel_refs()); } - _ => {} + _ => { + err.span_label(ident.span, "unknown field"); + } } self.suggest_fn_call(&mut err, base, base_ty, |output_ty| { @@ -2624,7 +2685,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let param_def_id = generic_param.def_id; let param_hir_id = match param_def_id.as_local() { - Some(x) => self.tcx.hir().local_def_id_to_hir_id(x), + Some(x) => self.tcx.local_def_id_to_hir_id(x), None => return, }; let param_span = self.tcx.hir().span(param_hir_id); @@ -2633,34 +2694,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(param_span, format!("type parameter '{param_name}' declared here")); } - fn suggest_fields_on_recordish( - &self, - err: &mut Diagnostic, - expr: &hir::Expr<'_>, - def: ty::AdtDef<'tcx>, - field: Ident, - ) { - let available_field_names = self.available_field_names(def.non_enum_variant(), expr, &[]); - if let Some(suggested_field_name) = - find_best_match_for_name(&available_field_names, field.name, None) - { - err.span_suggestion( - field.span, - "a field with a similar name exists", - suggested_field_name, - Applicability::MaybeIncorrect, - ); - } else { - err.span_label(field.span, "unknown field"); - if !available_field_names.is_empty() { - err.note(format!( - "available fields are: {}", - self.name_series_display(available_field_names), - )); - } - } - } - fn maybe_suggest_array_indexing( &self, err: &mut Diagnostic, @@ -2669,6 +2702,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { field: Ident, len: ty::Const<'tcx>, ) { + err.span_label(field.span, "unknown field"); if let (Some(len), Ok(user_index)) = (len.try_eval_target_usize(self.tcx, self.param_env), field.as_str().parse::<u64>()) && let Ok(base) = self.tcx.sess.source_map().span_to_snippet(base.span) @@ -2691,6 +2725,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base: &hir::Expr<'_>, field: Ident, ) { + err.span_label(field.span, "unknown field"); if let Ok(base) = self.tcx.sess.source_map().span_to_snippet(base.span) { let msg = format!("`{base}` is a raw pointer; try dereferencing it"); let suggestion = format!("(*{base}).{field}"); @@ -2709,7 +2744,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut err = type_error_struct!( self.tcx().sess, - field.span, + span, expr_t, E0609, "no field `{field}` on type `{expr_t}`", @@ -2717,10 +2752,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // try to add a suggestion in case the field is a nested field of a field of the Adt let mod_id = self.tcx.parent_module(id).to_def_id(); - if let Some((fields, args)) = - self.get_field_candidates_considering_privacy(span, expr_t, mod_id) + let (ty, unwrap) = if let ty::Adt(def, args) = expr_t.kind() + && (self.tcx.is_diagnostic_item(sym::Result, def.did()) + || self.tcx.is_diagnostic_item(sym::Option, def.did())) + && let Some(arg) = args.get(0) + && let Some(ty) = arg.as_type() + { + (ty, "unwrap().") + } else { + (expr_t, "") + }; + for (found_fields, args) in + self.get_field_candidates_considering_privacy(span, ty, mod_id, id) { - let candidate_fields: Vec<_> = fields + let field_names = found_fields.iter().map(|field| field.name).collect::<Vec<_>>(); + let mut candidate_fields: Vec<_> = found_fields + .into_iter() .filter_map(|candidate_field| { self.check_for_nested_field_satisfying( span, @@ -2729,17 +2776,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { args, vec![], mod_id, + id, ) }) .map(|mut field_path| { field_path.pop(); field_path .iter() - .map(|id| id.name.to_ident_string()) - .collect::<Vec<String>>() - .join(".") + .map(|id| format!("{}.", id.name.to_ident_string())) + .collect::<String>() }) .collect::<Vec<_>>(); + candidate_fields.sort(); let len = candidate_fields.len(); if len > 0 { @@ -2750,9 +2798,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if len > 1 { "some" } else { "one" }, if len > 1 { "have" } else { "has" }, ), - candidate_fields.iter().map(|path| format!("{path}.")), + candidate_fields.iter().map(|path| format!("{unwrap}{path}")), Applicability::MaybeIncorrect, ); + } else { + if let Some(field_name) = find_best_match_for_name(&field_names, field.name, None) { + err.span_suggestion_verbose( + field.span, + "a field with a similar name exists", + format!("{unwrap}{}", field_name), + Applicability::MaybeIncorrect, + ); + } else if !field_names.is_empty() { + let is = if field_names.len() == 1 { " is" } else { "s are" }; + err.note(format!( + "available field{is}: {}", + self.name_series_display(field_names), + )); + } } } err @@ -2781,33 +2844,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, base_ty: Ty<'tcx>, mod_id: DefId, - ) -> Option<(impl Iterator<Item = &'tcx ty::FieldDef> + 'tcx, GenericArgsRef<'tcx>)> { + hir_id: hir::HirId, + ) -> Vec<(Vec<&'tcx ty::FieldDef>, GenericArgsRef<'tcx>)> { debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_ty); - for (base_t, _) in self.autoderef(span, base_ty) { - match base_t.kind() { - ty::Adt(base_def, args) if !base_def.is_enum() => { - let tcx = self.tcx; - let fields = &base_def.non_enum_variant().fields; - // Some struct, e.g. some that impl `Deref`, have all private fields - // because you're expected to deref them to access the _real_ fields. - // This, for example, will help us suggest accessing a field through a `Box<T>`. - if fields.iter().all(|field| !field.vis.is_accessible_from(mod_id, tcx)) { - continue; + self.autoderef(span, base_ty) + .filter_map(move |(base_t, _)| { + match base_t.kind() { + ty::Adt(base_def, args) if !base_def.is_enum() => { + let tcx = self.tcx; + let fields = &base_def.non_enum_variant().fields; + // Some struct, e.g. some that impl `Deref`, have all private fields + // because you're expected to deref them to access the _real_ fields. + // This, for example, will help us suggest accessing a field through a `Box<T>`. + if fields.iter().all(|field| !field.vis.is_accessible_from(mod_id, tcx)) { + return None; + } + return Some(( + fields + .iter() + .filter(move |field| { + field.vis.is_accessible_from(mod_id, tcx) + && self.is_field_suggestable(field, hir_id, span) + }) + // For compile-time reasons put a limit on number of fields we search + .take(100) + .collect::<Vec<_>>(), + *args, + )); } - return Some(( - fields - .iter() - .filter(move |field| field.vis.is_accessible_from(mod_id, tcx)) - // For compile-time reasons put a limit on number of fields we search - .take(100), - args, - )); + _ => None, } - _ => {} - } - } - None + }) + .collect() } /// This method is called after we have encountered a missing field error to recursively @@ -2820,6 +2889,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { subst: GenericArgsRef<'tcx>, mut field_path: Vec<Ident>, mod_id: DefId, + hir_id: HirId, ) -> Option<Vec<Ident>> { debug!( "check_for_nested_field_satisfying(span: {:?}, candidate_field: {:?}, field_path: {:?}", @@ -2835,20 +2905,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let field_ty = candidate_field.ty(self.tcx, subst); if matches(candidate_field, field_ty) { return Some(field_path); - } else if let Some((nested_fields, subst)) = - self.get_field_candidates_considering_privacy(span, field_ty, mod_id) - { - // recursively search fields of `candidate_field` if it's a ty::Adt - for field in nested_fields { - if let Some(field_path) = self.check_for_nested_field_satisfying( - span, - matches, - field, - subst, - field_path.clone(), - mod_id, - ) { - return Some(field_path); + } else { + for (nested_fields, subst) in + self.get_field_candidates_considering_privacy(span, field_ty, mod_id, hir_id) + { + // recursively search fields of `candidate_field` if it's a ty::Adt + for field in nested_fields { + if let Some(field_path) = self.check_for_nested_field_satisfying( + span, + matches, + field, + subst, + field_path.clone(), + mod_id, + hir_id, + ) { + return Some(field_path); + } } } } @@ -2863,8 +2936,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &'tcx hir::Expr<'tcx>, brackets_span: Span, ) -> Ty<'tcx> { - let base_t = self.check_expr(&base); - let idx_t = self.check_expr(&idx); + let base_t = self.check_expr(base); + let idx_t = self.check_expr(idx); if base_t.references_error() { base_t @@ -2877,7 +2950,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // two-phase not needed because index_ty is never mutable self.demand_coerce(idx, idx_t, index_ty, None, AllowTwoPhase::No); self.select_obligations_where_possible(|errors| { - self.point_at_index_if_possible(errors, idx.span) + self.point_at_index(errors, idx.span); }); element_ty } @@ -2905,7 +2978,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut needs_note = true; // If the index is an integer, we can show the actual // fixed expression: - if let ExprKind::Lit(ref lit) = idx.kind + if let ExprKind::Lit(lit) = idx.kind && let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) = lit.node && i < types .len() @@ -2978,7 +3051,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; }; - self.commit_if_ok(|_| { + self.commit_if_ok(|snapshot| { + let outer_universe = self.universe(); + let ocx = ObligationCtxt::new(self); let impl_args = self.fresh_args_for_item(base_expr.span, impl_def_id); let impl_trait_ref = @@ -2988,7 +3063,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Match the impl self type against the base ty. If this fails, // we just skip this impl, since it's not particularly useful. let impl_trait_ref = ocx.normalize(&cause, self.param_env, impl_trait_ref); - ocx.eq(&cause, self.param_env, impl_trait_ref.self_ty(), base_ty)?; + ocx.eq(&cause, self.param_env, base_ty, impl_trait_ref.self_ty())?; // Register the impl's predicates. One of these predicates // must be unsatisfied, or else we wouldn't have gotten here @@ -3024,11 +3099,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ty::new_projection(self.tcx, index_trait_output_def_id, impl_trait_ref.args), ); - let errors = ocx.select_where_possible(); + let true_errors = ocx.select_where_possible(); + + // Do a leak check -- we can't really report report a useful error here, + // but it at least avoids an ICE when the error has to do with higher-ranked + // lifetimes. + self.leak_check(outer_universe, Some(snapshot))?; + + // Bail if we have ambiguity errors, which we can't report in a useful way. + let ambiguity_errors = ocx.select_all_or_error(); + if true_errors.is_empty() && !ambiguity_errors.is_empty() { + return Err(NoSolution); + } + // There should be at least one error reported. If not, we // will still delay a span bug in `report_fulfillment_errors`. Ok::<_, NoSolution>(( - self.err_ctxt().report_fulfillment_errors(errors), + self.err_ctxt().report_fulfillment_errors(true_errors), impl_trait_ref.args.type_at(1), element_ty, )) @@ -3036,16 +3123,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .ok() } - fn point_at_index_if_possible( - &self, - errors: &mut Vec<traits::FulfillmentError<'tcx>>, - span: Span, - ) { + fn point_at_index(&self, errors: &mut Vec<traits::FulfillmentError<'tcx>>, span: Span) { + let mut seen_preds = FxHashSet::default(); + // We re-sort here so that the outer most root obligations comes first, as we have the + // subsequent weird logic to identify *every* relevant obligation for proper deduplication + // of diagnostics. + errors.sort_by_key(|error| error.root_obligation.recursion_depth); for error in errors { - match error.obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) - if self.tcx.is_diagnostic_item(sym::SliceIndex, predicate.trait_ref.def_id) => { + match ( + error.root_obligation.predicate.kind().skip_binder(), + error.obligation.predicate.kind().skip_binder(), + ) { + (ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)), _) + if self.tcx.lang_items().index_trait() == Some(predicate.trait_ref.def_id) => + { + seen_preds.insert(error.obligation.predicate.kind().skip_binder()); + } + (_, ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate))) + if self.tcx.is_diagnostic_item(sym::SliceIndex, predicate.trait_ref.def_id) => + { + seen_preds.insert(error.obligation.predicate.kind().skip_binder()); } + (root, pred) if seen_preds.contains(&pred) || seen_preds.contains(&root) => {} _ => continue, } error.obligation.cause.span = span; @@ -3060,7 +3159,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Ty<'tcx> { match self.resume_yield_tys { Some((resume_ty, yield_ty)) => { - self.check_expr_coercible_to_type(&value, yield_ty, None); + self.check_expr_coercible_to_type(value, yield_ty, None); resume_ty } @@ -3069,7 +3168,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // information. Hence, we check the source of the yield expression here and check its // value's type against `()` (this check should always hold). None if src.is_await() => { - self.check_expr_coercible_to_type(&value, Ty::new_unit(self.tcx), None); + self.check_expr_coercible_to_type(value, Ty::new_unit(self.tcx), None); Ty::new_unit(self.tcx) } _ => { @@ -3163,7 +3262,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match container.kind() { ty::Adt(container_def, args) if container_def.is_enum() => { - let block = self.tcx.hir().local_def_id_to_hir_id(self.body_id); + let block = self.tcx.local_def_id_to_hir_id(self.body_id); let (ident, _def_scope) = self.tcx.adjust_ident_and_get_scope(field, container_def.did(), block); @@ -3173,19 +3272,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sym::offset_of_enum, ident.span, "using enums in offset_of is experimental", - ).emit(); + ) + .emit(); } - let Some((index, variant)) = container_def.variants() + let Some((index, variant)) = container_def + .variants() .iter_enumerated() - .find(|(_, v)| v.ident(self.tcx).normalize_to_macros_2_0() == ident) else { + .find(|(_, v)| v.ident(self.tcx).normalize_to_macros_2_0() == ident) + else { let mut err = type_error_struct!( self.tcx().sess, ident.span, container, E0599, "no variant named `{ident}` found for enum `{container}`", - ); + ); err.span_label(field.span, "variant not found"); err.emit(); break; @@ -3197,7 +3299,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { container, E0795, "`{ident}` is an enum variant; expected field at end of `offset_of`", - ); + ); err.span_label(field.span, "enum variant"); err.emit(); break; @@ -3205,16 +3307,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (subident, sub_def_scope) = self.tcx.adjust_ident_and_get_scope(subfield, variant.def_id, block); - let Some((subindex, field)) = variant.fields + let Some((subindex, field)) = variant + .fields .iter_enumerated() - .find(|(_, f)| f.ident(self.tcx).normalize_to_macros_2_0() == subident) else { + .find(|(_, f)| f.ident(self.tcx).normalize_to_macros_2_0() == subident) + else { let mut err = type_error_struct!( self.tcx().sess, ident.span, container, E0609, "no field named `{subfield}` on enum variant `{container}::{ident}`", - ); + ); err.span_label(field.span, "this enum variant..."); err.span_label(subident.span, "...does not have this field"); err.emit(); @@ -3240,7 +3344,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { continue; } ty::Adt(container_def, args) => { - let block = self.tcx.hir().local_def_id_to_hir_id(self.body_id); + let block = self.tcx.local_def_id_to_hir_id(self.body_id); let (ident, def_scope) = self.tcx.adjust_ident_and_get_scope(field, container_def.did(), block); diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 6be3ad657..c22b15231 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -147,7 +147,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { self.walk_irrefutable_pat(¶m_place, param.pat); } - self.consume_expr(&body.value); + self.consume_expr(body.value); } fn tcx(&self) -> TyCtxt<'tcx> { @@ -237,10 +237,10 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { self.consume_exprs(exprs); } - hir::ExprKind::If(ref cond_expr, ref then_expr, ref opt_else_expr) => { + hir::ExprKind::If(cond_expr, then_expr, ref opt_else_expr) => { self.consume_expr(cond_expr); self.consume_expr(then_expr); - if let Some(ref else_expr) = *opt_else_expr { + if let Some(else_expr) = *opt_else_expr { self.consume_expr(else_expr); } } @@ -249,7 +249,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { self.walk_local(init, pat, None, |t| t.borrow_expr(init, ty::ImmBorrow)) } - hir::ExprKind::Match(ref discr, arms, _) => { + hir::ExprKind::Match(discr, arms, _) => { let discr_place = return_if_err!(self.mc.cat_expr(discr)); return_if_err!(self.maybe_read_scrutinee( discr, @@ -267,7 +267,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { self.consume_exprs(exprs); } - hir::ExprKind::AddrOf(_, m, ref base) => { + hir::ExprKind::AddrOf(_, m, base) => { // &base // make sure that the thing we are pointing out stays valid // for the lifetime `scope_r` of the resulting ptr: @@ -379,7 +379,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // only the fn body we were given. } - hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => { + hir::StmtKind::Expr(expr) | hir::StmtKind::Semi(expr) => { self.consume_expr(expr); } } @@ -401,12 +401,17 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { mc.cat_pattern(discr_place.clone(), pat, |place, pat| { match &pat.kind { PatKind::Binding(.., opt_sub_pat) => { - // If the opt_sub_pat is None, than the binding does not count as + // If the opt_sub_pat is None, then the binding does not count as // a wildcard for the purpose of borrowing discr. if opt_sub_pat.is_none() { needs_to_be_read = true; } } + PatKind::Never => { + // A never pattern reads the value. + // FIXME(never_patterns): does this do what I expect? + needs_to_be_read = true; + } PatKind::Path(qpath) => { // A `Path` pattern is just a name like `Foo`. This is either a // named constant or else it refers to an ADT variant @@ -505,7 +510,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { )); self.walk_block(els) } - self.walk_irrefutable_pat(&expr_place, &pat); + self.walk_irrefutable_pat(&expr_place, pat); } /// Indicates that the value of `blk` will be consumed, meaning either copied or moved @@ -517,7 +522,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { self.walk_stmt(stmt); } - if let Some(ref tail_expr) = blk.expr { + if let Some(tail_expr) = blk.expr { self.consume_expr(tail_expr); } } @@ -533,7 +538,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // The struct path probably didn't resolve if self.mc.typeck_results.opt_field_index(field.hir_id).is_none() { - self.tcx().sess.delay_span_bug(field.span, "couldn't resolve index for field"); + self.tcx().sess.span_delayed_bug(field.span, "couldn't resolve index for field"); } } @@ -665,8 +670,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { self.walk_pat(discr_place, arm.pat, arm.guard.is_some()); match arm.guard { - Some(hir::Guard::If(ref e)) => self.consume_expr(e), - Some(hir::Guard::IfLet(ref l)) => { + Some(hir::Guard::If(e)) => self.consume_expr(e), + Some(hir::Guard::IfLet(l)) => { self.walk_local(l.init, l.pat, None, |t| t.borrow_expr(l.init, ty::ImmBorrow)) } None => {} @@ -848,7 +853,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // be a local variable PlaceBase::Local(*var_hir_id) }; - let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_def_id); + let closure_hir_id = tcx.local_def_id_to_hir_id(closure_def_id); let place_with_id = PlaceWithHirId::new( capture_info .path_expr_id diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index 38b780367..023bd70be 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -24,9 +24,9 @@ impl<'tcx> FnCtxt<'_, 'tcx> { self.fulfillment_cx.borrow_mut().pending_obligations() ); - let fallback_occured = self.fallback_types() | self.fallback_effects(); + let fallback_occurred = self.fallback_types() | self.fallback_effects(); - if !fallback_occured { + if !fallback_occurred { return; } @@ -57,24 +57,25 @@ impl<'tcx> FnCtxt<'_, 'tcx> { } fn fallback_types(&self) -> bool { - // Check if we have any unsolved variables. If not, no need for fallback. - let unsolved_variables = self.unsolved_variables(); + // Check if we have any unresolved variables. If not, no need for fallback. + let unresolved_variables = self.unresolved_variables(); - if unsolved_variables.is_empty() { + if unresolved_variables.is_empty() { return false; } - let diverging_fallback = self.calculate_diverging_fallback(&unsolved_variables); + let diverging_fallback = self.calculate_diverging_fallback(&unresolved_variables); // We do fallback in two passes, to try to generate // better error messages. // The first time, we do *not* replace opaque types. - for ty in unsolved_variables { + let mut fallback_occurred = false; + for ty in unresolved_variables { debug!("unsolved_variable = {:?}", ty); - self.fallback_if_possible(ty, &diverging_fallback); + fallback_occurred |= self.fallback_if_possible(ty, &diverging_fallback); } - true + fallback_occurred } fn fallback_effects(&self) -> bool { @@ -84,9 +85,8 @@ impl<'tcx> FnCtxt<'_, 'tcx> { return false; } - // not setting `fallback_has_occured` here because that field is only used for type fallback - // diagnostics. - + // not setting the `fallback_has_occured` field here because + // that field is only used for type fallback diagnostics. for effect in unsolved_effects { let expected = self.tcx.consts.true_; let cause = self.misc(rustc_span::DUMMY_SP); @@ -122,7 +122,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { &self, ty: Ty<'tcx>, diverging_fallback: &UnordMap<Ty<'tcx>, Ty<'tcx>>, - ) { + ) -> bool { // Careful: we do NOT shallow-resolve `ty`. We know that `ty` // is an unsolved variable, and we determine its fallback // based solely on how it was created, not what other type @@ -147,7 +147,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64, _ => match diverging_fallback.get(&ty) { Some(&fallback_ty) => fallback_ty, - None => return, + None => return false, }, }; debug!("fallback_if_possible(ty={:?}): defaulting to `{:?}`", ty, fallback); @@ -159,6 +159,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { .unwrap_or(rustc_span::DUMMY_SP); self.demand_eqtype(span, ty, fallback); self.fallback_has_occurred.set(true); + true } /// The "diverging fallback" system is rather complicated. This is @@ -230,9 +231,9 @@ impl<'tcx> FnCtxt<'_, 'tcx> { /// any variable that has an edge into `D`. fn calculate_diverging_fallback( &self, - unsolved_variables: &[Ty<'tcx>], + unresolved_variables: &[Ty<'tcx>], ) -> UnordMap<Ty<'tcx>, Ty<'tcx>> { - debug!("calculate_diverging_fallback({:?})", unsolved_variables); + debug!("calculate_diverging_fallback({:?})", unresolved_variables); // Construct a coercion graph where an edge `A -> B` indicates // a type variable is that is coerced @@ -240,7 +241,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // Extract the unsolved type inference variable vids; note that some // unsolved variables are integer/float variables and are excluded. - let unsolved_vids = unsolved_variables.iter().filter_map(|ty| ty.ty_vid()); + let unsolved_vids = unresolved_variables.iter().filter_map(|ty| ty.ty_vid()); // Compute the diverging root vids D -- that is, the root vid of // those type variables that (a) are the target of a coercion from 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), .. })) = diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 0ad2c1d92..0cca779b1 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -93,7 +93,7 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { fn declare(&mut self, decl: Declaration<'tcx>) { let local_ty = match decl.ty { Some(ref ty) => { - let o_ty = self.fcx.to_ty(&ty); + let o_ty = self.fcx.to_ty(ty); let c_ty = self.fcx.inh.infcx.canonicalize_user_type_annotation(UserType::Ty(o_ty.raw)); diff --git a/compiler/rustc_hir_typeck/src/inherited.rs b/compiler/rustc_hir_typeck/src/inherited.rs index efd0b8577..7a6a2b2a0 100644 --- a/compiler/rustc_hir_typeck/src/inherited.rs +++ b/compiler/rustc_hir_typeck/src/inherited.rs @@ -9,7 +9,7 @@ use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::LocalDefIdMap; -use rustc_span::{self, Span}; +use rustc_span::Span; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{self, PredicateObligation, TraitEngine, TraitEngineExt as _}; @@ -75,7 +75,7 @@ impl<'tcx> Deref for Inherited<'tcx> { impl<'tcx> Inherited<'tcx> { pub fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { - let hir_owner = tcx.hir().local_def_id_to_hir_id(def_id).owner; + let hir_owner = tcx.local_def_id_to_hir_id(def_id).owner; let infcx = tcx .infer_ctxt() diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index 5d516eaf5..a3c77af62 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -48,7 +48,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let to = normalize(to); trace!(?from, ?to); if from.has_non_region_infer() || to.has_non_region_infer() { - tcx.sess.delay_span_bug(span, "argument to transmute has inference variables"); + tcx.sess.span_delayed_bug(span, "argument to transmute has inference variables"); return; } // Transmutes that are only changing lifetimes are always ok. diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 46dcc4555..13a249486 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -52,11 +52,7 @@ use crate::expectation::Expectation; use crate::fn_ctxt::RawTy; use crate::gather_locals::GatherLocalsVisitor; use rustc_data_structures::unord::UnordSet; -use rustc_errors::{ - struct_span_err, DiagnosticId, DiagnosticMessage, ErrorGuaranteed, MultiSpan, - SubdiagnosticMessage, -}; -use rustc_fluent_macro::fluent_messages; +use rustc_errors::{struct_span_err, DiagnosticId, ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::Visitor; @@ -71,7 +67,7 @@ use rustc_session::config; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::Span; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } #[macro_export] macro_rules! type_error_struct { @@ -131,7 +127,7 @@ fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool { } if let Some(def_id) = def_id.as_local() { - primary_body_of(tcx.hir().get_by_def_id(def_id)).is_some() + primary_body_of(tcx.hir_node_by_def_id(def_id)).is_some() } else { false } @@ -150,7 +146,7 @@ fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tc /// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors. fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> { let fallback = move || { - let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id)); + let span = tcx.hir().span(tcx.local_def_id_to_hir_id(def_id)); Ty::new_error_with_message(tcx, span, "diagnostic only typeck table used") }; typeck_with_fallback(tcx, def_id, fallback) @@ -169,8 +165,8 @@ fn typeck_with_fallback<'tcx>( return tcx.typeck(typeck_root_def_id); } - let id = tcx.hir().local_def_id_to_hir_id(def_id); - let node = tcx.hir().get(id); + let id = tcx.local_def_id_to_hir_id(def_id); + let node = tcx.hir_node(id); let span = tcx.hir().span(id); // Figure out what primary body this item has. @@ -205,7 +201,7 @@ fn typeck_with_fallback<'tcx>( span, })) } else if let Node::AnonConst(_) = node { - match tcx.hir().get(tcx.hir().parent_id(id)) { + match tcx.hir_node(tcx.hir().parent_id(id)) { Node::Ty(&hir::Ty { kind: hir::TyKind::Typeof(ref anon_const), .. }) if anon_const.hir_id == id => { @@ -243,7 +239,7 @@ fn typeck_with_fallback<'tcx>( // Gather locals in statics (because of block expressions). GatherLocalsVisitor::new(&fcx).visit_body(body); - fcx.check_expr_coercible_to_type(&body.value, expected_type, None); + fcx.check_expr_coercible_to_type(body.value, expected_type, None); fcx.write_ty(id, expected_type); }; @@ -287,8 +283,6 @@ fn typeck_with_fallback<'tcx>( fcx.check_asms(); - fcx.infcx.skip_region_resolution(); - let typeck_results = fcx.resolve_type_vars_in_body(body); // Consistency check our TypeckResults instance can hold all ItemLocalIds @@ -419,32 +413,32 @@ enum TupleArgumentsFlag { } fn fatally_break_rust(tcx: TyCtxt<'_>) { - let handler = tcx.sess.diagnostic(); - handler.span_bug_no_panic( + let dcx = tcx.sess.dcx(); + dcx.span_bug_no_panic( MultiSpan::new(), "It looks like you're trying to break rust; would you like some ICE?", ); - handler.note_without_error("the compiler expectedly panicked. this is a feature."); - handler.note_without_error( + dcx.note("the compiler expectedly panicked. this is a feature."); + dcx.note( "we would appreciate a joke overview: \ https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675", ); - handler.note_without_error(format!( - "rustc {} running on {}", - tcx.sess.cfg_version, - config::host_triple(), - )); + dcx.note(format!("rustc {} running on {}", tcx.sess.cfg_version, config::host_triple(),)); if let Some((flags, excluded_cargo_defaults)) = rustc_session::utils::extra_compiler_flags() { - handler.note_without_error(format!("compiler flags: {}", flags.join(" "))); + dcx.note(format!("compiler flags: {}", flags.join(" "))); if excluded_cargo_defaults { - handler.note_without_error("some of the compiler flags provided by cargo are hidden"); + dcx.note("some of the compiler flags provided by cargo are hidden"); } } } +/// `expected` here is the expected number of explicit generic arguments on the trait. fn has_expected_num_generic_args(tcx: TyCtxt<'_>, trait_did: DefId, expected: usize) -> bool { let generics = tcx.generics_of(trait_did); - generics.count() == expected + if generics.has_self { 1 } else { 0 } + generics.count() + == expected + + if generics.has_self { 1 } else { 0 } + + if generics.host_effect_index.is_some() { 1 } else { 0 } } pub fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs index 337d12b2d..ebb15e072 100644 --- a/compiler/rustc_hir_typeck/src/mem_categorization.rs +++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs @@ -66,25 +66,18 @@ use rustc_trait_selection::infer::InferCtxtExt; pub(crate) trait HirNode { fn hir_id(&self) -> hir::HirId; - fn span(&self) -> Span; } impl HirNode for hir::Expr<'_> { fn hir_id(&self) -> hir::HirId { self.hir_id } - fn span(&self) -> Span { - self.span - } } impl HirNode for hir::Pat<'_> { fn hir_id(&self) -> hir::HirId { self.hir_id } - fn span(&self) -> Span { - self.span - } } #[derive(Clone)] @@ -304,7 +297,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { ) -> McResult<PlaceWithHirId<'tcx>> { let expr_ty = self.expr_ty(expr)?; match expr.kind { - hir::ExprKind::Unary(hir::UnOp::Deref, ref e_base) => { + hir::ExprKind::Unary(hir::UnOp::Deref, e_base) => { if self.typeck_results.is_method_call(expr) { self.cat_overloaded_place(expr, e_base) } else { @@ -313,7 +306,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { } } - hir::ExprKind::Field(ref base, _) => { + hir::ExprKind::Field(base, _) => { let base = self.cat_expr(base)?; debug!(?base); @@ -332,7 +325,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { )) } - hir::ExprKind::Index(ref base, _, _) => { + hir::ExprKind::Index(base, _, _) => { if self.typeck_results.is_method_call(expr) { // If this is an index implemented by a method call, then it // will include an implicit deref of the result. @@ -351,7 +344,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { self.cat_res(expr.hir_id, expr.span, expr_ty, res) } - hir::ExprKind::Type(ref e, _) => self.cat_expr(e), + hir::ExprKind::Type(e, _) => self.cat_expr(e), hir::ExprKind::AddrOf(..) | hir::ExprKind::Call(..) @@ -547,7 +540,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { let ty::Adt(adt_def, _) = ty.kind() else { self.tcx() .sess - .delay_span_bug(span, "struct or tuple struct pattern not applied to an ADT"); + .span_delayed_bug(span, "struct or tuple struct pattern not applied to an ADT"); return Err(()); }; @@ -582,7 +575,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { _ => { self.tcx() .sess - .delay_span_bug(span, "struct or tuple struct pattern not applied to an ADT"); + .span_delayed_bug(span, "struct or tuple struct pattern not applied to an ADT"); Err(()) } } @@ -595,7 +588,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { match ty.kind() { ty::Tuple(args) => Ok(args.len()), _ => { - self.tcx().sess.delay_span_bug(span, "tuple pattern not applied to a tuple"); + self.tcx().sess.span_delayed_bug(span, "tuple pattern not applied to a tuple"); Err(()) } } @@ -728,11 +721,11 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { } } - PatKind::Binding(.., Some(ref subpat)) => { + PatKind::Binding(.., Some(subpat)) => { self.cat_pattern_(place_with_id, subpat, op)?; } - PatKind::Box(ref subpat) | PatKind::Ref(ref subpat, _) => { + PatKind::Box(subpat) | PatKind::Ref(subpat, _) => { // box p1, &p1, &mut p1. we can ignore the mutability of // PatKind::Ref since that information is already contained // in the type. @@ -754,7 +747,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { for before_pat in before { self.cat_pattern_(elt_place.clone(), before_pat, op)?; } - if let Some(ref slice_pat) = *slice { + if let Some(slice_pat) = *slice { let slice_pat_ty = self.pat_ty_adjusted(slice_pat)?; let slice_place = self.cat_projection( pat, @@ -773,6 +766,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { | PatKind::Binding(.., None) | PatKind::Lit(..) | PatKind::Range(..) + | PatKind::Never | PatKind::Wild => { // always ok } diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 7c73f6a89..b2ead3cd4 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -93,16 +93,16 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { segment: &hir::PathSegment<'_>, ) -> ConfirmResult<'tcx> { // Adjust the self expression the user provided and obtain the adjusted type. - let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick); + let self_ty = self.adjust_self_ty(unadjusted_self_ty, pick); // Create substitutions for the method's type parameters. - let rcvr_args = self.fresh_receiver_args(self_ty, &pick); - let all_args = self.instantiate_method_args(&pick, segment, rcvr_args); + let rcvr_args = self.fresh_receiver_args(self_ty, pick); + let all_args = self.instantiate_method_args(pick, segment, rcvr_args); debug!("rcvr_args={rcvr_args:?}, all_args={all_args:?}"); // Create the final signature for the method, replacing late-bound regions. - let (method_sig, method_predicates) = self.instantiate_method_sig(&pick, all_args); + let (method_sig, method_predicates) = self.instantiate_method_sig(pick, all_args); // If there is a `Self: Sized` bound and `Self` is a trait object, it is possible that // something which derefs to `Self` actually implements the trait and the caller @@ -129,14 +129,14 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { "confirm: self_ty={:?} method_sig_rcvr={:?} method_sig={:?} method_predicates={:?}", self_ty, method_sig_rcvr, method_sig, method_predicates ); - self.unify_receivers(self_ty, method_sig_rcvr, &pick, all_args); + self.unify_receivers(self_ty, method_sig_rcvr, pick, all_args); let (method_sig, method_predicates) = self.normalize(self.span, (method_sig, method_predicates)); let method_sig = ty::Binder::dummy(method_sig); // Make sure nobody calls `drop()` explicitly. - self.enforce_illegal_method_limitations(&pick); + self.enforce_illegal_method_limitations(pick); // Add any trait/regions obligations specified on the method's type parameters. // We won't add these if we encountered an illegal sized bound, so that we can use @@ -415,7 +415,9 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { ) .into() } - _ => unreachable!(), + (kind, arg) => { + bug!("mismatched method arg kind {kind:?} in turbofish: {arg:?}") + } } } diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index d69d2529b..f820835ac 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -385,7 +385,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // type parameters or early-bound regions. let tcx = self.tcx; let Some(method_item) = self.associated_value(trait_def_id, m_name) else { - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( obligation.cause.span, "operator trait does not have corresponding operator method", ); @@ -393,7 +393,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if method_item.kind != ty::AssocKind::Fn { - self.tcx.sess.delay_span_bug(tcx.def_span(method_item.def_id), "not a method"); + self.tcx.sess.span_delayed_bug(tcx.def_span(method_item.def_id), "not a method"); return None; } diff --git a/compiler/rustc_hir_typeck/src/method/prelude2021.rs b/compiler/rustc_hir_typeck/src/method/prelude2021.rs index 3f1dca5b1..43d258de6 100644 --- a/compiler/rustc_hir_typeck/src/method/prelude2021.rs +++ b/compiler/rustc_hir_typeck/src/method/prelude2021.rs @@ -122,8 +122,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("disambiguate the method call with `({self_adjusted})`",), ); } - - lint }, ); } else { @@ -187,8 +185,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ), ); } - - lint }, ); } @@ -307,8 +303,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("<{} as {}>::{}", self_ty_name, trait_name, method_name.name,), Applicability::MachineApplicable, ); - - lint }, ); } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 74f469cb3..fe2d43a3c 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -445,7 +445,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { scope_expr_id, span, "type annotations needed", - |lint| lint, + |_| {}, ); } } else { @@ -619,7 +619,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { fn push_candidate(&mut self, candidate: Candidate<'tcx>, is_inherent: bool) { let is_accessible = if let Some(name) = self.method_name { let item = candidate.item; - let hir_id = self.tcx.hir().local_def_id_to_hir_id(self.body_id); + let hir_id = self.tcx.local_def_id_to_hir_id(self.body_id); let def_scope = self.tcx.adjust_ident_and_get_scope(name, item.container_id(self.tcx), hir_id).1; item.visibility(self.tcx).is_accessible_from(def_scope, self.tcx) @@ -801,15 +801,15 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // a `&self` method will wind up with an argument type like `&dyn Trait`. let trait_ref = principal.with_self_ty(self.tcx, self_ty); self.elaborate_bounds(iter::once(trait_ref), |this, new_trait_ref, item| { - if new_trait_ref.has_non_region_late_bound() { - this.tcx.sess.delay_span_bug( + if new_trait_ref.has_non_region_bound_vars() { + this.tcx.sess.span_delayed_bug( this.span, "tried to select method from HRTB with non-lifetime bound vars", ); return; } - let new_trait_ref = this.erase_late_bound_regions(new_trait_ref); + let new_trait_ref = this.instantiate_bound_regions_with_erased(new_trait_ref); let (xform_self_ty, xform_ret_ty) = this.xform_self_ty(item, new_trait_ref.self_ty(), new_trait_ref.args); @@ -853,7 +853,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.elaborate_bounds(bounds, |this, poly_trait_ref, item| { let trait_ref = this.instantiate_binder_with_fresh_vars( this.span, - infer::LateBoundRegionConversionTime::FnCall, + infer::BoundRegionConversionTime::FnCall, poly_trait_ref, ); @@ -971,7 +971,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } else { let new_trait_ref = self.instantiate_binder_with_fresh_vars( self.span, - infer::LateBoundRegionConversionTime::FnCall, + infer::BoundRegionConversionTime::FnCall, bound_trait_ref, ); @@ -1135,7 +1135,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { .fcx .probe_instantiate_query_response( self.span, - &self.orig_steps_var_values, + self.orig_steps_var_values, &step.self_ty, ) .unwrap_or_else(|_| { @@ -1427,8 +1427,6 @@ impl<'tcx> Pick<'tcx> { )); } } - - lint }, ); } @@ -1509,7 +1507,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // match as well (or at least may match, sometimes we // don't have enough information to fully evaluate). match probe.kind { - InherentImplCandidate(ref args, ref ref_obligations) => { + InherentImplCandidate(args, ref ref_obligations) => { // `xform_ret_ty` hasn't been normalized yet, only `xform_self_ty`, // see the reasons mentioned in the comments in `assemble_inherent_impl_probe` // for why this is necessary @@ -1548,9 +1546,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { ); let candidate_obligations = impl_obligations - .chain(norm_obligations.into_iter()) + .chain(norm_obligations) .chain(ref_obligations.iter().cloned()) - .chain(normalization_obligations.into_iter()); + .chain(normalization_obligations); // Evaluate those obligations to see if they might possibly hold. for o in candidate_obligations { @@ -1799,9 +1797,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { .iter() .find(|cand| self.matches_by_doc_alias(cand.def_id)) .map(|cand| cand.name) - }) - .unwrap(); - Ok(applicable_close_candidates.into_iter().find(|method| method.name == best_name)) + }); + Ok(best_name.and_then(|best_name| { + applicable_close_candidates.into_iter().find(|method| method.name == best_name) + })) } }) } @@ -1861,7 +1860,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // method yet. So create fresh variables here for those too, // if there are any. let generics = self.tcx.generics_of(method); - assert_eq!(args.len(), generics.parent_count as usize); + assert_eq!(args.len(), generics.parent_count); let xform_fn_sig = if generics.params.is_empty() { fn_sig.instantiate(self.tcx, args) @@ -1885,7 +1884,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { fn_sig.instantiate(self.tcx, args) }; - self.erase_late_bound_regions(xform_fn_sig) + self.instantiate_bound_regions_with_erased(xform_fn_sig) } /// Gets the type of an impl and generate substitutions with inference vars. @@ -1897,7 +1896,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } /// Replaces late-bound-regions bound by `value` with `'static` using - /// `ty::erase_late_bound_regions`. + /// `ty::instantiate_bound_regions_with_erased`. /// /// This is only a reasonable thing to do during the *probe* phase, not the *confirm* phase, of /// method matching. It is reasonable during the probe phase because we don't consider region @@ -1914,11 +1913,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { /// region got replaced with the same variable, which requires a bit more coordination /// and/or tracking the substitution and /// so forth. - fn erase_late_bound_regions<T>(&self, value: ty::Binder<'tcx, T>) -> T + fn instantiate_bound_regions_with_erased<T>(&self, value: ty::Binder<'tcx, T>) -> T where T: TypeFoldable<TyCtxt<'tcx>>, { - self.tcx.erase_late_bound_regions(value) + self.tcx.instantiate_bound_regions_with_erased(value) } /// Determine if the given associated item type is relevant in the current context. @@ -1939,7 +1938,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let Some(local_def_id) = def_id.as_local() else { return false; }; - let hir_id = self.fcx.tcx.hir().local_def_id_to_hir_id(local_def_id); + let hir_id = self.fcx.tcx.local_def_id_to_hir_id(local_def_id); let attrs = self.fcx.tcx.hir().attrs(hir_id); for attr in attrs { let sym::doc = attr.name_or_empty() else { diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index bd40e6c10..7595f21d9 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1,6 +1,8 @@ //! Give useful errors and suggestions to users when an item can't be //! found or is otherwise invalid. +// ignore-tidy-filelength + use crate::errors; use crate::errors::{CandidateTraitNote, NoAssociatedItem}; use crate::Expectation; @@ -228,7 +230,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = kind && let hir::def::Res::Local(hir_id) = path.res - && let Some(hir::Node::Pat(b)) = self.tcx.hir().find(hir_id) + && let Some(hir::Node::Pat(b)) = self.tcx.opt_hir_node(hir_id) && let Some(hir::Node::Param(p)) = self.tcx.hir().find_parent(b.hir_id) && let Some(node) = self.tcx.hir().find_parent(p.hir_id) && let Some(decl) = node.fn_decl() @@ -260,7 +262,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rcvr_ty: Ty<'tcx>, rcvr_expr: &hir::Expr<'tcx>, ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { - let (ty_str, _ty_file) = self.tcx.short_ty_string(rcvr_ty); + let mut file = None; + let ty_str = self.tcx.short_ty_string(rcvr_ty, &mut file); let mut err = struct_span_err!( self.tcx.sess, rcvr_expr.span, @@ -278,6 +281,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "a writer is needed before this format string", ); }; + if let Some(file) = file { + err.note(format!("the full type name has been written to '{}'", file.display())); + } err } @@ -297,11 +303,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mode = no_match_data.mode; let tcx = self.tcx; let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty); - let ((mut ty_str, ty_file), short_ty_str) = + let mut ty_file = None; + let (mut ty_str, short_ty_str) = if trait_missing_method && let ty::Dynamic(predicates, _, _) = rcvr_ty.kind() { - ((predicates.to_string(), None), with_forced_trimmed_paths!(predicates.to_string())) + (predicates.to_string(), with_forced_trimmed_paths!(predicates.to_string())) } else { - (tcx.short_ty_string(rcvr_ty), with_forced_trimmed_paths!(rcvr_ty.to_string())) + ( + tcx.short_ty_string(rcvr_ty, &mut ty_file), + with_forced_trimmed_paths!(rcvr_ty.to_string()), + ) }; let is_method = mode == Mode::MethodCall; let unsatisfied_predicates = &no_match_data.unsatisfied_predicates; @@ -369,25 +379,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx.is_diagnostic_item(sym::write_macro, def_id) || tcx.is_diagnostic_item(sym::writeln_macro, def_id) }) && item_name.name == Symbol::intern("write_fmt"); - let mut err = - if is_write && let SelfSource::MethodCall(rcvr_expr) = source - { - self.suggest_missing_writer(rcvr_ty, rcvr_expr) - } else { - tcx.sess.create_err(NoAssociatedItem { - span, - item_kind, - item_name, - ty_prefix: if trait_missing_method { - // FIXME(mu001999) E0599 maybe not suitable here because it is for types - Cow::from("trait") - } else { - rcvr_ty.prefix_string(self.tcx) - }, - ty_str: ty_str_reported, - trait_missing_method, - }) - }; + let mut err = if is_write && let SelfSource::MethodCall(rcvr_expr) = source { + self.suggest_missing_writer(rcvr_ty, rcvr_expr) + } else { + tcx.sess.create_err(NoAssociatedItem { + span, + item_kind, + item_name, + ty_prefix: if trait_missing_method { + // FIXME(mu001999) E0599 maybe not suitable here because it is for types + Cow::from("trait") + } else { + rcvr_ty.prefix_string(self.tcx) + }, + ty_str: ty_str_reported, + trait_missing_method, + }) + }; if tcx.sess.source_map().is_multiline(sugg_span) { err.span_label(sugg_span.with_hi(span.lo()), ""); } @@ -484,7 +492,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.note_internal_mutation_in_method( &mut err, rcvr_expr, - expected.to_option(&self), + expected.to_option(self), rcvr_ty, ); } @@ -509,7 +517,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if static_candidates.len() == 1 { self.suggest_associated_call_syntax( &mut err, - &static_candidates, + static_candidates, rcvr_ty, source, item_name, @@ -605,16 +613,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let (ty::Param(_), ty::PredicateKind::Clause(ty::ClauseKind::Trait(p))) = (self_ty.kind(), parent_pred.kind().skip_binder()) { - let hir = self.tcx.hir(); let node = match p.trait_ref.self_ty().kind() { ty::Param(_) => { // Account for `fn` items like in `issue-35677.rs` to // suggest restricting its type params. - Some(hir.get_by_def_id(self.body_id)) - } - ty::Adt(def, _) => { - def.did().as_local().map(|def_id| hir.get_by_def_id(def_id)) + Some(self.tcx.hir_node_by_def_id(self.body_id)) } + ty::Adt(def, _) => def + .did() + .as_local() + .map(|def_id| self.tcx.hir_node_by_def_id(def_id)), _ => None, }; if let Some(hir::Node::Item(hir::Item { kind, .. })) = node @@ -813,7 +821,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: item_span, .. })) => { - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( *item_span, "auto trait is invoked with no method error, but no error reported?", ); @@ -969,7 +977,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "the following trait bounds were not satisfied:\n{bound_list}" )); } - self.suggest_derive(&mut err, &unsatisfied_predicates); + self.suggest_derive(&mut err, unsatisfied_predicates); unsatisfied_bounds = true; } @@ -1170,8 +1178,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { args.map(|args| args.len() + 1), source, no_match_data.out_of_scope_traits.clone(), - &unsatisfied_predicates, - &static_candidates, + unsatisfied_predicates, + static_candidates, unsatisfied_bounds, expected.only_has_type(self), trait_missing_method, @@ -1240,20 +1248,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } // If an appropriate error source is not found, check method chain for possible candiates - if unsatisfied_predicates.is_empty() && let Mode::MethodCall = mode && let SelfSource::MethodCall(mut source_expr) = source { + if unsatisfied_predicates.is_empty() + && let Mode::MethodCall = mode + && let SelfSource::MethodCall(mut source_expr) = source + { let mut stack_methods = vec![]; while let hir::ExprKind::MethodCall(_path_segment, rcvr_expr, _args, method_span) = - source_expr.kind + source_expr.kind { - // Pop the matching receiver, to align on it's notional span - if let Some(prev_match) = stack_methods.pop() { - err.span_label(method_span, format!("{item_kind} `{item_name}` is available on `{prev_match}`")); + // Pop the matching receiver, to align on it's notional span + if let Some(prev_match) = stack_methods.pop() { + err.span_label( + method_span, + format!("{item_kind} `{item_name}` is available on `{prev_match}`"), + ); } let rcvr_ty = self.resolve_vars_if_possible( self.typeck_results .borrow() .expr_ty_adjusted_opt(rcvr_expr) - .unwrap_or(Ty::new_misc_error(self.tcx)),); + .unwrap_or(Ty::new_misc_error(self.tcx)), + ); for _matched_method in self.probe_for_name_many( Mode::MethodCall, @@ -1262,15 +1277,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { IsSuggestion(true), rcvr_ty, source_expr.hir_id, - ProbeScope::TraitsInScope,) { - // found a match, push to stack - stack_methods.push(rcvr_ty); + ProbeScope::TraitsInScope, + ) { + // found a match, push to stack + stack_methods.push(rcvr_ty); } source_expr = rcvr_expr; } // If there is a match at the start of the chain, add a label for it too! if let Some(prev_match) = stack_methods.pop() { - err.span_label(source_expr.span, format!("{item_kind} `{item_name}` is available on `{prev_match}`")); + err.span_label( + source_expr.span, + format!("{item_kind} `{item_name}` is available on `{prev_match}`"), + ); } } self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected); @@ -1357,10 +1376,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err, self_source, args, - trait_ref.instantiate( - self.tcx, - self.fresh_args_for_item(sugg_span, impl_did) - ).with_self_ty(self.tcx, rcvr_ty), + trait_ref + .instantiate( + self.tcx, + self.fresh_args_for_item(sugg_span, impl_did), + ) + .with_self_ty(self.tcx, rcvr_ty), idx, sugg_span, item, @@ -1397,8 +1418,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::TraitRef::new( self.tcx, trait_did, - self.fresh_args_for_item(sugg_span, trait_did) - ).with_self_ty(self.tcx, rcvr_ty), + self.fresh_args_for_item(sugg_span, trait_did), + ) + .with_self_ty(self.tcx, rcvr_ty), idx, sugg_span, item, @@ -1409,7 +1431,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } - if !suggs.is_empty() && let Some(span) = sugg_span { + if !suggs.is_empty() + && let Some(span) = sugg_span + { + suggs.sort(); err.span_suggestions( span.with_hi(item_name.span.lo()), "use fully-qualified syntax to disambiguate", @@ -1438,7 +1463,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .filter_map(|item| { // Only assoc fns that return `Self`, `Option<Self>` or `Result<Self, _>`. let ret_ty = self.tcx.fn_sig(item.def_id).skip_binder().output(); - let ret_ty = self.tcx.erase_late_bound_regions(ret_ty); + let ret_ty = self.tcx.instantiate_bound_regions_with_erased(ret_ty); let ty::Adt(def, args) = ret_ty.kind() else { return None; }; @@ -1574,10 +1599,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let sig = self.tcx.fn_sig(assoc.def_id).instantiate_identity(); sig.inputs().skip_binder().get(0).and_then(|first| { - if first.peel_refs() == rcvr_ty.peel_refs() { - None - } else { + let impl_ty = self.tcx.type_of(*impl_did).instantiate_identity(); + // if the type of first arg is the same as the current impl type, we should take the first arg into assoc function + if first.peel_refs() == impl_ty { Some(first.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str())) + } else { + None } }) } else { @@ -1585,39 +1612,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let mut applicability = Applicability::MachineApplicable; let args = if let SelfSource::MethodCall(receiver) = source - && let Some(args) = args - { - // The first arg is the same kind as the receiver - let explicit_args = if first_arg.is_some() { - std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>() - } else { - // There is no `Self` kind to infer the arguments from - if has_unsuggestable_args { - applicability = Applicability::HasPlaceholders; - } - args.iter().collect() - }; - format!( - "({}{})", - first_arg.unwrap_or(""), - explicit_args - .iter() - .map(|arg| self - .tcx - .sess - .source_map() - .span_to_snippet(arg.span) - .unwrap_or_else(|_| { - applicability = Applicability::HasPlaceholders; - "_".to_owned() - })) - .collect::<Vec<_>>() - .join(", "), - ) + && let Some(args) = args + { + // The first arg is the same kind as the receiver + let explicit_args = if first_arg.is_some() { + std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>() } else { - applicability = Applicability::HasPlaceholders; - "(...)".to_owned() + // There is no `Self` kind to infer the arguments from + if has_unsuggestable_args { + applicability = Applicability::HasPlaceholders; + } + args.iter().collect() }; + format!( + "({}{})", + first_arg.unwrap_or(""), + explicit_args + .iter() + .map(|arg| self + .tcx + .sess + .source_map() + .span_to_snippet(arg.span) + .unwrap_or_else(|_| { + applicability = Applicability::HasPlaceholders; + "_".to_owned() + })) + .collect::<Vec<_>>() + .join(", "), + ) + } else { + applicability = Applicability::HasPlaceholders; + "(...)".to_owned() + }; err.span_suggestion( sugg_span, "use associated function syntax instead", @@ -1705,7 +1732,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for (_, parent) in tcx.hir().parent_iter(expr.hir_id).take(5) { if let Node::Expr(parent_expr) = parent { let lang_item = match parent_expr.kind { - ExprKind::Struct(ref qpath, _, _) => match **qpath { + ExprKind::Struct(qpath, _, _) => match *qpath { QPath::LangItem(LangItem::Range, ..) => Some(LangItem::Range), QPath::LangItem(LangItem::RangeTo, ..) => Some(LangItem::RangeTo), QPath::LangItem(LangItem::RangeToInclusive, ..) => { @@ -1713,7 +1740,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } _ => None, }, - ExprKind::Call(ref func, _) => match func.kind { + ExprKind::Call(func, _) => match func.kind { // `..=` desugars into `::std::ops::RangeInclusive::new(...)`. ExprKind::Path(QPath::LangItem(LangItem::RangeInclusiveNew, ..)) => { Some(LangItem::RangeInclusiveStruct) @@ -1732,7 +1759,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { eps.len() > 0 && eps.last().is_some_and(|ep| ep.span.contains(span)) } // `..=` desugars into `::std::ops::RangeInclusive::new(...)`. - hir::ExprKind::Call(ref func, ..) => func.span.contains(span), + hir::ExprKind::Call(func, ..) => func.span.contains(span), _ => false, }; @@ -1826,7 +1853,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); let concrete_type = if actual.is_integral() { "i32" } else { "f32" }; match expr.kind { - ExprKind::Lit(ref lit) => { + ExprKind::Lit(lit) => { // numeric literal let snippet = tcx .sess @@ -1902,7 +1929,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; }; let Some(mut diag) = - self.tcx.sess.diagnostic().steal_diagnostic(seg1.ident.span, StashKey::CallAssocMethod) + self.tcx.sess.dcx().steal_diagnostic(seg1.ident.span, StashKey::CallAssocMethod) else { return; }; @@ -1930,10 +1957,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let mut visitor = LetVisitor { result: None, ident_name: seg1.ident.name }; - visitor.visit_body(&body); + visitor.visit_body(body); let parent = self.tcx.hir().parent_id(seg1.hir_id); - if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent) + if let Some(Node::Expr(call_expr)) = self.tcx.opt_hir_node(parent) && let Some(expr) = visitor.result && let Some(self_ty) = self.node_ty_opt(expr.hir_id) { @@ -1967,69 +1994,73 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item_name: Ident, return_type: Option<Ty<'tcx>>, ) { - if let SelfSource::MethodCall(expr) = source - && let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id() - && let Some((fields, args)) = - self.get_field_candidates_considering_privacy(span, actual, mod_id) - { - let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id)); + if let SelfSource::MethodCall(expr) = source { + let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id(); + for (fields, args) in + self.get_field_candidates_considering_privacy(span, actual, mod_id, expr.hir_id) + { + let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id)); - let lang_items = self.tcx.lang_items(); - let never_mention_traits = [ - lang_items.clone_trait(), - lang_items.deref_trait(), - lang_items.deref_mut_trait(), - self.tcx.get_diagnostic_item(sym::AsRef), - self.tcx.get_diagnostic_item(sym::AsMut), - self.tcx.get_diagnostic_item(sym::Borrow), - self.tcx.get_diagnostic_item(sym::BorrowMut), - ]; - let candidate_fields: Vec<_> = fields - .filter_map(|candidate_field| { - self.check_for_nested_field_satisfying( - span, - &|_, field_ty| { - self.lookup_probe_for_diagnostic( - item_name, - field_ty, - call_expr, - ProbeScope::TraitsInScope, - return_type, - ) - .is_ok_and(|pick| { - !never_mention_traits - .iter() - .flatten() - .any(|def_id| self.tcx.parent(pick.item.def_id) == *def_id) - }) - }, - candidate_field, - args, - vec![], - mod_id, - ) - }) - .map(|field_path| { - field_path - .iter() - .map(|id| id.name.to_ident_string()) - .collect::<Vec<String>>() - .join(".") - }) - .collect(); + let lang_items = self.tcx.lang_items(); + let never_mention_traits = [ + lang_items.clone_trait(), + lang_items.deref_trait(), + lang_items.deref_mut_trait(), + self.tcx.get_diagnostic_item(sym::AsRef), + self.tcx.get_diagnostic_item(sym::AsMut), + self.tcx.get_diagnostic_item(sym::Borrow), + self.tcx.get_diagnostic_item(sym::BorrowMut), + ]; + let mut candidate_fields: Vec<_> = fields + .into_iter() + .filter_map(|candidate_field| { + self.check_for_nested_field_satisfying( + span, + &|_, field_ty| { + self.lookup_probe_for_diagnostic( + item_name, + field_ty, + call_expr, + ProbeScope::TraitsInScope, + return_type, + ) + .is_ok_and(|pick| { + !never_mention_traits + .iter() + .flatten() + .any(|def_id| self.tcx.parent(pick.item.def_id) == *def_id) + }) + }, + candidate_field, + args, + vec![], + mod_id, + expr.hir_id, + ) + }) + .map(|field_path| { + field_path + .iter() + .map(|id| id.name.to_ident_string()) + .collect::<Vec<String>>() + .join(".") + }) + .collect(); + candidate_fields.sort(); - let len = candidate_fields.len(); - if len > 0 { - err.span_suggestions( - item_name.span.shrink_to_lo(), - format!( - "{} of the expressions' fields {} a method of the same name", - if len > 1 { "some" } else { "one" }, - if len > 1 { "have" } else { "has" }, - ), - candidate_fields.iter().map(|path| format!("{path}.")), - Applicability::MaybeIncorrect, - ); + let len = candidate_fields.len(); + if len > 0 { + err.span_suggestions( + item_name.span.shrink_to_lo(), + format!( + "{} of the expressions' fields {} a method of the same name", + if len > 1 { "some" } else { "one" }, + if len > 1 { "have" } else { "has" }, + ), + candidate_fields.iter().map(|path| format!("{path}.")), + Applicability::MaybeIncorrect, + ); + } } } } @@ -2267,7 +2298,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Adt(def, _) if def.did().is_local() => { spans.push_span_label( self.tcx.def_span(def.did()), - format!("must implement `{}`", pred.trait_ref.print_only_trait_path()), + format!("must implement `{}`", pred.trait_ref.print_trait_sugared()), ); } _ => {} @@ -2278,7 +2309,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let msg = if preds.len() == 1 { format!( "an implementation of `{}` might be missing for `{}`", - preds[0].trait_ref.print_only_trait_path(), + preds[0].trait_ref.print_trait_sugared(), preds[0].self_ty() ) } else { @@ -2548,13 +2579,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.item_name(*trait_did), ) }); + let mut sugg: Vec<_> = path_strings.chain(glob_path_strings).collect(); + sugg.sort(); - err.span_suggestions( - span, - msg, - path_strings.chain(glob_path_strings), - Applicability::MaybeIncorrect, - ); + err.span_suggestions(span, msg, sugg, Applicability::MaybeIncorrect); } fn suggest_valid_traits( @@ -2849,11 +2877,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let id = item .def_id .as_local() - .map(|def_id| self.tcx.hir().local_def_id_to_hir_id(def_id)); + .map(|def_id| self.tcx.hir_node_by_def_id(def_id)); if let Some(hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(fn_sig, method), .. - })) = id.map(|id| self.tcx.hir().get(id)) + })) = id { let self_first_arg = match method { hir::TraitFn::Required([ident, ..]) => { @@ -2939,11 +2967,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let type_param = generics.type_param(param, self.tcx); let hir = self.tcx.hir(); if let Some(def_id) = type_param.def_id.as_local() { - let id = hir.local_def_id_to_hir_id(def_id); + let id = self.tcx.local_def_id_to_hir_id(def_id); // Get the `hir::Param` to verify whether it already has any bounds. // We do this to avoid suggesting code that ends up as `T: FooBar`, // instead we suggest `T: Foo + Bar` in that case. - match hir.get(id) { + match self.tcx.hir_node(id) { Node::GenericParam(param) => { enum Introducer { Plus, @@ -3163,7 +3191,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let parent = self.tcx.hir().parent_id(expr.hir_id); - if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent) + if let Some(Node::Expr(call_expr)) = self.tcx.opt_hir_node(parent) && let hir::ExprKind::MethodCall( hir::PathSegment { ident: method_name, .. }, self_expr, @@ -3296,8 +3324,13 @@ fn print_disambiguation_help<'tcx>( { let def_kind_descr = tcx.def_kind_descr(item.kind.as_def_kind(), item.def_id); let item_name = item.ident(tcx); - let rcvr_ref = tcx.fn_sig(item.def_id).skip_binder().skip_binder().inputs()[0] - .ref_mutability() + let rcvr_ref = tcx + .fn_sig(item.def_id) + .skip_binder() + .skip_binder() + .inputs() + .get(0) + .and_then(|ty| ty.ref_mutability()) .map_or("", |mutbl| mutbl.ref_prefix_str()); let args = format!( "({}{})", diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index f40406c67..59b4b0032 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -4,7 +4,7 @@ use super::method::MethodCallee; use super::{has_expected_num_generic_args, FnCtxt}; use crate::Expectation; use rustc_ast as ast; -use rustc_errors::{self, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder}; +use rustc_errors::{struct_span_err, Applicability, Diagnostic, DiagnosticBuilder}; use rustc_hir as hir; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::traits::ObligationCauseCode; @@ -291,7 +291,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .push(autoref); } } - self.write_method_call(expr.hir_id, method); + self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method); method.sig.output() } @@ -781,7 +781,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { assert!(op.is_by_value()); match self.lookup_op_method(operand_ty, None, Op::Unary(op, ex.span), expected) { Ok(method) => { - self.write_method_call(ex.hir_id, method); + self.write_method_call_and_enforce_effects(ex.hir_id, ex.span, method); method.sig.output() } Err(errors) => { @@ -900,7 +900,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { self.tcx .sess - .delay_span_bug(span, "operator didn't have the right number of generic args"); + .span_delayed_bug(span, "operator didn't have the right number of generic args"); return Err(vec![]); } @@ -933,7 +933,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This path may do some inference, so make sure we've really // doomed compilation so as to not accidentally stabilize new // inference or something here... - self.tcx.sess.delay_span_bug(span, "this path really should be doomed..."); + self.tcx.sess.span_delayed_bug(span, "this path really should be doomed..."); // Guide inference for the RHS expression if it's provided -- // this will allow us to better error reporting, at the expense // of making some error messages a bit more specific. diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index b30f9b82f..56a420fab 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -178,6 +178,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = match pat.kind { PatKind::Wild => expected, + // FIXME(never_patterns): check the type is uninhabited. If that is not possible within + // typeck, do that in a later phase. + PatKind::Never => expected, PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti), PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti), PatKind::Binding(ba, var_id, _, sub) => { @@ -287,9 +290,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | PatKind::Box(_) | PatKind::Range(..) | PatKind::Slice(..) => AdjustMode::Peel, + // A never pattern behaves somewhat like a literal or unit variant. + PatKind::Never => AdjustMode::Peel, // String and byte-string literals result in types `&str` and `&[u8]` respectively. // All other literals result in non-reference types. - // As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo {}`. + // As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo" {}`. // // Call `resolve_vars_if_possible` here for inline const blocks. PatKind::Lit(lt) => match self.resolve_vars_if_possible(self.check_expr(lt)).kind() { @@ -715,7 +720,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let PatKind::Binding(_, _, binding, ..) = inner.kind { let binding_parent_id = tcx.hir().parent_id(pat.hir_id); - let binding_parent = tcx.hir().get(binding_parent_id); + let binding_parent = tcx.hir_node(binding_parent_id); debug!(?inner, ?pat, ?binding_parent); let mutability = match mutbl { @@ -743,6 +748,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | PatKind::Slice(..) => "binding", PatKind::Wild + | PatKind::Never | PatKind::Binding(..) | PatKind::Path(..) | PatKind::Box(..) @@ -872,7 +878,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.demand_eqtype_pat(pat.span, expected, pat_ty, pat_info.top_info); // Type-check subpatterns. - if self.check_struct_pat_fields(pat_ty, &pat, variant, fields, has_rest_pat, pat_info) { + if self.check_struct_pat_fields(pat_ty, pat, variant, fields, has_rest_pat, pat_info) { pat_ty } else { Ty::new_misc_error(self.tcx) @@ -893,7 +899,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (res, opt_ty, segments) = path_resolution; match res { Res::Err => { - let e = tcx.sess.delay_span_bug(qpath.span(), "`Res::Err` but no error emitted"); + let e = tcx.sess.span_delayed_bug(qpath.span(), "`Res::Err` but no error emitted"); self.set_tainted_by_errors(e); return Ty::new_error(tcx, e); } @@ -935,7 +941,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(_, _, body_id), .. - })) => match self.tcx.hir().get(body_id.hir_id) { + })) => match self.tcx.hir_node(body_id.hir_id) { hir::Node::Expr(expr) => { if hir::is_range_literal(expr) { let span = self.tcx.hir().span(body_id.hir_id); @@ -1062,7 +1068,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (res, opt_ty, segments) = self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span, None); if res == Res::Err { - let e = tcx.sess.delay_span_bug(pat.span, "`Res::Err` but no error emitted"); + let e = tcx.sess.span_delayed_bug(pat.span, "`Res::Err` but no error emitted"); self.set_tainted_by_errors(e); on_error(e); return Ty::new_error(tcx, e); @@ -1078,7 +1084,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let variant = match res { Res::Err => { - let e = tcx.sess.delay_span_bug(pat.span, "`Res::Err` but no error emitted"); + let e = tcx.sess.span_delayed_bug(pat.span, "`Res::Err` but no error emitted"); self.set_tainted_by_errors(e); on_error(e); return Ty::new_error(tcx, e); @@ -1814,7 +1820,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn joined_uncovered_patterns(witnesses: &[&Ident]) -> String { const LIMIT: usize = 3; match witnesses { - [] => bug!(), + [] => { + unreachable!( + "expected an uncovered pattern, otherwise why are we emitting an error?" + ) + } [witness] => format!("`{witness}`"), [head @ .., tail] if head.len() < LIMIT => { let head: Vec<_> = head.iter().map(<_>::to_string).collect(); @@ -1839,8 +1849,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lint.note(format!( "the pattern is of type `{ty}` and the `non_exhaustive_omitted_patterns` attribute was found", )); - - lint }); } diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index 406434e09..79e41ef92 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -38,7 +38,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span_bug!(expr.span, "input to deref is not a ref?"); } let ty = self.make_overloaded_place_return_type(method).ty; - self.write_method_call(expr.hir_id, method); + self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method); Some(ty) } @@ -179,7 +179,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } self.apply_adjustments(base_expr, adjustments); - self.write_method_call(expr.hir_id, method); + self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method); return Some((input_ty, self.make_overloaded_place_return_type(method).ty)); } @@ -283,9 +283,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Gather up expressions we want to munge. let mut exprs = vec![expr]; - while let hir::ExprKind::Field(ref expr, _) - | hir::ExprKind::Index(ref expr, _, _) - | hir::ExprKind::Unary(hir::UnOp::Deref, ref expr) = exprs.last().unwrap().kind + while let hir::ExprKind::Field(expr, _) + | hir::ExprKind::Index(expr, _, _) + | hir::ExprKind::Unary(hir::UnOp::Deref, expr) = exprs.last().unwrap().kind { exprs.push(expr); } @@ -404,7 +404,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None => return, }; debug!("convert_place_op_to_mutable: method={:?}", method); - self.write_method_call(expr.hir_id, method); + self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method); let ty::Ref(region, _, hir::Mutability::Mut) = method.sig.inputs()[0].kind() else { span_bug!(expr.span, "input to mutable place op is not a mut ref?"); diff --git a/compiler/rustc_hir_typeck/src/rvalue_scopes.rs b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs index 04d841023..b9b3ed53d 100644 --- a/compiler/rustc_hir_typeck/src/rvalue_scopes.rs +++ b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs @@ -69,12 +69,13 @@ pub fn resolve_rvalue_scopes<'a, 'tcx>( def_id: DefId, ) -> RvalueScopes { let tcx = &fcx.tcx; - let hir_map = tcx.hir(); let mut rvalue_scopes = RvalueScopes::new(); debug!("start resolving rvalue scopes, def_id={def_id:?}"); debug!("rvalue_scope: rvalue_candidates={:?}", scope_tree.rvalue_candidates); for (&hir_id, candidate) in &scope_tree.rvalue_candidates { - let Some(Node::Expr(expr)) = hir_map.find(hir_id) else { bug!("hir node does not exist") }; + let Some(Node::Expr(expr)) = tcx.opt_hir_node(hir_id) else { + bug!("hir node does not exist") + }; record_rvalue_scope(&mut rvalue_scopes, expr, candidate); } rvalue_scopes diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 17b81acd5..726ee02d7 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -221,7 +221,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.compute_min_captures(closure_def_id, capture_information, span); - let closure_hir_id = self.tcx.hir().local_def_id_to_hir_id(closure_def_id); + let closure_hir_id = self.tcx.local_def_id_to_hir_id(closure_def_id); if should_do_rust_2021_incompatible_closure_captures_analysis(self.tcx, closure_hir_id) { self.perform_2229_migration_analysis(closure_def_id, body_id, capture_clause, span); @@ -261,7 +261,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Unify the (as yet unbound) type variable in the closure // args with the kind we inferred. let closure_kind_ty = closure_args.as_closure().kind_ty(); - self.demand_eqtype(span, closure_kind.to_ty(self.tcx), closure_kind_ty); + self.demand_eqtype( + span, + Ty::from_closure_kind(self.tcx, closure_kind), + closure_kind_ty, + ); // If we have an origin, store it. if let Some(mut origin) = origin { @@ -315,11 +319,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let final_tupled_upvars_type = Ty::new_tup(self.tcx, &final_upvar_tys); self.demand_suptype(span, args.tupled_upvars_ty(), final_tupled_upvars_type); - let fake_reads = delegate - .fake_reads - .into_iter() - .map(|(place, cause, hir_id)| (place, cause, hir_id)) - .collect(); + let fake_reads = delegate.fake_reads; + self.typeck_results.borrow_mut().closure_fake_reads.insert(closure_def_id, fake_reads); if self.tcx.sess.opts.unstable_opts.profile_closures { @@ -679,53 +680,41 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `tests/ui/closures/2229_closure_analysis/preserve_field_drop_order.rs`. for (_, captures) in &mut root_var_min_capture_list { captures.sort_by(|capture1, capture2| { - for (p1, p2) in capture1.place.projections.iter().zip(&capture2.place.projections) { + fn is_field<'a>(p: &&Projection<'a>) -> bool { + match p.kind { + ProjectionKind::Field(_, _) => true, + ProjectionKind::Deref | ProjectionKind::OpaqueCast => false, + p @ (ProjectionKind::Subslice | ProjectionKind::Index) => { + bug!("ProjectionKind {:?} was unexpected", p) + } + } + } + + // Need to sort only by Field projections, so filter away others. + // A previous implementation considered other projection types too + // but that caused ICE #118144 + let capture1_field_projections = capture1.place.projections.iter().filter(is_field); + let capture2_field_projections = capture2.place.projections.iter().filter(is_field); + + for (p1, p2) in capture1_field_projections.zip(capture2_field_projections) { // We do not need to look at the `Projection.ty` fields here because at each // step of the iteration, the projections will either be the same and therefore // the types must be as well or the current projection will be different and // we will return the result of comparing the field indexes. match (p1.kind, p2.kind) { - // Paths are the same, continue to next loop. - (ProjectionKind::Deref, ProjectionKind::Deref) => {} - (ProjectionKind::OpaqueCast, ProjectionKind::OpaqueCast) => {} - (ProjectionKind::Field(i1, _), ProjectionKind::Field(i2, _)) - if i1 == i2 => {} - - // Fields are different, compare them. (ProjectionKind::Field(i1, _), ProjectionKind::Field(i2, _)) => { - return i1.cmp(&i2); + // Compare only if paths are different. + // Otherwise continue to the next iteration + if i1 != i2 { + return i1.cmp(&i2); + } } - - // We should have either a pair of `Deref`s or a pair of `Field`s. - // Anything else is a bug. - ( - l @ (ProjectionKind::Deref | ProjectionKind::Field(..)), - r @ (ProjectionKind::Deref | ProjectionKind::Field(..)), - ) => bug!( - "ProjectionKinds Deref and Field were mismatched: ({:?}, {:?})", - l, - r - ), - ( - l @ (ProjectionKind::Index - | ProjectionKind::Subslice - | ProjectionKind::Deref - | ProjectionKind::OpaqueCast - | ProjectionKind::Field(..)), - r @ (ProjectionKind::Index - | ProjectionKind::Subslice - | ProjectionKind::Deref - | ProjectionKind::OpaqueCast - | ProjectionKind::Field(..)), - ) => bug!( - "ProjectionKinds Index or Subslice were unexpected: ({:?}, {:?})", - l, - r - ), + // Given the filter above, this arm should never be hit + (l, r) => bug!("ProjectionKinds {:?} or {:?} were unexpected", l, r), } } - self.tcx.sess.delay_span_bug( + self.tcx.sess.span_delayed_bug( closure_span, format!( "two identical projections: ({:?}, {:?})", @@ -763,7 +752,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (migration_string, migrated_variables_concat) = migration_suggestion_for_2229(self.tcx, &need_migrations); - let closure_hir_id = self.tcx.hir().local_def_id_to_hir_id(closure_def_id); + let closure_hir_id = self.tcx.local_def_id_to_hir_id(closure_def_id); let closure_head_span = self.tcx.def_span(closure_def_id); self.tcx.struct_span_lint_hir( lint::builtin::RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES, @@ -853,7 +842,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Looks like a macro fragment. Try to find the real block. if let Some(hir::Node::Expr(&hir::Expr { kind: hir::ExprKind::Block(block, ..), .. - })) = self.tcx.hir().find(body_id.hir_id) { + })) = self.tcx.opt_hir_node(body_id.hir_id) { // If the body is a block (with `{..}`), we use the span of that block. // E.g. with a `|| $body` expanded from a `m!({ .. })`, we use `{ .. }`, and not `$body`. // Since we know it's a block, we know we can insert the `let _ = ..` without @@ -911,8 +900,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::HasPlaceholders ); } - - lint }, ); } @@ -1673,7 +1660,7 @@ fn apply_capture_kind_on_capture_ty<'tcx>( fn drop_location_span(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> Span { let owner_id = tcx.hir().get_enclosing_scope(hir_id).unwrap(); - let owner_node = tcx.hir().get(owner_id); + let owner_node = tcx.hir_node(owner_id); let owner_span = match owner_node { hir::Node::Item(item) => match item.kind { hir::ItemKind::Fn(_, _, owner_id) => tcx.hir().span(owner_id.hir_id), diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 896aacc69..d0cf4575c 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -8,12 +8,16 @@ use rustc_errors::{ErrorGuaranteed, StashKey}; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; +use rustc_middle::traits::ObligationCause; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion}; -use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; +use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::visit::TypeVisitableExt; +use rustc_middle::ty::TypeSuperFoldable; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_trait_selection::solve; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use std::mem; @@ -47,7 +51,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Type only exists for constants and statics, not functions. match self.tcx.hir().body_owner_kind(item_def_id) { hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_) => { - let item_hir_id = self.tcx.hir().local_def_id_to_hir_id(item_def_id); + let item_hir_id = self.tcx.local_def_id_to_hir_id(item_def_id); wbcx.visit_node_id(body.value.span, item_hir_id); } hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => (), @@ -218,7 +222,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // When encountering `return [0][0]` outside of a `fn` body we can encounter a base // that isn't in the type table. We assume more relevant errors have already been // emitted, so we delay an ICE if none have. (#64638) - self.tcx().sess.delay_span_bug(e.span, format!("bad base: `{base:?}`")); + self.tcx().sess.span_delayed_bug(e.span, format!("bad base: `{base:?}`")); } if let Some(base_ty) = base_ty && let ty::Ref(_, base_ty_inner, _) = *base_ty.kind() @@ -311,7 +315,9 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { // Nothing to write back here } hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => { - self.tcx().sess.delay_span_bug(p.span, format!("unexpected generic param: {p:?}")); + self.tcx() + .sess + .span_delayed_bug(p.span, format!("unexpected generic param: {p:?}")); } } } @@ -382,7 +388,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { .to_sorted(hcx, false) .into_iter() .map(|(&closure_def_id, data)| { - let closure_hir_id = self.tcx().hir().local_def_id_to_hir_id(closure_def_id); + let closure_hir_id = self.tcx().local_def_id_to_hir_id(closure_def_id); let data = self.resolve(*data, &closure_hir_id); (closure_def_id, data) }) @@ -407,7 +413,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { .map(|captured_place| { let locatable = captured_place.info.path_expr_id.unwrap_or_else(|| { - self.tcx().hir().local_def_id_to_hir_id(closure_def_id) + self.tcx().local_def_id_to_hir_id(closure_def_id) }); self.resolve(captured_place.clone(), &locatable) }) @@ -433,7 +439,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { let resolved_fake_reads = fake_reads .iter() .map(|(place, cause, hir_id)| { - let locatable = self.tcx().hir().local_def_id_to_hir_id(closure_def_id); + let locatable = self.tcx().local_def_id_to_hir_id(closure_def_id); let resolved_fake_read = self.resolve(place.clone(), &locatable); (resolved_fake_read, *cause, *hir_id) }) @@ -498,8 +504,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { if !errors_buffer.is_empty() { errors_buffer.sort_by_key(|diag| diag.span.primary_span()); - for mut diag in errors_buffer { - self.tcx().sess.diagnostic().emit_diagnostic(&mut diag); + for diag in errors_buffer { + self.tcx().sess.dcx().emit_diagnostic(diag); } } } @@ -693,24 +699,22 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } - fn resolve<T>(&mut self, x: T, span: &dyn Locatable) -> T + fn resolve<T>(&mut self, value: T, span: &dyn Locatable) -> T where T: TypeFoldable<TyCtxt<'tcx>>, { - let mut resolver = Resolver::new(self.fcx, span, self.body); - let x = x.fold_with(&mut resolver); - if cfg!(debug_assertions) && x.has_infer() { - span_bug!(span.to_span(self.fcx.tcx), "writeback: `{:?}` has inference variables", x); - } + let value = self.fcx.resolve_vars_if_possible(value); + let value = value.fold_with(&mut Resolver::new(self.fcx, span, self.body)); + assert!(!value.has_infer()); // We may have introduced e.g. `ty::Error`, if inference failed, make sure // to mark the `TypeckResults` as tainted in that case, so that downstream // users of the typeck results don't produce extra errors, or worse, ICEs. - if let Some(e) = resolver.replaced_with_error { - self.typeck_results.tainted_by_errors = Some(e); + if let Err(guar) = value.error_reported() { + self.typeck_results.tainted_by_errors = Some(guar); } - x + value } } @@ -730,15 +734,13 @@ impl Locatable for hir::HirId { } } -/// The Resolver. This is the type folding engine that detects -/// unresolved types and so forth. struct Resolver<'cx, 'tcx> { fcx: &'cx FnCtxt<'cx, 'tcx>, span: &'cx dyn Locatable, body: &'tcx hir::Body<'tcx>, - - /// Set to `Some` if any `Ty` or `ty::Const` had to be replaced with an `Error`. - replaced_with_error: Option<ErrorGuaranteed>, + /// Whether we should normalize using the new solver, disabled + /// both when using the old solver and when resolving predicates. + should_normalize: bool, } impl<'cx, 'tcx> Resolver<'cx, 'tcx> { @@ -747,7 +749,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { span: &'cx dyn Locatable, body: &'tcx hir::Body<'tcx>, ) -> Resolver<'cx, 'tcx> { - Resolver { fcx, span, body, replaced_with_error: None } + Resolver { fcx, span, body, should_normalize: fcx.next_trait_solver() } } fn report_error(&self, p: impl Into<ty::GenericArg<'tcx>>) -> ErrorGuaranteed { @@ -766,26 +768,42 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { .emit(), } } -} -struct EraseEarlyRegions<'tcx> { - tcx: TyCtxt<'tcx>, -} + fn handle_term<T>( + &mut self, + value: T, + outer_exclusive_binder: impl FnOnce(T) -> ty::DebruijnIndex, + new_err: impl Fn(TyCtxt<'tcx>, ErrorGuaranteed) -> T, + ) -> T + where + T: Into<ty::GenericArg<'tcx>> + TypeSuperFoldable<TyCtxt<'tcx>> + Copy, + { + let tcx = self.fcx.tcx; + // We must deeply normalize in the new solver, since later lints + // expect that types that show up in the typeck are fully + // normalized. + let value = if self.should_normalize { + let body_id = tcx.hir().body_owner_def_id(self.body.id()); + let cause = ObligationCause::misc(self.span.to_span(tcx), body_id); + let at = self.fcx.at(&cause, self.fcx.param_env); + let universes = vec![None; outer_exclusive_binder(value).as_usize()]; + solve::deeply_normalize_with_skipped_universes(at, value, universes).unwrap_or_else( + |errors| { + let guar = self.fcx.err_ctxt().report_fulfillment_errors(errors); + new_err(tcx, guar) + }, + ) + } else { + value + }; -impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EraseEarlyRegions<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { - self.tcx - } - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if ty.has_type_flags(ty::TypeFlags::HAS_FREE_REGIONS) { - ty.super_fold_with(self) + if value.has_non_region_infer() { + let guar = self.report_error(value); + new_err(tcx, guar) } else { - ty + tcx.fold_regions(value, |_, _| tcx.lifetimes.re_erased) } } - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - if r.is_late_bound() { r } else { self.tcx.lifetimes.re_erased } - } } impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> { @@ -793,56 +811,28 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> { self.fcx.tcx } - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match self.fcx.fully_resolve(t) { - Ok(t) if self.fcx.next_trait_solver() => { - // We must normalize erasing regions here, since later lints - // expect that types that show up in the typeck are fully - // normalized. - if let Ok(t) = self.fcx.tcx.try_normalize_erasing_regions(self.fcx.param_env, t) { - t - } else { - EraseEarlyRegions { tcx: self.fcx.tcx }.fold_ty(t) - } - } - Ok(t) => { - // Do not anonymize late-bound regions - // (e.g. keep `for<'a>` named `for<'a>`). - // This allows NLL to generate error messages that - // refer to the higher-ranked lifetime names written by the user. - EraseEarlyRegions { tcx: self.fcx.tcx }.fold_ty(t) - } - Err(_) => { - debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t); - let e = self.report_error(t); - self.replaced_with_error = Some(e); - Ty::new_error(self.fcx.tcx, e) - } - } - } - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - debug_assert!(!r.is_late_bound(), "Should not be resolving bound region."); + debug_assert!(!r.is_bound(), "Should not be resolving bound region."); self.fcx.tcx.lifetimes.re_erased } + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + self.handle_term(ty, Ty::outer_exclusive_binder, Ty::new_error) + } + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { - match self.fcx.fully_resolve(ct) { - Ok(ct) => self.fcx.tcx.erase_regions(ct), - Err(_) => { - debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct); - let e = self.report_error(ct); - self.replaced_with_error = Some(e); - ty::Const::new_error(self.fcx.tcx, e, ct.ty()) - } - } + self.handle_term(ct, ty::Const::outer_exclusive_binder, |tcx, guar| { + ty::Const::new_error(tcx, guar, ct.ty()) + }) } -} -/////////////////////////////////////////////////////////////////////////// -// During type check, we store promises with the result of trait -// lookup rather than the actual results (because the results are not -// necessarily available immediately). These routines unwind the -// promises. It is expected that we will have already reported any -// errors that may be encountered, so if the promises store an error, -// a dummy result is returned. + fn fold_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + // Do not normalize predicates in the new solver. The new solver is + // supposed to handle unnormalized predicates and incorrectly normalizing + // them can be unsound, e.g. for `WellFormed` predicates. + let prev = mem::replace(&mut self.should_normalize, false); + let predicate = predicate.super_fold_with(self); + self.should_normalize = prev; + predicate + } +} |