From d1b2d29528b7794b41e66fc2136e395a02f8529b Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 30 May 2024 05:59:35 +0200 Subject: Merging upstream version 1.73.0+dfsg1. Signed-off-by: Daniel Baumann --- compiler/rustc_hir_typeck/src/_match.rs | 74 ++--- compiler/rustc_hir_typeck/src/callee.rs | 121 ++++---- compiler/rustc_hir_typeck/src/cast.rs | 48 ++-- compiler/rustc_hir_typeck/src/check.rs | 4 +- compiler/rustc_hir_typeck/src/closure.rs | 52 ++-- compiler/rustc_hir_typeck/src/coercion.rs | 167 ++++++----- compiler/rustc_hir_typeck/src/demand.rs | 293 +++++++++++-------- compiler/rustc_hir_typeck/src/errors.rs | 40 +++ compiler/rustc_hir_typeck/src/expectation.rs | 9 +- compiler/rustc_hir_typeck/src/expr.rs | 171 +++++------ compiler/rustc_hir_typeck/src/expr_use_visitor.rs | 6 +- compiler/rustc_hir_typeck/src/fallback.rs | 32 ++- compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs | 159 +++++----- .../src/fn_ctxt/adjust_fulfillment_errors.rs | 129 +++++---- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 156 +++++----- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 10 +- .../rustc_hir_typeck/src/fn_ctxt/suggestions.rs | 320 ++++++++++++++------- compiler/rustc_hir_typeck/src/gather_locals.rs | 26 +- .../generator_interior/drop_ranges/cfg_build.rs | 10 +- .../src/generator_interior/drop_ranges/mod.rs | 14 +- .../drop_ranges/record_consumed_borrow.rs | 15 +- .../rustc_hir_typeck/src/generator_interior/mod.rs | 2 +- compiler/rustc_hir_typeck/src/inherited.rs | 6 +- compiler/rustc_hir_typeck/src/intrinsicck.rs | 17 +- compiler/rustc_hir_typeck/src/lib.rs | 21 +- .../rustc_hir_typeck/src/mem_categorization.rs | 93 +++--- compiler/rustc_hir_typeck/src/method/confirm.rs | 108 +++---- compiler/rustc_hir_typeck/src/method/mod.rs | 44 ++- .../rustc_hir_typeck/src/method/prelude2021.rs | 45 +-- compiler/rustc_hir_typeck/src/method/probe.rs | 89 +++--- compiler/rustc_hir_typeck/src/method/suggest.rs | 305 +++++++++++++------- compiler/rustc_hir_typeck/src/op.rs | 167 +++++++++-- compiler/rustc_hir_typeck/src/pat.rs | 264 +++++++++++------ compiler/rustc_hir_typeck/src/place_op.rs | 4 +- compiler/rustc_hir_typeck/src/rvalue_scopes.rs | 6 +- compiler/rustc_hir_typeck/src/upvar.rs | 124 ++++---- compiler/rustc_hir_typeck/src/writeback.rs | 206 +++++++------ 37 files changed, 1897 insertions(+), 1460 deletions(-) (limited to 'compiler/rustc_hir_typeck/src') diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index e8720a5da..7ad9f51ba 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -41,7 +41,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)); + self.check_pat_top(&arm.pat, scrutinee_ty, Some(scrut_span), Some(scrut), None); } // Now typecheck the blocks. @@ -107,7 +107,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (span, code) = match prior_arm { // The reason for the first arm to fail is not that the match arms diverge, // but rather that there's a prior obligation that doesn't hold. - None => (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id)), + None => { + (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id, match_src)) + } Some((prior_arm_block_id, prior_arm_ty, prior_arm_span)) => ( expr.span, ObligationCauseCode::MatchExpressionArm(Box::new(MatchExpressionArmCause { @@ -120,7 +122,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { scrut_span: scrut.span, source: match_src, prior_arms: other_arms.clone(), - scrut_hir_id: scrut.hir_id, opt_suggest_box_span, })), ), @@ -136,15 +137,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &cause, Some(&arm.body), arm_ty, - Some(&mut |err| { - self.suggest_removing_semicolon_for_coerce( - err, - expr, - orig_expected, - arm_ty, - prior_arm, - ) - }), + |err| self.suggest_removing_semicolon_for_coerce(err, expr, arm_ty, prior_arm), false, ); @@ -153,7 +146,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { other_arms.remove(0); } - prior_arm = Some((arm_block_id, arm_ty, arm_span)); + if !arm_ty.is_never() { + // When a match arm has type `!`, then it doesn't influence the expected type for + // the following arm. If all of the prior arms are `!`, then the influence comes + // from elsewhere and we shouldn't point to any previous arm. + prior_arm = Some((arm_block_id, arm_ty, arm_span)); + } } // If all of the arms in the `match` diverge, @@ -181,18 +179,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, diag: &mut Diagnostic, expr: &hir::Expr<'tcx>, - expectation: Expectation<'tcx>, arm_ty: Ty<'tcx>, prior_arm: Option<(Option, Ty<'tcx>, Span)>, ) { let hir = self.tcx.hir(); // First, check that we're actually in the tail of a function. - let Some(body_id) = hir.maybe_body_owned_by(self.body_id) else { return; }; + let Some(body_id) = hir.maybe_body_owned_by(self.body_id) else { + return; + }; let body = hir.body(body_id); - let hir::ExprKind::Block(block, _) = body.value.kind else { return; }; - let Some(hir::Stmt { kind: hir::StmtKind::Semi(last_expr), .. }) - = block.innermost_block().stmts.last() else { return; }; + let hir::ExprKind::Block(block, _) = body.value.kind else { + return; + }; + let Some(hir::Stmt { kind: hir::StmtKind::Semi(last_expr), span: semi_span, .. }) = + block.innermost_block().stmts.last() + else { + return; + }; if last_expr.hir_id != expr.hir_id { return; } @@ -201,8 +205,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let Some(ret) = hir .find_by_def_id(self.body_id) .and_then(|owner| owner.fn_decl()) - .map(|decl| decl.output.span()) else { return; }; - let Expectation::IsLast(stmt) = expectation else { + .map(|decl| decl.output.span()) + else { return; }; @@ -221,7 +225,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } - let semi_span = expr.span.shrink_to_hi().with_hi(stmt.hi()); + let semi_span = expr.span.shrink_to_hi().with_hi(semi_span.hi()); let mut ret_span: MultiSpan = semi_span.into(); ret_span.push_span_label( expr.span, @@ -269,7 +273,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { coercion.coerce_forced_unit( self, &cause, - &mut |err| { + |err| { if let Some((span, msg)) = &ret_reason { err.span_label(*span, msg.clone()); } else if let ExprKind::Block(block, _) = &then_expr.kind @@ -508,9 +512,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, kind: TypeVariableOriginKind::OpaqueTypeInference(rpit_def_id), .. - } = self.type_var_origin(expected)? else { return None; }; + } = self.type_var_origin(expected)? + else { + return None; + }; - let Some(rpit_local_def_id) = rpit_def_id.as_local() else { return None; }; + let Some(rpit_local_def_id) = rpit_def_id.as_local() else { + return None; + }; if !matches!( self.tcx.hir().expect_item(rpit_local_def_id).expect_opaque_ty().origin, hir::OpaqueTyOrigin::FnReturn(..) @@ -520,12 +529,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let sig = self.body_fn_sig()?; - let substs = sig.output().walk().find_map(|arg| { + let args = sig.output().walk().find_map(|arg| { if let ty::GenericArgKind::Type(ty) = arg.unpack() - && let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) = *ty.kind() + && let ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) = *ty.kind() && def_id == rpit_def_id { - Some(substs) + Some(args) } else { None } @@ -539,23 +548,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for (clause, _) in self .tcx .explicit_item_bounds(rpit_def_id) - .subst_iter_copied(self.tcx, substs) + .iter_instantiated_copied(self.tcx, args) { let pred = clause.kind().rebind(match clause.kind().skip_binder() { ty::ClauseKind::Trait(trait_pred) => { - // FIXME(rpitit): This will need to be fixed when we move to associated types assert!(matches!( *trait_pred.trait_ref.self_ty().kind(), - ty::Alias(_, ty::AliasTy { def_id, substs: alias_substs, .. }) - if def_id == rpit_def_id && substs == alias_substs + ty::Alias(ty::Opaque, ty::AliasTy { def_id, args: alias_args, .. }) + if def_id == rpit_def_id && args == alias_args )); ty::ClauseKind::Trait(trait_pred.with_self_ty(self.tcx, ty)) } ty::ClauseKind::Projection(mut proj_pred) => { assert!(matches!( *proj_pred.projection_ty.self_ty().kind(), - ty::Alias(_, ty::AliasTy { def_id, substs: alias_substs, .. }) - if def_id == rpit_def_id && substs == alias_substs + ty::Alias(ty::Opaque, ty::AliasTy { def_id, args: alias_args, .. }) + if def_id == rpit_def_id && args == alias_args )); proj_pred = proj_pred.with_self_ty(self.tcx, ty); ty::ClauseKind::Projection(proj_pred) diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index f306653c1..02371f85a 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -21,7 +21,7 @@ use rustc_infer::{ use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, }; -use rustc_middle::ty::SubstsRef; +use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::{sym, Ident}; @@ -149,14 +149,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return Some(CallStep::Builtin(adjusted_ty)); } - ty::Closure(def_id, substs) => { + ty::Closure(def_id, args) => { let def_id = def_id.expect_local(); // Check whether this is a call to a closure where we // haven't yet decided on whether the closure is fn vs // fnmut vs fnonce. If so, we have to defer further processing. - if self.closure_kind(substs).is_none() { - let closure_sig = substs.as_closure().sig(); + if self.closure_kind(args).is_none() { + let closure_sig = args.as_closure().sig(); let closure_sig = self.instantiate_binder_with_fresh_vars( call_expr.span, infer::FnCall, @@ -171,7 +171,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { adjusted_ty, adjustments, fn_sig: closure_sig, - closure_substs: substs, + closure_args: args, }, ); return Some(CallStep::DeferredClosure(def_id, closure_sig)); @@ -380,16 +380,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Expectation<'tcx>, ) -> Ty<'tcx> { let (fn_sig, def_id) = match *callee_ty.kind() { - ty::FnDef(def_id, substs) => { - self.enforce_context_effects(call_expr.hir_id, call_expr.span, def_id, substs); - let fn_sig = self.tcx.fn_sig(def_id).subst(self.tcx, substs); + ty::FnDef(def_id, args) => { + self.enforce_context_effects(call_expr.hir_id, 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 // `#[rustc_evaluate_where_clauses]` trigger special output // to let us test the trait evaluation system. if self.tcx.has_attr(def_id, sym::rustc_evaluate_where_clauses) { let predicates = self.tcx.predicates_of(def_id); - let predicates = predicates.instantiate(self.tcx, substs); + let predicates = predicates.instantiate(self.tcx, args); for (predicate, predicate_span) in predicates { let obligation = Obligation::new( self.tcx, @@ -402,7 +402,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .sess .struct_span_err( callee_expr.span, - format!("evaluate({:?}) = {:?}", predicate, result), + format!("evaluate({predicate:?}) = {result:?}"), ) .span_label(predicate_span, "predicate") .emit(); @@ -499,15 +499,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Expectation<'tcx>, ) { if let [callee_expr, rest @ ..] = arg_exprs { - let Some(callee_ty) = self.typeck_results.borrow().expr_ty_adjusted_opt(callee_expr) else { + let Some(callee_ty) = self.typeck_results.borrow().expr_ty_adjusted_opt(callee_expr) + else { return; }; // First, do a probe with `IsSuggestion(true)` to avoid emitting // any strange errors. If it's successful, then we'll do a true // method lookup. - let Ok(pick) = self - .lookup_probe_for_diagnostic( + let Ok(pick) = self.lookup_probe_for_diagnostic( segment.ident, callee_ty, call_expr, @@ -531,8 +531,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } - let up_to_rcvr_span = segment.ident.span.until(callee_expr.span); - let rest_span = callee_expr.span.shrink_to_hi().to(call_expr.span.shrink_to_hi()); + let Some(callee_expr_span) = callee_expr.span.find_ancestor_inside(call_expr.span) + else { + return; + }; + let up_to_rcvr_span = segment.ident.span.until(callee_expr_span); + let rest_span = callee_expr_span.shrink_to_hi().to(call_expr.span.shrink_to_hi()); let rest_snippet = if let Some(first) = rest.first() { self.tcx .sess @@ -581,12 +585,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { callee_ty: Ty<'tcx>, arg_exprs: &'tcx [hir::Expr<'tcx>], ) -> ErrorGuaranteed { + // Callee probe fails when APIT references errors, so suppress those + // errors here. + if let Some((_, _, args)) = self.extract_callable_info(callee_ty) + && let Err(err) = args.error_reported() + { + return err; + } + let mut unit_variant = None; if let hir::ExprKind::Path(qpath) = &callee_expr.kind && let Res::Def(def::DefKind::Ctor(kind, CtorKind::Const), _) = self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id) // Only suggest removing parens if there are no arguments && arg_exprs.is_empty() + && call_expr.span.contains(callee_expr.span) { let descr = match kind { def::CtorOf::Struct => "struct", @@ -633,18 +646,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id) } hir::ExprKind::Call(ref inner_callee, _) => { - // If the call spans more than one line and the callee kind is - // itself another `ExprCall`, that's a clue that we might just be - // missing a semicolon (Issue #51055) - let call_is_multiline = self.tcx.sess.source_map().is_multiline(call_expr.span); - if call_is_multiline { - err.span_suggestion( - callee_expr.span.shrink_to_hi(), - "consider using a semicolon here", - ";", - Applicability::MaybeIncorrect, - ); - } 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) @@ -656,6 +657,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) { + // If the call spans more than one line and the callee kind is + // itself another `ExprCall`, that's a clue that we might just be + // missing a semicolon (#51055, #106515). + let call_is_multiline = self + .tcx + .sess + .source_map() + .is_multiline(call_expr.span.with_lo(callee_expr.span.hi())) + && call_expr.span.ctxt() == callee_expr.span.ctxt(); + if call_is_multiline { + err.span_suggestion( + callee_expr.span.shrink_to_hi(), + "consider using a semicolon here to finish the statement", + ";", + Applicability::MaybeIncorrect, + ); + } if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_ty) && !self.type_is_sized_modulo_regions(self.param_env, output_ty) { @@ -751,13 +769,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_expr_hir: HirId, span: Span, callee_did: DefId, - callee_substs: SubstsRef<'tcx>, + callee_args: GenericArgsRef<'tcx>, ) { let tcx = self.tcx; - if !tcx.features().effects || tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you { - return; - } + // fast-reject if callee doesn't have the host effect param (non-const) + 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); @@ -768,33 +792,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if tcx.has_attr(context.to_def_id(), sym::rustc_do_not_const_check) { trace!("do not const check this context"); - return; + 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 substs = ty::InternalSubsts::identity_for_item(tcx, context); - substs.host_effect_param().expect("ConstContext::Maybe must have host effect param") + let args = ty::GenericArgs::identity_for_item(tcx, context); + args.host_effect_param().expect("ConstContext::Maybe must have host effect param") } None => tcx.consts.true_, }; - let generics = tcx.generics_of(callee_did); + trace!(?effect, ?generics, ?callee_args); - trace!(?effect, ?generics, ?callee_substs); - - if let Some(idx) = generics.host_effect_index { - let param = callee_substs.const_at(idx); - let cause = self.misc(span); - match self.at(&cause, self.param_env).eq(infer::DefineOpaqueTypes::No, effect, param) { - Ok(infer::InferOk { obligations, value: () }) => { - self.register_predicates(obligations); - } - Err(e) => { - // FIXME(effects): better diagnostic - self.err_ctxt().report_mismatched_consts(&cause, effect, param, e).emit(); - } + let param = callee_args.const_at(host_effect_index); + let cause = self.misc(span); + match self.at(&cause, self.param_env).eq(infer::DefineOpaqueTypes::No, effect, param) { + Ok(infer::InferOk { obligations, value: () }) => { + self.register_predicates(obligations); + } + Err(e) => { + // FIXME(effects): better diagnostic + self.err_ctxt().report_mismatched_consts(&cause, effect, param, e).emit(); } } } @@ -827,7 +848,7 @@ pub struct DeferredCallResolution<'tcx> { adjusted_ty: Ty<'tcx>, adjustments: Vec>, fn_sig: ty::FnSig<'tcx>, - closure_substs: SubstsRef<'tcx>, + closure_args: GenericArgsRef<'tcx>, } impl<'a, 'tcx> DeferredCallResolution<'tcx> { @@ -836,7 +857,7 @@ impl<'a, 'tcx> DeferredCallResolution<'tcx> { // we should not be invoked until the closure kind has been // determined by upvar inference - assert!(fcx.closure_kind(self.closure_substs).is_some()); + assert!(fcx.closure_kind(self.closure_args).is_some()); // We may now know enough to figure out fn vs fnmut etc. match fcx.try_overloaded_call_traits(self.call_expr, self.adjusted_ty, None) { diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 633933317..31a03fabe 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -103,10 +103,10 @@ 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::Adt(def, substs) if def.is_struct() => match def.non_enum_variant().tail_opt() { + ty::Adt(def, args) if def.is_struct() => match def.non_enum_variant().tail_opt() { None => Some(PointerKind::Thin), Some(f) => { - let field_ty = self.field_ty(span, f, substs); + let field_ty = self.field_ty(span, f, args); self.pointer_kind(field_ty, span)? } }, @@ -144,7 +144,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let reported = self .tcx .sess - .delay_span_bug(span, format!("`{:?}` should be sized but is not?", t)); + .delay_span_bug(span, format!("`{t:?}` should be sized but is not?")); return Err(reported); } }) @@ -389,34 +389,26 @@ impl<'a, 'tcx> CastCheck<'tcx> { if let ty::Ref(reg, cast_ty, mutbl) = *self.cast_ty.kind() { if let ty::RawPtr(TypeAndMut { ty: expr_ty, .. }) = *self.expr_ty.kind() && fcx - .try_coerce( - self.expr, + .can_coerce( Ty::new_ref(fcx.tcx, fcx.tcx.lifetimes.re_erased, TypeAndMut { ty: expr_ty, mutbl }, ), self.cast_ty, - AllowTwoPhase::No, - None, ) - .is_ok() { sugg = Some((format!("&{}*", mutbl.prefix_str()), cast_ty == expr_ty)); } else if let ty::Ref(expr_reg, expr_ty, expr_mutbl) = *self.expr_ty.kind() && expr_mutbl == Mutability::Not && mutbl == Mutability::Mut && fcx - .try_coerce( - self.expr, + .can_coerce( Ty::new_ref(fcx.tcx, expr_reg, TypeAndMut { ty: expr_ty, mutbl: Mutability::Mut }, ), self.cast_ty, - AllowTwoPhase::No, - None, ) - .is_ok() { sugg_mutref = true; } @@ -424,30 +416,22 @@ impl<'a, 'tcx> CastCheck<'tcx> { if !sugg_mutref && sugg == None && fcx - .try_coerce( - self.expr, + .can_coerce( Ty::new_ref(fcx.tcx,reg, TypeAndMut { ty: self.expr_ty, mutbl }), self.cast_ty, - AllowTwoPhase::No, - None, ) - .is_ok() { sugg = Some((format!("&{}", mutbl.prefix_str()), false)); } } else if let ty::RawPtr(TypeAndMut { mutbl, .. }) = *self.cast_ty.kind() && fcx - .try_coerce( - self.expr, + .can_coerce( Ty::new_ref(fcx.tcx, fcx.tcx.lifetimes.re_erased, TypeAndMut { ty: self.expr_ty, mutbl }, ), self.cast_ty, - AllowTwoPhase::No, - None, ) - .is_ok() { sugg = Some((format!("&{}", mutbl.prefix_str()), false)); } @@ -644,12 +628,12 @@ impl<'a, 'tcx> CastCheck<'tcx> { err.span_suggestion( self.cast_span, "try casting to a reference instead", - format!("&{}{}", mtstr, s), + format!("&{mtstr}{s}"), Applicability::MachineApplicable, ); } Err(_) => { - let msg = format!("did you mean `&{}{}`?", mtstr, tstr); + let msg = format!("did you mean `&{mtstr}{tstr}`?"); err.span_help(self.cast_span, msg); } } @@ -705,10 +689,10 @@ impl<'a, 'tcx> CastCheck<'tcx> { ) }), |lint| { - lint.help(format!( + lint.help( "cast can be replaced by coercion; this might \ - require a temporary variable" - )) + require a temporary variable", + ) }, ); } @@ -760,7 +744,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { ty::FnDef(..) => { // Attempt a coercion to a fn pointer type. let f = fcx.normalize(self.expr_span, self.expr_ty.fn_sig(fcx.tcx)); - let res = fcx.try_coerce( + let res = fcx.coerce( self.expr, self.expr_ty, Ty::new_fn_ptr(fcx.tcx, f), @@ -860,7 +844,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { (_, DynStar) => { if fcx.tcx.features().dyn_star { - bug!("should be handled by `try_coerce`") + bug!("should be handled by `coerce`") } else { Err(CastError::IllegalCast) } @@ -956,7 +940,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { // Coerce to a raw pointer so that we generate AddressOf in MIR. let array_ptr_type = Ty::new_ptr(fcx.tcx, m_expr); - fcx.try_coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None) + fcx.coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None) .unwrap_or_else(|_| { bug!( "could not cast from reference to array to pointer to array ({:?} to {:?})", @@ -992,7 +976,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { } fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<(), ty::error::TypeError<'tcx>> { - match fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No, None) { + match fcx.coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No, None) { Ok(_) => Ok(()), Err(err) => Err(err), } diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 8b57e311f..1fc1e5aca 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -80,7 +80,7 @@ pub(super) fn check_fn<'a, 'tcx>( let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span)); let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span)); - tcx.type_of(va_list_did).subst(tcx, &[region.into()]) + tcx.type_of(va_list_did).instantiate(tcx, &[region.into()]) }); // Add formal parameters. @@ -89,7 +89,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); + fcx.check_pat_top(¶m.pat, param_ty, ty_span, None, None); // Check that argument is Sized. if !params_can_be_unsized { diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 78a9ac49d..b19fb6da6 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -10,8 +10,8 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi use rustc_infer::infer::{DefineOpaqueTypes, LateBoundRegionConversionTime}; use rustc_infer::infer::{InferOk, InferResult}; use rustc_macros::{TypeFoldable, TypeVisitable}; -use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; +use rustc_middle::ty::GenericArgs; use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Span; @@ -81,7 +81,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!(?bound_sig, ?liberated_sig); - let mut fcx = FnCtxt::new(self, self.param_env.without_const(), closure.def_id); + let mut fcx = FnCtxt::new(self, self.param_env, closure.def_id); let generator_types = check_fn( &mut fcx, liberated_sig, @@ -93,7 +93,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false, ); - let parent_substs = InternalSubsts::identity_for_item( + let parent_args = GenericArgs::identity_for_item( self.tcx, self.tcx.typeck_root_def_id(expr_def_id.to_def_id()), ); @@ -105,10 +105,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(GeneratorTypes { resume_ty, yield_ty, interior, movability }) = generator_types { - let generator_substs = ty::GeneratorSubsts::new( + let generator_args = ty::GeneratorArgs::new( self.tcx, - ty::GeneratorSubstsParts { - parent_substs, + ty::GeneratorArgsParts { + parent_args, resume_ty, yield_ty, return_ty: liberated_sig.output(), @@ -120,7 +120,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return Ty::new_generator( self.tcx, expr_def_id.to_def_id(), - generator_substs.substs, + generator_args.args, movability, ); } @@ -151,17 +151,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }), }; - let closure_substs = ty::ClosureSubsts::new( + let closure_args = ty::ClosureArgs::new( self.tcx, - ty::ClosureSubstsParts { - parent_substs, + ty::ClosureArgsParts { + parent_args, closure_kind_ty, closure_sig_as_fn_ptr_ty: Ty::new_fn_ptr(self.tcx, sig), tupled_upvars_ty, }, ); - Ty::new_closure(self.tcx, expr_def_id.to_def_id(), closure_substs.substs) + Ty::new_closure(self.tcx, expr_def_id.to_def_id(), closure_args.args) } /// Given the expected type, figures out what it can about this closure we @@ -172,12 +172,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected_ty: Ty<'tcx>, ) -> (Option>, Option) { match *expected_ty.kind() { - ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => self + ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => self .deduce_closure_signature_from_predicates( expected_ty, self.tcx .explicit_item_bounds(def_id) - .subst_iter_copied(self.tcx, substs) + .iter_instantiated_copied(self.tcx, args) .map(|(c, s)| (c.as_predicate(), s)), ), ty::Dynamic(ref object_type, ..) => { @@ -315,7 +315,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let input_tys = if is_fn { - let arg_param_ty = projection.skip_binder().projection_ty.substs.type_at(1); + let arg_param_ty = projection.skip_binder().projection_ty.args.type_at(1); let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty); debug!(?arg_param_ty); @@ -711,38 +711,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; + let span = self.tcx.def_span(expr_def_id); + let output_ty = match *ret_ty.kind() { ty::Infer(ty::TyVar(ret_vid)) => { self.obligations_for_self_ty(ret_vid).find_map(|obligation| { get_future_output(obligation.predicate, obligation.cause.span) })? } - ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => self + ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => self .tcx .explicit_item_bounds(def_id) - .subst_iter_copied(self.tcx, substs) + .iter_instantiated_copied(self.tcx, args) .find_map(|(p, s)| get_future_output(p.as_predicate(), s))?, ty::Error(_) => return None, - ty::Alias(ty::Projection, proj) if self.tcx.is_impl_trait_in_trait(proj.def_id) => self - .tcx - .explicit_item_bounds(proj.def_id) - .subst_iter_copied(self.tcx, proj.substs) - .find_map(|(p, s)| get_future_output(p.as_predicate(), s))?, _ => span_bug!( - self.tcx.def_span(expr_def_id), + span, "async fn generator return type not an inference variable: {ret_ty}" ), }; + let output_ty = self.normalize(span, output_ty); + // async fn that have opaque types in their return type need to redo the conversion to inference variables // as they fetch the still opaque version from the signature. let InferOk { value: output_ty, obligations } = self - .replace_opaque_types_with_inference_vars( - output_ty, - body_def_id, - self.tcx.def_span(expr_def_id), - self.param_env, - ); + .replace_opaque_types_with_inference_vars(output_ty, body_def_id, span, self.param_env); self.register_predicates(obligations); Some(output_ty) @@ -800,7 +794,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Converts the types that the user supplied, in case that doing /// so should yield an error, but returns back a signature where - /// all parameters are of type `TyErr`. + /// all parameters are of type `ty::Error`. fn error_sig_of_closure( &self, decl: &hir::FnDecl<'_>, diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index dc58d99ed..fca675ea9 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -46,13 +46,14 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult}; use rustc_infer::traits::{Obligation, PredicateObligation}; use rustc_middle::lint::in_external_macro; +use rustc_middle::traits::BuiltinImplSource; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCoercion, }; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::RelateResult; -use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::visit::TypeVisitableExt; +use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, Ty, TypeAndMut}; use rustc_session::parse::feature_err; use rustc_span::symbol::sym; @@ -251,11 +252,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // unsafe qualifier. self.coerce_from_fn_pointer(a, a_f, b) } - ty::Closure(closure_def_id_a, substs_a) => { + ty::Closure(closure_def_id_a, args_a) => { // Non-capturing closures are coercible to // function pointers or unsafe function pointers. // It cannot convert closures that require unsafe. - self.coerce_closure_to_fn(a, closure_def_id_a, substs_a, b) + self.coerce_closure_to_fn(a, closure_def_id_a, args_a, b) } _ => { // Otherwise, just use unification rules. @@ -509,9 +510,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { success(adjustments, ty, obligations) } - // &[T; n] or &mut [T; n] -> &[T] - // or &mut [T; n] -> &mut [T] - // or &Concrete -> &Trait, etc. + /// Performs [unsized coercion] by emulating a fulfillment loop on a + /// `CoerceUnsized` goal until all `CoerceUnsized` and `Unsize` goals + /// are successfully selected. + /// + /// [unsized coercion](https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions) #[instrument(skip(self), level = "debug")] fn coerce_unsized(&self, mut source: Ty<'tcx>, mut target: Ty<'tcx>) -> CoerceResult<'tcx> { source = self.shallow_resolve(source); @@ -636,21 +639,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred))) if traits.contains(&trait_pred.def_id()) => { - if unsize_did == trait_pred.def_id() { - let self_ty = trait_pred.self_ty(); - let unsize_ty = trait_pred.trait_ref.substs[1].expect_ty(); - if let (ty::Dynamic(ref data_a, ..), ty::Dynamic(ref data_b, ..)) = - (self_ty.kind(), unsize_ty.kind()) - && data_a.principal_def_id() != data_b.principal_def_id() - { - debug!("coerce_unsized: found trait upcasting coercion"); - has_trait_upcasting_coercion = Some((self_ty, unsize_ty)); - } - if let ty::Tuple(..) = unsize_ty.kind() { - debug!("coerce_unsized: found unsized tuple coercion"); - has_unsized_tuple_coercion = true; - } - } trait_pred } _ => { @@ -658,13 +646,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { continue; } }; + let trait_pred = self.resolve_vars_if_possible(trait_pred); match selcx.select(&obligation.with(selcx.tcx(), trait_pred)) { // Uncertain or unimplemented. Ok(None) => { if trait_pred.def_id() == unsize_did { - let trait_pred = self.resolve_vars_if_possible(trait_pred); let self_ty = trait_pred.self_ty(); - let unsize_ty = trait_pred.trait_ref.substs[1].expect_ty(); + let unsize_ty = trait_pred.trait_ref.args[1].expect_ty(); debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_pred); match (self_ty.kind(), unsize_ty.kind()) { (&ty::Infer(ty::TyVar(v)), ty::Dynamic(..)) @@ -701,20 +689,28 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // be silent, as it causes a type mismatch later. } - Ok(Some(impl_source)) => queue.extend(impl_source.nested_obligations()), + Ok(Some(impl_source)) => { + // Some builtin coercions are still unstable so we detect + // these here and emit a feature error if coercion doesn't fail + // due to another reason. + match impl_source { + traits::ImplSource::Builtin( + BuiltinImplSource::TraitUpcasting { .. }, + _, + ) => { + has_trait_upcasting_coercion = + Some((trait_pred.self_ty(), trait_pred.trait_ref.args.type_at(1))); + } + traits::ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => { + has_unsized_tuple_coercion = true; + } + _ => {} + } + queue.extend(impl_source.nested_obligations()) + } } } - if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion { - feature_err( - &self.tcx.sess.parse_sess, - sym::unsized_tuple_coercion, - self.cause.span, - "unsized tuple coercion is not stable enough for use and is subject to change", - ) - .emit(); - } - if let Some((sub, sup)) = has_trait_upcasting_coercion && !self.tcx().features().trait_upcasting { @@ -730,6 +726,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { err.emit(); } + if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion { + feature_err( + &self.tcx.sess.parse_sess, + sym::unsized_tuple_coercion, + self.cause.span, + "unsized tuple coercion is not stable enough for use and is subject to change", + ) + .emit(); + } + Ok(coercion) } @@ -916,7 +922,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { &self, a: Ty<'tcx>, closure_def_id_a: DefId, - substs_a: SubstsRef<'tcx>, + args_a: GenericArgsRef<'tcx>, b: Ty<'tcx>, ) -> CoerceResult<'tcx> { //! Attempts to coerce from the type of a non-capturing closure @@ -927,7 +933,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { match b.kind() { // At this point we haven't done capture analysis, which means - // that the ClosureSubsts just contains an inference variable instead + // that the ClosureArgs just contains an inference variable instead // of tuple of captured types. // // All we care here is if any variable is being captured and not the exact paths, @@ -944,7 +950,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // `fn(arg0,arg1,...) -> _` // or // `unsafe fn(arg0,arg1,...) -> _` - let closure_sig = substs_a.as_closure().sig(); + let closure_sig = args_a.as_closure().sig(); let unsafety = fn_ty.unsafety(); let pointer_ty = Ty::new_fn_ptr(self.tcx, self.tcx.signature_unclosure(closure_sig, unsafety)); @@ -999,15 +1005,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// adjusted type of the expression, if successful. /// Adjustments are only recorded if the coercion succeeded. /// The expressions *must not* have any preexisting adjustments. - pub fn try_coerce( + pub fn coerce( &self, expr: &hir::Expr<'_>, expr_ty: Ty<'tcx>, - target: Ty<'tcx>, + mut target: Ty<'tcx>, allow_two_phase: AllowTwoPhase, cause: Option>, ) -> RelateResult<'tcx, Ty<'tcx>> { let source = self.try_structurally_resolve_type(expr.span, expr_ty); + if self.next_trait_solver() { + target = self.try_structurally_resolve_type( + cause.as_ref().map_or(expr.span, |cause| cause.span), + target, + ); + } debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); let cause = @@ -1024,11 +1036,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) } - /// Same as `try_coerce()`, but without side-effects. + /// Same as `coerce()`, but without side-effects. /// /// 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. let source = self.resolve_vars_with_obligations(expr_ty); debug!("coercion::can_with_predicates({:?} -> {:?})", source, target); @@ -1093,8 +1106,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { where E: AsCoercionSite, { - let prev_ty = self.resolve_vars_with_obligations(prev_ty); - let new_ty = self.resolve_vars_with_obligations(new_ty); + let prev_ty = self.try_structurally_resolve_type(cause.span, prev_ty); + let new_ty = self.try_structurally_resolve_type(new.span, new_ty); debug!( "coercion::try_find_coercion_lub({:?}, {:?}, exprs={:?} exprs)", prev_ty, @@ -1109,10 +1122,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // Special-case that coercion alone cannot handle: - // Function items or non-capturing closures of differing IDs or InternalSubsts. + // Function items or non-capturing closures of differing IDs or GenericArgs. let (a_sig, b_sig) = { let is_capturing_closure = |ty: Ty<'tcx>| { - if let &ty::Closure(closure_def_id, _substs) = ty.kind() { + if let &ty::Closure(closure_def_id, _args) = ty.kind() { self.tcx.upvars_mentioned(closure_def_id.expect_local()).is_some() } else { false @@ -1139,30 +1152,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } - (ty::Closure(_, substs), ty::FnDef(..)) => { + (ty::Closure(_, args), ty::FnDef(..)) => { let b_sig = new_ty.fn_sig(self.tcx); - let a_sig = self - .tcx - .signature_unclosure(substs.as_closure().sig(), b_sig.unsafety()); + let a_sig = + self.tcx.signature_unclosure(args.as_closure().sig(), b_sig.unsafety()); (Some(a_sig), Some(b_sig)) } - (ty::FnDef(..), ty::Closure(_, substs)) => { + (ty::FnDef(..), ty::Closure(_, args)) => { let a_sig = prev_ty.fn_sig(self.tcx); - let b_sig = self - .tcx - .signature_unclosure(substs.as_closure().sig(), a_sig.unsafety()); + let b_sig = + self.tcx.signature_unclosure(args.as_closure().sig(), a_sig.unsafety()); (Some(a_sig), Some(b_sig)) } - (ty::Closure(_, substs_a), ty::Closure(_, substs_b)) => ( - Some(self.tcx.signature_unclosure( - substs_a.as_closure().sig(), - hir::Unsafety::Normal, - )), - Some(self.tcx.signature_unclosure( - substs_b.as_closure().sig(), - hir::Unsafety::Normal, - )), - ), + (ty::Closure(_, args_a), ty::Closure(_, args_b)) => { + ( + Some(self.tcx.signature_unclosure( + args_a.as_closure().sig(), + hir::Unsafety::Normal, + )), + Some(self.tcx.signature_unclosure( + args_b.as_closure().sig(), + hir::Unsafety::Normal, + )), + ) + } _ => (None, None), } } @@ -1414,7 +1427,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { expression: &'tcx hir::Expr<'tcx>, expression_ty: Ty<'tcx>, ) { - self.coerce_inner(fcx, cause, Some(expression), expression_ty, None, false) + self.coerce_inner(fcx, cause, Some(expression), expression_ty, |_| {}, false) } /// Indicates that one of the inputs is a "forced unit". This @@ -1433,7 +1446,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { &mut self, fcx: &FnCtxt<'a, 'tcx>, cause: &ObligationCause<'tcx>, - augment_error: &mut dyn FnMut(&mut Diagnostic), + augment_error: impl FnOnce(&mut Diagnostic), label_unit_as_expected: bool, ) { self.coerce_inner( @@ -1441,7 +1454,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { cause, None, Ty::new_unit(fcx.tcx), - Some(augment_error), + augment_error, label_unit_as_expected, ) } @@ -1456,7 +1469,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { cause: &ObligationCause<'tcx>, expression: Option<&'tcx hir::Expr<'tcx>>, mut expression_ty: Ty<'tcx>, - augment_error: Option<&mut dyn FnMut(&mut Diagnostic)>, + augment_error: impl FnOnce(&mut Diagnostic), label_expression_as_expected: bool, ) { // Incorporate whatever type inference information we have @@ -1481,7 +1494,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { // Special-case the first expression we are coercing. // To be honest, I'm not entirely sure why we do this. // We don't allow two-phase borrows, see comment in try_find_coercion_lub for why - fcx.try_coerce( + fcx.coerce( expression, expression_ty, self.expected_ty, @@ -1590,7 +1603,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { ); err.span_label(cause.span, "return type is not `()`"); } - ObligationCauseCode::BlockTailExpression(blk_id) => { + ObligationCauseCode::BlockTailExpression(blk_id, ..) => { let parent_id = fcx.tcx.hir().parent_id(blk_id); err = self.report_return_mismatched_types( cause, @@ -1635,14 +1648,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { } } - if let Some(augment_error) = augment_error { - augment_error(&mut err); - } - - let is_insufficiently_polymorphic = - matches!(coercion_error, TypeError::RegionsInsufficientlyPolymorphic(..)); + augment_error(&mut err); - if !is_insufficiently_polymorphic && let Some(expr) = expression { + if let Some(expr) = expression { fcx.emit_coerce_suggestions( &mut err, expr, @@ -1670,7 +1678,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { expr: &hir::Expr<'tcx>, ret_exprs: &Vec<&'tcx hir::Expr<'tcx>>, ) { - let hir::ExprKind::Loop(_, _, _, loop_span) = expr.kind else { return;}; + let hir::ExprKind::Loop(_, _, _, loop_span) = expr.kind else { + return; + }; let mut span: MultiSpan = vec![loop_span].into(); span.push_span_label(loop_span, "this might have zero elements to iterate on"); const MAXITER: usize = 3; @@ -1738,7 +1748,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { ) && !in_external_macro(fcx.tcx.sess, cond_expr.span) && !matches!( cond_expr.kind, - hir::ExprKind::Match(.., hir::MatchSource::TryDesugar) + hir::ExprKind::Match(.., hir::MatchSource::TryDesugar(_)) ) { err.span_label(cond_expr.span, "expected this to be `()`"); @@ -1791,8 +1801,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { err.span_note( sp, format!( - "return type inferred to be `{}` here", - expected + "return type inferred to be `{expected}` here" ), ); } diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index cc8198aab..2c16f21b4 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut, TypeFoldable}; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::sym; use rustc_span::{BytePos, Span, DUMMY_SP}; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::ObligationCause; @@ -53,7 +53,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { || self.suggest_no_capture_closure(err, expected, expr_ty) || self.suggest_boxing_when_appropriate(err, expr.span, expr.hir_id, expected, expr_ty) || self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected) - || self.suggest_copied_or_cloned(err, expr, expr_ty, expected) + || self.suggest_copied_cloned_or_as_ref(err, expr, expr_ty, expected) || self.suggest_clone_for_ref(err, expr, expr_ty, expected) || self.suggest_into(err, expr, expr_ty, expected) || self.suggest_floating_point_literal(err, expr, expected) @@ -84,6 +84,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.annotate_expected_due_to_let_ty(err, expr, error); + // FIXME(#73154): For now, we do leak check when coercing function + // pointers in typeck, instead of only during borrowck. This can lead + // to these `RegionsInsufficientlyPolymorphic` errors that aren't helpful. + if matches!(error, Some(TypeError::RegionsInsufficientlyPolymorphic(..))) { + return; + } + if self.is_destruct_assignment_desugaring(expr) { return; } @@ -102,7 +109,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { found_expr: &mut &'tcx hir::Expr<'tcx>, expected_expr: &mut Option<&'tcx hir::Expr<'tcx>>, ) { - let Some(expected_expr) = expected_expr else { return; }; + let Some(expected_expr) = expected_expr else { + return; + }; if !found_expr.span.eq_ctxt(expected_expr.span) { return; @@ -121,11 +130,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let hir::ExprKind::Unary( hir::UnOp::Deref, hir::Expr { kind: hir::ExprKind::Path(found_path), .. }, - ) = found_expr.kind else { return; }; + ) = found_expr.kind + else { + return; + }; let hir::ExprKind::Unary( hir::UnOp::Deref, hir::Expr { kind: hir::ExprKind::Path(expected_path), .. }, - ) = expected_expr.kind else { return; }; + ) = expected_expr.kind + else { + return; + }; for (path, name, idx, var) in [ (expected_path, "left_val", 0, expected_expr), @@ -239,7 +254,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> (Ty<'tcx>, Option>) { let expected = self.resolve_vars_with_obligations(expected); - let e = match self.try_coerce(expr, checked_ty, expected, allow_two_phase, None) { + let e = match self.coerce(expr, checked_ty, expected, allow_two_phase, None) { Ok(ty) => return (ty, None), Err(e) => e, }; @@ -252,25 +267,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); let expr = expr.peel_drop_temps(); let cause = self.misc(expr.span); - let expr_ty = self.resolve_vars_with_obligations(checked_ty); + let expr_ty = self.resolve_vars_if_possible(checked_ty); let mut err = self.err_ctxt().report_mismatched_types(&cause, expected, expr_ty, e); - let is_insufficiently_polymorphic = - matches!(e, TypeError::RegionsInsufficientlyPolymorphic(..)); - - // FIXME(#73154): For now, we do leak check when coercing function - // pointers in typeck, instead of only during borrowck. This can lead - // to these `RegionsInsufficientlyPolymorphic` errors that aren't helpful. - if !is_insufficiently_polymorphic { - self.emit_coerce_suggestions( - &mut err, - expr, - expr_ty, - expected, - expected_ty_expr, - Some(e), - ); - } + self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected, expected_ty_expr, Some(e)); (expected, Some(err)) } @@ -285,16 +285,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> bool { let hir = self.tcx.hir(); - let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = expr.kind else { return false; }; - let [hir::PathSegment { ident, args: None, .. }] = p.segments else { return false; }; - let hir::def::Res::Local(local_hir_id) = p.res else { return false; }; - let hir::Node::Pat(pat) = hir.get(local_hir_id) else { return false; }; + let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = expr.kind else { + return false; + }; + let [hir::PathSegment { ident, args: None, .. }] = p.segments else { + return false; + }; + let hir::def::Res::Local(local_hir_id) = p.res else { + return false; + }; + let hir::Node::Pat(pat) = hir.get(local_hir_id) else { + return false; + }; let (init_ty_hir_id, init) = match hir.get_parent(pat.hir_id) { hir::Node::Local(hir::Local { ty: Some(ty), init, .. }) => (ty.hir_id, *init), hir::Node::Local(hir::Local { init: Some(init), .. }) => (init.hir_id, Some(*init)), _ => return false, }; - let Some(init_ty) = self.node_ty_opt(init_ty_hir_id) else { return false; }; + let Some(init_ty) = self.node_ty_opt(init_ty_hir_id) else { + return false; + }; // Locate all the usages of the relevant binding. struct FindExprs<'tcx> { @@ -413,14 +423,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Bindings always update their recorded type after the fact, so we // need to look at the *following* usage's type to see when the // binding became incompatible. - let [binding, next_usage] = *window else { continue; }; + let [binding, next_usage] = *window else { + continue; + }; // Don't go past the binding (always gonna be a nonsense label if so) if binding.hir_id == expr.hir_id { break; } - let Some(next_use_ty) = self.node_ty_opt(next_usage.hir_id) else { continue; }; + let Some(next_use_ty) = self.node_ty_opt(next_usage.hir_id) else { + continue; + }; // If the type is not constrained in a way making it not possible to // equate with `expected_ty` by this point, skip. @@ -461,7 +475,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let Some(arg_ty) = self.node_ty_opt(arg_expr.hir_id) else { continue; }; let arg_ty = arg_ty.fold_with(&mut fudger); - let _ = self.try_coerce( + let _ = self.coerce( arg_expr, arg_ty, *expected_arg_ty, @@ -599,7 +613,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // is in a different line, so we point at both. err.span_label(secondary_span, "expected due to the type of this binding"); err.span_label(primary_span, format!("expected due to this{post_message}")); - } else if post_message == "" { + } else if post_message.is_empty() { // We are pointing at either the assignment lhs or the binding def pattern. err.span_label(primary_span, "expected due to the type of this binding"); } else { @@ -634,27 +648,36 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { error: Option>, ) { let parent = self.tcx.hir().parent_id(expr.hir_id); - let Some(TypeError::Sorts(ExpectedFound { expected, .. })) = error else {return;}; - let Some(hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Assign(lhs, rhs, _), .. - })) = self.tcx.hir().find(parent) else {return; }; + let Some(TypeError::Sorts(ExpectedFound { expected, .. })) = error else { + return; + }; + let Some(hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(lhs, rhs, _), .. })) = + self.tcx.hir().find(parent) + else { + return; + }; if rhs.hir_id != expr.hir_id || expected.is_closure() { return; } - let hir::ExprKind::Unary(hir::UnOp::Deref, deref) = lhs.kind else { return; }; - let hir::ExprKind::MethodCall(path, base, args, _) = deref.kind else { return; }; - let Some(self_ty) = self.typeck_results.borrow().expr_ty_adjusted_opt(base) else { return; }; + let hir::ExprKind::Unary(hir::UnOp::Deref, deref) = lhs.kind else { + return; + }; + let hir::ExprKind::MethodCall(path, base, args, _) = deref.kind else { + return; + }; + let Some(self_ty) = self.typeck_results.borrow().expr_ty_adjusted_opt(base) else { + return; + }; - let Ok(pick) = self - .lookup_probe_for_diagnostic( - path.ident, - self_ty, - deref, - probe::ProbeScope::TraitsInScope, - None, - ) else { - return; - }; + let Ok(pick) = self.lookup_probe_for_diagnostic( + path.ident, + self_ty, + deref, + probe::ProbeScope::TraitsInScope, + None, + ) else { + return; + }; let in_scope_methods = self.probe_for_name_many( probe::Mode::MethodCall, path.ident, @@ -681,7 +704,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .filter(|c| c.item.def_id != pick.item.def_id) .map(|c| { let m = c.item; - let substs = ty::InternalSubsts::for_item(self.tcx, m.def_id, |param, _| { + let generic_args = ty::GenericArgs::for_item(self.tcx, m.def_id, |param, _| { self.var_for_def(deref.span, param) }); let mutability = @@ -696,7 +719,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!( "{}({}", with_no_trimmed_paths!( - self.tcx.def_path_str_with_substs(m.def_id, substs,) + self.tcx.def_path_str_with_args(m.def_id, generic_args,) ), mutability, ), @@ -793,8 +816,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, found: Ty<'tcx>, ) -> bool { - let ty::Adt(e, substs_e) = expected.kind() else { return false; }; - let ty::Adt(f, substs_f) = found.kind() else { return false; }; + let ty::Adt(e, args_e) = expected.kind() else { + return false; + }; + let ty::Adt(f, args_f) = found.kind() else { + return false; + }; if e.did() != f.did() { return false; } @@ -811,8 +838,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { return false; } - let e = substs_e.type_at(1); - let f = substs_f.type_at(1); + let e = args_e.type_at(1); + let f = args_f.type_at(1); if self .infcx .type_implements_trait( @@ -845,7 +872,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, expr_ty: Ty<'tcx>, ) -> bool { - if let ty::Adt(expected_adt, substs) = expected.kind() { + if in_external_macro(self.tcx.sess, expr.span) { + return false; + } + if let ty::Adt(expected_adt, args) = expected.kind() { if let hir::ExprKind::Field(base, ident) = expr.kind { let base_ty = self.typeck_results.borrow().expr_ty(base); if self.can_eq(self.param_env, base_ty, expected) @@ -944,7 +974,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let note_about_variant_field_privacy = (field_is_local && !field_is_accessible) .then(|| " (its field is private, but it's local to this crate and its privacy can be changed)".to_string()); - let sole_field_ty = sole_field.ty(self.tcx, substs); + let sole_field_ty = sole_field.ty(self.tcx, args); if self.can_coerce(expr_ty, sole_field_ty) { let variant_path = with_no_trimmed_paths!(self.tcx.def_path_str(variant.def_id)); @@ -962,7 +992,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .collect(); let suggestions_for = |variant: &_, ctor_kind, field_name| { - let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) { + let prefix = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) { Some(ident) => format!("{ident}: "), None => String::new(), }; @@ -1037,9 +1067,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx; let (adt, unwrap) = match expected.kind() { // In case Option is wanted, but * is provided, suggest calling new - ty::Adt(adt, substs) if tcx.is_diagnostic_item(sym::Option, adt.did()) => { + ty::Adt(adt, args) if tcx.is_diagnostic_item(sym::Option, adt.did()) => { // Unwrap option - let ty::Adt(adt, _) = substs.type_at(0).kind() else { return false; }; + let ty::Adt(adt, _) = args.type_at(0).kind() else { + return false; + }; (adt, "") } @@ -1061,10 +1093,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (sym::NonZeroI128, tcx.types.i128), ]; - let Some((s, _)) = map - .iter() - .find(|&&(s, t)| self.tcx.is_diagnostic_item(s, adt.did()) && self.can_coerce(expr_ty, t)) - else { return false; }; + let Some((s, _)) = map.iter().find(|&&(s, t)| { + self.tcx.is_diagnostic_item(s, adt.did()) && self.can_coerce(expr_ty, t) + }) else { + return false; + }; let path = self.tcx.def_path_str(adt.non_enum_variant().def_id); @@ -1152,7 +1185,9 @@ 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) else { + let Some(Node::Param(hir::Param { hir_id: param_hir_id, .. })) = + self.tcx.hir().find(local_parent) + else { return None; }; @@ -1161,7 +1196,8 @@ 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) else { + })) = self.tcx.hir().find(param_parent) + else { return None; }; @@ -1174,7 +1210,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .. })), 1, - ) = (hir, closure_params_len) else { + ) = (hir, closure_params_len) + else { return None; }; @@ -1198,39 +1235,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - pub(crate) fn maybe_get_struct_pattern_shorthand_field( - &self, - expr: &hir::Expr<'_>, - ) -> Option { - let hir = self.tcx.hir(); - let local = match expr { - hir::Expr { - kind: - hir::ExprKind::Path(hir::QPath::Resolved( - None, - hir::Path { - res: hir::def::Res::Local(_), - segments: [hir::PathSegment { ident, .. }], - .. - }, - )), - .. - } => Some(ident), - _ => None, - }?; - - match hir.find_parent(expr.hir_id)? { - Node::ExprField(field) => { - if field.ident.name == local.name && field.is_shorthand { - return Some(local.name); - } - } - _ => {} - } - - None - } - /// If the given `HirId` corresponds to a block with a trailing expression, return that expression pub(crate) fn maybe_get_block_expr( &self, @@ -1425,7 +1429,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); } - let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) { + let prefix = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) { Some(ident) => format!("{ident}: "), None => String::new(), }; @@ -1619,7 +1623,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) }; - let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) { + let prefix = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) { Some(ident) => format!("{ident}: "), None => String::new(), }; @@ -2028,11 +2032,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !hir::is_range_literal(expr) { return; } - let hir::ExprKind::Struct( - hir::QPath::LangItem(LangItem::Range, ..), - [start, end], - _, - ) = expr.kind else { return; }; + let hir::ExprKind::Struct(hir::QPath::LangItem(LangItem::Range, ..), [start, end], _) = + expr.kind + else { + return; + }; let parent = self.tcx.hir().parent_id(expr.hir_id); if let Some(hir::Node::ExprField(_)) = self.tcx.hir().find(parent) { // Ignore `Foo { field: a..Default::default() }` @@ -2048,8 +2052,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // cannot guide the method probe. expectation = None; } - let hir::ExprKind::Call(method_name, _) = expr.kind else { return; }; - let ty::Adt(adt, _) = checked_ty.kind() else { return; }; + let hir::ExprKind::Call(method_name, _) = expr.kind else { + return; + }; + let ty::Adt(adt, _) = checked_ty.kind() else { + return; + }; if self.tcx.lang_items().range_struct() != Some(adt.did()) { return; } @@ -2059,8 +2067,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } // Check if start has method named end. - let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = method_name.kind else { return; }; - let [hir::PathSegment { ident, .. }] = p.segments else { return; }; + let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = method_name.kind else { + return; + }; + let [hir::PathSegment { ident, .. }] = p.segments else { + return; + }; let self_ty = self.typeck_results.borrow().expr_ty(start.expr); let Ok(_pick) = self.lookup_probe_for_diagnostic( *ident, @@ -2068,7 +2080,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr, probe::ProbeScope::AllTraits, expectation, - ) else { return; }; + ) else { + return; + }; let mut sugg = "."; let mut span = start.expr.span.between(end.expr.span); if span.lo() + BytePos(2) == span.hi() { @@ -2097,17 +2111,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !checked_ty.is_unit() { return; } - let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind else { return; }; - let hir::def::Res::Local(hir_id) = path.res else { return; }; + let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind else { + return; + }; + let hir::def::Res::Local(hir_id) = path.res else { + return; + }; let Some(hir::Node::Pat(pat)) = self.tcx.hir().find(hir_id) else { return; }; - let Some(hir::Node::Local(hir::Local { - ty: None, - init: Some(init), - .. - })) = self.tcx.hir().find_parent(pat.hir_id) else { return; }; - let hir::ExprKind::Block(block, None) = init.kind else { return; }; + let Some(hir::Node::Local(hir::Local { ty: None, init: Some(init), .. })) = + self.tcx.hir().find_parent(pat.hir_id) + else { + return; + }; + let hir::ExprKind::Block(block, None) = init.kind else { + return; + }; if block.expr.is_some() { return; } @@ -2115,8 +2135,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(block.span, "this empty block is missing a tail expression"); return; }; - let hir::StmtKind::Semi(tail_expr) = stmt.kind else { return; }; - let Some(ty) = self.node_ty_opt(tail_expr.hir_id) else { return; }; + let hir::StmtKind::Semi(tail_expr) = stmt.kind else { + return; + }; + let Some(ty) = self.node_ty_opt(tail_expr.hir_id) else { + return; + }; if self.can_eq(self.param_env, expected_ty, ty) { err.span_suggestion_short( stmt.span.with_lo(tail_expr.span.hi()), @@ -2135,7 +2159,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &hir::Expr<'_>, checked_ty: Ty<'tcx>, ) { - let Some(hir::Node::Expr(parent_expr)) = self.tcx.hir().find_parent(expr.hir_id) else { return; }; + let Some(hir::Node::Expr(parent_expr)) = self.tcx.hir().find_parent(expr.hir_id) else { + return; + }; enum CallableKind { Function, Method, @@ -2151,7 +2177,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } let fn_sig = fn_ty.fn_sig(self.tcx).skip_binder(); - let Some(&arg) = fn_sig.inputs().get(arg_idx + if matches!(kind, CallableKind::Method) { 1 } else { 0 }) else { return; }; + let Some(&arg) = fn_sig + .inputs() + .get(arg_idx + if matches!(kind, CallableKind::Method) { 1 } else { 0 }) + else { + return; + }; if matches!(arg.kind(), ty::Param(_)) && fn_sig.output().contains(arg) && self.node_ty(args[arg_idx].hir_id) == checked_ty @@ -2185,8 +2216,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; match parent_expr.kind { hir::ExprKind::Call(fun, args) => { - let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = fun.kind else { return; }; - let hir::def::Res::Def(kind, def_id) = path.res else { return; }; + let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = fun.kind else { + return; + }; + let hir::def::Res::Def(kind, def_id) = path.res else { + return; + }; let callable_kind = if matches!(kind, hir::def::DefKind::Ctor(_, _)) { CallableKind::Constructor } else { @@ -2195,7 +2230,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { maybe_emit_help(def_id, path.segments[0].ident, args, callable_kind); } hir::ExprKind::MethodCall(method, _receiver, args, _span) => { - let Some(def_id) = self.typeck_results.borrow().type_dependent_def_id(parent_expr.hir_id) else { return; }; + let Some(def_id) = + self.typeck_results.borrow().type_dependent_def_id(parent_expr.hir_id) + else { + return; + }; maybe_emit_help(def_id, method.ident, args, CallableKind::Method) } _ => return, diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 05906a4b9..054d23c71 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -252,6 +252,46 @@ impl HelpUseLatestEdition { } } +#[derive(Subdiagnostic)] +pub enum OptionResultRefMismatch { + #[suggestion( + hir_typeck_option_result_copied, + code = ".copied()", + style = "verbose", + applicability = "machine-applicable" + )] + Copied { + #[primary_span] + span: Span, + def_path: String, + }, + #[suggestion( + hir_typeck_option_result_cloned, + code = ".cloned()", + style = "verbose", + applicability = "machine-applicable" + )] + Cloned { + #[primary_span] + span: Span, + def_path: String, + }, + // FIXME: #114050 + // #[suggestion( + // hir_typeck_option_result_asref, + // code = ".as_ref()", + // style = "verbose", + // applicability = "machine-applicable" + // )] + // AsRef { + // #[primary_span] + // span: Span, + // def_path: String, + // expected_ty: Ty<'tcx>, + // expr_ty: Ty<'tcx>, + // }, +} + #[derive(Diagnostic)] #[diag(hir_typeck_const_select_must_be_const)] #[help] diff --git a/compiler/rustc_hir_typeck/src/expectation.rs b/compiler/rustc_hir_typeck/src/expectation.rs index 4f086cf59..35e5fb769 100644 --- a/compiler/rustc_hir_typeck/src/expectation.rs +++ b/compiler/rustc_hir_typeck/src/expectation.rs @@ -21,8 +21,6 @@ pub enum Expectation<'tcx> { /// This rvalue expression will be wrapped in `&` or `Box` and coerced /// to `&Ty` or `Box`, respectively. `Ty` is `[A]` or `Trait`. ExpectRvalueLikeUnsized(Ty<'tcx>), - - IsLast(Span), } impl<'a, 'tcx> Expectation<'tcx> { @@ -88,13 +86,12 @@ impl<'a, 'tcx> Expectation<'tcx> { ExpectCastableToType(t) => ExpectCastableToType(fcx.resolve_vars_if_possible(t)), ExpectHasType(t) => ExpectHasType(fcx.resolve_vars_if_possible(t)), ExpectRvalueLikeUnsized(t) => ExpectRvalueLikeUnsized(fcx.resolve_vars_if_possible(t)), - IsLast(sp) => IsLast(sp), } } pub(super) fn to_option(self, fcx: &FnCtxt<'a, 'tcx>) -> Option> { match self.resolve(fcx) { - NoExpectation | IsLast(_) => None, + NoExpectation => None, ExpectCastableToType(ty) | ExpectHasType(ty) | ExpectRvalueLikeUnsized(ty) => Some(ty), } } @@ -106,9 +103,7 @@ impl<'a, 'tcx> Expectation<'tcx> { pub(super) fn only_has_type(self, fcx: &FnCtxt<'a, 'tcx>) -> Option> { match self { ExpectHasType(ty) => Some(fcx.resolve_vars_if_possible(ty)), - NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) | IsLast(_) => { - None - } + NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) => None, } } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 72b29f7b6..7cea40fdd 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -13,7 +13,7 @@ use crate::errors::{ YieldExprOutsideOfGenerator, }; use crate::fatally_break_rust; -use crate::method::SelfSource; +use crate::method::{MethodCallComponents, SelfSource}; use crate::type_error_struct; use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation}; use crate::{ @@ -44,7 +44,7 @@ use rustc_infer::traits::ObligationCause; use rustc_middle::middle::stability; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase}; use rustc_middle::ty::error::TypeError::FieldMisMatch; -use rustc_middle::ty::subst::SubstsRef; +use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, AdtKind, Ty, TypeVisitableExt}; use rustc_session::errors::ExprParenthesesNeeded; use rustc_session::parse::feature_err; @@ -60,28 +60,13 @@ use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::{self, ObligationCauseCode}; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { - fn check_expr_eq_type(&self, expr: &'tcx hir::Expr<'tcx>, expected: Ty<'tcx>) { - let ty = self.check_expr_with_hint(expr, expected); - self.demand_eqtype(expr.span, expected, ty); - } - pub fn check_expr_has_type_or_error( &self, expr: &'tcx hir::Expr<'tcx>, - expected: Ty<'tcx>, - extend_err: impl FnMut(&mut Diagnostic), - ) -> Ty<'tcx> { - self.check_expr_meets_expectation_or_error(expr, ExpectHasType(expected), extend_err) - } - - fn check_expr_meets_expectation_or_error( - &self, - expr: &'tcx hir::Expr<'tcx>, - expected: Expectation<'tcx>, - mut extend_err: impl FnMut(&mut Diagnostic), + expected_ty: Ty<'tcx>, + extend_err: impl FnOnce(&mut Diagnostic), ) -> Ty<'tcx> { - let expected_ty = expected.to_option(&self).unwrap_or(self.tcx.types.bool); - let mut ty = self.check_expr_with_expectation(expr, expected); + let mut ty = self.check_expr_with_expectation(expr, ExpectHasType(expected_ty)); // While we don't allow *arbitrary* coercions here, we *do* allow // coercions from ! to `expected`. @@ -341,9 +326,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ExprKind::Cast(e, t) => self.check_expr_cast(e, t, expr), ExprKind::Type(e, t) => { - let ty = self.to_ty_saving_user_provided_ty(&t); - self.check_expr_eq_type(&e, ty); - ty + 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 } ExprKind::If(cond, then_expr, opt_else_expr) => { self.check_then_else(cond, then_expr, opt_else_expr, expr.span, expected) @@ -359,7 +345,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_expr_struct(expr, expected, qpath, fields, base_expr) } ExprKind::Field(base, field) => self.check_field(expr, &base, field, expected), - ExprKind::Index(base, idx) => self.check_expr_index(base, idx, expr), + ExprKind::Index(base, idx, brackets_span) => { + self.check_expr_index(base, idx, expr, brackets_span) + } ExprKind::Yield(value, ref src) => self.check_expr_yield(value, expr, src), hir::ExprKind::Err(guar) => Ty::new_error(tcx, guar), } @@ -593,8 +581,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We always require that the type provided as the value for // a type parameter outlives the moment of instantiation. - let substs = self.typeck_results.borrow().node_substs(expr.hir_id); - self.add_wf_bounds(substs, expr); + let args = self.typeck_results.borrow().node_args(expr.hir_id); + self.add_wf_bounds(args, expr); ty } @@ -650,7 +638,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); let Some(ctxt) = enclosing_breakables.opt_find_breakable(target_id) else { // Avoid ICE when `break` is inside a closure (#65383). - return Ty::new_error_with_message(tcx, + return Ty::new_error_with_message( + tcx, expr.span, "break was outside loop, but no error was emitted", ); @@ -665,7 +654,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { coerce.coerce_forced_unit( self, &cause, - &mut |mut err| { + |mut err| { self.suggest_mismatched_types_on_tail( &mut err, expr, ty, e_ty, target_id, ); @@ -761,7 +750,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { coercion.coerce_forced_unit( self, &cause, - &mut |db| { + |db| { let span = fn_decl.output.span(); if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { db.span_label( @@ -773,7 +762,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { true, ); } else { - coercion.coerce_forced_unit(self, &cause, &mut |_| (), true); + coercion.coerce_forced_unit(self, &cause, |_| (), true); } } self.tcx.types.never @@ -1280,7 +1269,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We could add a "consider `foo::`" 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.substs); + self.enforce_context_effects(expr.hir_id, expr.span, method.def_id, method.args); self.write_method_call(expr.hir_id, method); Ok(method) } @@ -1292,7 +1281,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { segment.ident, SelfSource::MethodCall(rcvr), error, - Some((rcvr, args)), + Some(MethodCallComponents { receiver: rcvr, args, full_expr: expr }), expected, false, ) { @@ -1333,7 +1322,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { t_cast, t.span, expr.span, - self.param_env.constness(), + hir::Constness::NotConst, ) { Ok(cast_check) => { debug!( @@ -1390,11 +1379,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let parent_node = self.tcx.hir().parent_iter(expr.hir_id).find(|(_, node)| { !matches!(node, hir::Node::Expr(hir::Expr { kind: hir::ExprKind::AddrOf(..), .. })) }); - let Some((_, + let Some(( + _, hir::Node::Local(hir::Local { ty: Some(ty), .. }) - | hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _), .. })) - ) = parent_node else { - return + | hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _, _), .. }), + )) = parent_node + else { + return; }; if let hir::TyKind::Array(_, length) = ty.peel_refs().kind && let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length @@ -1425,7 +1416,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Create a new function context. let def_id = block.def_id; - let fcx = FnCtxt::new(self, self.param_env.with_const(), def_id); + 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); @@ -1617,7 +1608,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // re-link the regions that EIfEO can erase. self.demand_eqtype(span, adt_ty_hint, adt_ty); - let ty::Adt(adt, substs) = adt_ty.kind() else { + let ty::Adt(adt, args) = adt_ty.kind() else { span_bug!(span, "non-ADT passed to check_expr_struct_fields"); }; let adt_kind = adt.adt_kind(); @@ -1646,7 +1637,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx.check_stability(v_field.did, Some(expr_id), field.span, None); } - self.field_ty(field.span, v_field, substs) + self.field_ty(field.span, v_field, args) } else { error_happened = true; let guar = if let Some(prev_span) = seen_fields.get(&ident) { @@ -1678,7 +1669,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(mut diag) = diag { if idx == ast_fields.len() - 1 { if remaining_fields.is_empty() { - self.suggest_fru_from_range(field, variant, substs, &mut diag); + self.suggest_fru_from_range(field, variant, args, &mut diag); diag.emit(); } else { diag.stash(field.span, StashKey::MaybeFruTypo); @@ -1718,7 +1709,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let fru_tys = if self.tcx.features().type_changing_struct_update { if adt.is_struct() { // Make some fresh substitutions for our ADT type. - let fresh_substs = self.fresh_substs_for_item(base_expr.span, adt.did()); + let fresh_args = self.fresh_args_for_item(base_expr.span, adt.did()); // We do subtyping on the FRU fields first, so we can // learn exactly what types we expect the base expr // needs constrained to be compatible with the struct @@ -1727,13 +1718,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .fields .iter() .map(|f| { - let fru_ty = self.normalize( - expr_span, - self.field_ty(base_expr.span, f, fresh_substs), - ); + let fru_ty = self + .normalize(expr_span, self.field_ty(base_expr.span, f, fresh_args)); let ident = self.tcx.adjust_ident(f.ident(self.tcx), variant.def_id); if let Some(_) = remaining_fields.remove(&ident) { - let target_ty = self.field_ty(base_expr.span, f, substs); + let target_ty = self.field_ty(base_expr.span, f, args); let cause = self.misc(base_expr.span); match self.at(&cause, self.param_env).sup( DefineOpaqueTypes::No, @@ -1760,7 +1749,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.resolve_vars_if_possible(fru_ty) }) .collect(); - // The use of fresh substs that we have subtyped against + // The use of fresh args that we have subtyped against // our base ADT type's fields allows us to guide inference // along so that, e.g. // ``` @@ -1778,7 +1767,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `MyStruct<'a, _, F2, C>`, as opposed to just `_`... // This is important to allow coercions to happen in // `other_struct` itself. See `coerce-in-base-expr.rs`. - let fresh_base_ty = Ty::new_adt(self.tcx, *adt, fresh_substs); + let fresh_base_ty = Ty::new_adt(self.tcx, *adt, fresh_args); self.check_expr_has_type_or_error( base_expr, self.resolve_vars_if_possible(fresh_base_ty), @@ -1810,10 +1799,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }); match adt_ty.kind() { - ty::Adt(adt, substs) if adt.is_struct() => variant + ty::Adt(adt, args) if adt.is_struct() => variant .fields .iter() - .map(|f| self.normalize(expr_span, f.ty(self.tcx, substs))) + .map(|f| self.normalize(expr_span, f.ty(self.tcx, args))) .collect(), _ => { self.tcx @@ -1841,7 +1830,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { remaining_fields, variant, ast_fields, - substs, + args, ); } } @@ -1878,7 +1867,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { remaining_fields: FxHashMap, variant: &'tcx ty::VariantDef, ast_fields: &'tcx [hir::ExprField<'tcx>], - substs: SubstsRef<'tcx>, + args: GenericArgsRef<'tcx>, ) { let len = remaining_fields.len(); @@ -1889,7 +1878,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut truncated_fields_error = String::new(); let remaining_fields_names = match &displayable_field_names[..] { - [field1] => format!("`{}`", field1), + [field1] => format!("`{field1}`"), [field1, field2] => format!("`{field1}` and `{field2}`"), [field1, field2, field3] => format!("`{field1}`, `{field2}` and `{field3}`"), _ => { @@ -1917,7 +1906,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(span, format!("missing {remaining_fields_names}{truncated_fields_error}")); if let Some(last) = ast_fields.last() { - self.suggest_fru_from_range(last, variant, substs, &mut err); + self.suggest_fru_from_range(last, variant, args, &mut err); } err.emit(); @@ -1929,7 +1918,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, last_expr_field: &hir::ExprField<'tcx>, variant: &ty::VariantDef, - substs: SubstsRef<'tcx>, + args: GenericArgsRef<'tcx>, err: &mut Diagnostic, ) { // I don't use 'is_range_literal' because only double-sided, half-open ranges count. @@ -1942,7 +1931,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { variant.fields.iter().find(|field| field.ident(self.tcx) == last_expr_field.ident) && let range_def_id = self.tcx.lang_items().range_struct() && variant_field - .and_then(|field| field.ty(self.tcx, substs).ty_adt_def()) + .and_then(|field| field.ty(self.tcx, args).ty_adt_def()) .map(|adt| adt.did()) != range_def_id { @@ -2116,16 +2105,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } _ => { - err.span_label(variant_ident_span, format!("`{adt}` defined here", adt = ty)); + err.span_label(variant_ident_span, format!("`{ty}` defined here")); err.span_label(field.ident.span, "field does not exist"); err.span_suggestion_verbose( expr_span, - format!( - "`{adt}` is a tuple {kind_name}, use the appropriate syntax", - adt = ty, - kind_name = kind_name, - ), - format!("{adt}(/* fields */)", adt = ty), + format!("`{ty}` is a tuple {kind_name}, use the appropriate syntax",), + format!("{ty}(/* fields */)"), Applicability::HasPlaceholders, ); } @@ -2242,7 +2227,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // dynamic limit, to never omit just one field let limit = if names.len() == 6 { 6 } else { 5 }; let mut display = - names.iter().take(limit).map(|n| format!("`{}`", n)).collect::>().join(", "); + names.iter().take(limit).map(|n| format!("`{n}`")).collect::>().join(", "); if names.len() > limit { display = format!("{} ... and {} others", display, names.len() - limit); } @@ -2265,7 +2250,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { while let Some((deref_base_ty, _)) = autoderef.next() { debug!("deref_base_ty: {:?}", deref_base_ty); match deref_base_ty.kind() { - ty::Adt(base_def, substs) if !base_def.is_enum() => { + 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 (ident, def_scope) = @@ -2275,7 +2260,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter_enumerated() .find(|(_, f)| f.ident(self.tcx).normalize_to_macros_2_0() == ident) { - let field_ty = self.field_ty(expr.span, field, substs); + let field_ty = self.field_ty(expr.span, field, args); // Save the index of all fields regardless of their visibility in case // of error recovery. self.write_field_index(expr.hir_id, index); @@ -2416,7 +2401,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base: &'tcx hir::Expr<'tcx>, ty: Ty<'tcx>, ) { - let Some(output_ty) = self.get_impl_future_output_ty(ty) else { return; }; + let Some(output_ty) = self.get_impl_future_output_ty(ty) else { + return; + }; let mut add_label = true; if let ty::Adt(def, _) = output_ty.kind() { // no field access on enum type @@ -2711,7 +2698,7 @@ 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, substs)) = + if let Some((fields, args)) = self.get_field_candidates_considering_privacy(span, expr_t, mod_id) { let candidate_fields: Vec<_> = fields @@ -2720,7 +2707,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, &|candidate_field, _| candidate_field.ident(self.tcx()) == field, candidate_field, - substs, + args, vec![], mod_id, ) @@ -2775,12 +2762,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, base_ty: Ty<'tcx>, mod_id: DefId, - ) -> Option<(impl Iterator + 'tcx, SubstsRef<'tcx>)> { + ) -> Option<(impl Iterator + 'tcx, 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, substs) if !base_def.is_enum() => { + 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 @@ -2795,7 +2782,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .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), - substs, + args, )); } _ => {} @@ -2811,7 +2798,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, matches: &impl Fn(&ty::FieldDef, Ty<'tcx>) -> bool, candidate_field: &ty::FieldDef, - subst: SubstsRef<'tcx>, + subst: GenericArgsRef<'tcx>, mut field_path: Vec, mod_id: DefId, ) -> Option> { @@ -2855,6 +2842,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base: &'tcx hir::Expr<'tcx>, idx: &'tcx hir::Expr<'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); @@ -2888,7 +2876,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut err = type_error_struct!( self.tcx.sess, - expr.span, + brackets_span, base_t, E0608, "cannot index into a value of type `{base_t}`", @@ -2902,16 +2890,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) = lit.node && i < types.len().try_into().expect("expected tuple index to be < usize length") { - let snip = self.tcx.sess.source_map().span_to_snippet(base.span); - if let Ok(snip) = snip { - err.span_suggestion( - expr.span, - "to access tuple elements, use", - format!("{snip}.{i}"), - Applicability::MachineApplicable, - ); - needs_note = false; - } + + err.span_suggestion( + brackets_span, + "to access tuple elements, use", + format!(".{i}"), + Applicability::MachineApplicable, + ); + needs_note = false; } else if let ExprKind::Path(..) = idx.peel_borrows().kind { err.span_label(idx.span, "cannot access tuple elements at a variable index"); } @@ -2970,9 +2956,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.commit_if_ok(|_| { let ocx = ObligationCtxt::new(self); - let impl_substs = self.fresh_substs_for_item(base_expr.span, impl_def_id); + let impl_args = self.fresh_args_for_item(base_expr.span, impl_def_id); let impl_trait_ref = - self.tcx.impl_trait_ref(impl_def_id).unwrap().subst(self.tcx, impl_substs); + self.tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(self.tcx, impl_args); let cause = self.misc(base_expr.span); // Match the impl self type against the base ty. If this fails, @@ -2989,7 +2975,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Binder::dummy(ty::TraitPredicate { trait_ref: impl_trait_ref, polarity: ty::ImplPolarity::Positive, - constness: ty::BoundConstness::NotConst, }), |derived| { traits::ImplDerivedObligation(Box::new( @@ -3004,7 +2989,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) }, self.param_env, - self.tcx.predicates_of(impl_def_id).instantiate(self.tcx, impl_substs), + self.tcx.predicates_of(impl_def_id).instantiate(self.tcx, impl_args), )); // Normalize the output type, which we can use later on as the @@ -3012,7 +2997,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let element_ty = ocx.normalize( &cause, self.param_env, - Ty::new_projection(self.tcx, index_trait_output_def_id, impl_trait_ref.substs), + Ty::new_projection(self.tcx, index_trait_output_def_id, impl_trait_ref.args), ); let errors = ocx.select_where_possible(); @@ -3020,7 +3005,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // will still delay a span bug in `report_fulfillment_errors`. Ok::<_, NoSolution>(( self.err_ctxt().report_fulfillment_errors(&errors), - impl_trait_ref.substs.type_at(1), + impl_trait_ref.args.type_at(1), element_ty, )) }) @@ -3152,7 +3137,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let container = self.structurally_resolve_type(expr.span, current_container); match container.kind() { - ty::Adt(container_def, substs) if !container_def.is_enum() => { + 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 (ident, def_scope) = self.tcx.adjust_ident_and_get_scope(field, container_def.did(), block); @@ -3162,7 +3147,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter_enumerated() .find(|(_, f)| f.ident(self.tcx).normalize_to_macros_2_0() == ident) { - let field_ty = self.field_ty(expr.span, field, substs); + let field_ty = self.field_ty(expr.span, field, args); // FIXME: DSTs with static alignment should be allowed self.require_type_is_sized(field_ty, expr.span, traits::MiscObligation); diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 0d2e0602e..840910732 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -211,7 +211,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { self.select_from_expr(base); } - hir::ExprKind::Index(lhs, rhs) => { + hir::ExprKind::Index(lhs, rhs, _) => { // lhs[rhs] self.select_from_expr(lhs); self.consume_expr(rhs); @@ -549,7 +549,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // Select just those fields of the `with` // expression that will actually be used match with_place.place.ty().kind() { - ty::Adt(adt, substs) if adt.is_struct() => { + ty::Adt(adt, args) if adt.is_struct() => { // Consume those fields of the with expression that are needed. for (f_index, with_field) in adt.non_enum_variant().fields.iter_enumerated() { let is_mentioned = fields @@ -559,7 +559,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { let field_place = self.mc.cat_projection( &*with_expr, with_place.clone(), - with_field.ty(self.tcx(), substs), + with_field.ty(self.tcx(), args), ProjectionKind::Field(f_index, FIRST_VARIANT), ); self.delegate_consume(&field_place, field_place.hir_id); diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index a76db6e73..5b5986a34 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -1,8 +1,8 @@ use crate::FnCtxt; use rustc_data_structures::{ - fx::{FxHashMap, FxHashSet}, graph::WithSuccessors, graph::{iterate::DepthFirstSearch, vec_graph::VecGraph}, + unord::{UnordBag, UnordMap, UnordSet}, }; use rustc_middle::ty::{self, Ty}; @@ -83,7 +83,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { fn fallback_if_possible( &self, ty: Ty<'tcx>, - diverging_fallback: &FxHashMap, Ty<'tcx>>, + diverging_fallback: &UnordMap, Ty<'tcx>>, ) { // Careful: we do NOT shallow-resolve `ty`. We know that `ty` // is an unsolved variable, and we determine its fallback @@ -193,7 +193,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { fn calculate_diverging_fallback( &self, unsolved_variables: &[Ty<'tcx>], - ) -> FxHashMap, Ty<'tcx>> { + ) -> UnordMap, Ty<'tcx>> { debug!("calculate_diverging_fallback({:?})", unsolved_variables); // Construct a coercion graph where an edge `A -> B` indicates @@ -210,10 +210,10 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // // These variables are the ones that are targets for fallback to // either `!` or `()`. - let diverging_roots: FxHashSet = self + let diverging_roots: UnordSet = self .diverging_type_vars .borrow() - .iter() + .items() .map(|&ty| self.shallow_resolve(ty)) .filter_map(|ty| ty.ty_vid()) .map(|vid| self.root_var(vid)) @@ -284,8 +284,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // For each diverging variable, figure out whether it can // reach a member of N. If so, it falls back to `()`. Else // `!`. - let mut diverging_fallback = FxHashMap::default(); - diverging_fallback.reserve(diverging_vids.len()); + let mut diverging_fallback = UnordMap::with_capacity(diverging_vids.len()); for &diverging_vid in &diverging_vids { let diverging_ty = Ty::new_var(self.tcx, diverging_vid); let root_vid = self.root_var(diverging_vid); @@ -293,14 +292,19 @@ impl<'tcx> FnCtxt<'_, 'tcx> { .depth_first_search(root_vid) .any(|n| roots_reachable_from_non_diverging.visited(n)); - let mut found_infer_var_info = ty::InferVarInfo { self_in_trait: false, output: false }; + let infer_var_infos: UnordBag<_> = self + .inh + .infer_var_info + .borrow() + .items() + .filter(|&(vid, _)| self.infcx.root_var(*vid) == root_vid) + .map(|(_, info)| *info) + .collect(); - for (vid, info) in self.inh.infer_var_info.borrow().iter() { - if self.infcx.root_var(*vid) == root_vid { - found_infer_var_info.self_in_trait |= info.self_in_trait; - found_infer_var_info.output |= info.output; - } - } + let found_infer_var_info = ty::InferVarInfo { + self_in_trait: infer_var_infos.items().any(|info| info.self_in_trait), + output: infer_var_infos.items().any(|info| info.output), + }; if found_infer_var_info.self_in_trait && found_infer_var_info.output { // This case falls back to () to ensure that the code pattern in diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 9a80a9c93..28fe2e062 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -12,7 +12,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, GenericArg, Node, QPath}; use rustc_hir_analysis::astconv::generics::{ - check_generic_arg_count_for_call, create_substs_for_generic_args, + check_generic_arg_count_for_call, create_args_for_parent_generic_args, }; use rustc_hir_analysis::astconv::{ AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch, @@ -28,7 +28,7 @@ use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{ self, AdtKind, CanonicalUserType, GenericParamDefKind, Ty, TyCtxt, UserType, }; -use rustc_middle::ty::{GenericArgKind, SubstsRef, UserSelfTy, UserSubsts}; +use rustc_middle::ty::{GenericArgKind, GenericArgsRef, UserArgs, UserSelfTy}; use rustc_session::lint; use rustc_span::def_id::LocalDefId; use rustc_span::hygiene::DesugaringKind; @@ -61,7 +61,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind); - let msg = format!("unreachable {}", kind); + let msg = format!("unreachable {kind}"); self.tcx().struct_span_lint_hir( lint::builtin::UNREACHABLE_CODE, id, @@ -85,16 +85,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// to get more type information. // FIXME(-Ztrait-solver=next): A lot of the calls to this method should // probably be `try_structurally_resolve_type` or `structurally_resolve_type` instead. - pub(in super::super) fn resolve_vars_with_obligations(&self, ty: Ty<'tcx>) -> Ty<'tcx> { - self.resolve_vars_with_obligations_and_mutate_fulfillment(ty, |_| {}) - } - - #[instrument(skip(self, mutate_fulfillment_errors), level = "debug", ret)] - pub(in super::super) fn resolve_vars_with_obligations_and_mutate_fulfillment( - &self, - mut ty: Ty<'tcx>, - mutate_fulfillment_errors: impl Fn(&mut Vec>), - ) -> Ty<'tcx> { + #[instrument(skip(self), level = "debug", ret)] + pub(in super::super) fn resolve_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { // No Infer()? Nothing needs doing. if !ty.has_non_region_infer() { debug!("no inference var, nothing needs doing"); @@ -112,7 +104,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // possible. This can help substantially when there are // indirect dependencies that don't seem worth tracking // precisely. - self.select_obligations_where_possible(mutate_fulfillment_errors); + self.select_obligations_where_possible(|_| {}); self.resolve_vars_if_possible(ty) } @@ -134,7 +126,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub fn tag(&self) -> String { - format!("{:p}", self) + format!("{self:p}") } pub fn local_ty(&self, span: Span, nid: hir::HirId) -> Ty<'tcx> { @@ -169,18 +161,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[instrument(level = "debug", skip(self))] pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) { self.write_resolution(hir_id, Ok((DefKind::AssocFn, method.def_id))); - self.write_substs(hir_id, method.substs); + self.write_args(hir_id, method.args); } - pub fn write_substs(&self, node_id: hir::HirId, substs: SubstsRef<'tcx>) { - if !substs.is_empty() { - debug!("write_substs({:?}, {:?}) in fcx {}", node_id, substs, self.tag()); + pub fn write_args(&self, node_id: hir::HirId, args: GenericArgsRef<'tcx>) { + if !args.is_empty() { + debug!("write_args({:?}, {:?}) in fcx {}", node_id, args, self.tag()); - self.typeck_results.borrow_mut().node_substs_mut().insert(node_id, substs); + self.typeck_results.borrow_mut().node_args_mut().insert(node_id, args); } } - /// Given the substs that we just converted from the HIR, try to + /// Given the args that we just converted from the HIR, try to /// canonicalize them and store them as user-given substitutions /// (i.e., substitutions that must be respected by the NLL check). /// @@ -188,19 +180,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// occurred**, so that annotations like `Vec<_>` are preserved /// properly. #[instrument(skip(self), level = "debug")] - pub fn write_user_type_annotation_from_substs( + pub fn write_user_type_annotation_from_args( &self, hir_id: hir::HirId, def_id: DefId, - substs: SubstsRef<'tcx>, + args: GenericArgsRef<'tcx>, user_self_ty: Option>, ) { debug!("fcx {}", self.tag()); - if Self::can_contain_user_lifetime_bounds((substs, user_self_ty)) { + if Self::can_contain_user_lifetime_bounds((args, user_self_ty)) { let canonicalized = self.canonicalize_user_type_annotation(UserType::TypeOf( def_id, - UserSubsts { substs, user_self_ty }, + UserArgs { args, user_self_ty }, )); debug!(?canonicalized); self.write_user_type_annotation(hir_id, canonicalized); @@ -221,7 +213,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .user_provided_types_mut() .insert(hir_id, canonical_user_type_annotation); } else { - debug!("skipping identity substs"); + debug!("skipping identity args"); } } @@ -306,12 +298,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, span: Span, def_id: DefId, - substs: SubstsRef<'tcx>, + args: GenericArgsRef<'tcx>, ) -> ty::InstantiatedPredicates<'tcx> { let bounds = self.tcx.predicates_of(def_id); - let result = bounds.instantiate(self.tcx, substs); + let result = bounds.instantiate(self.tcx, args); let result = self.normalize(span, result); - debug!("instantiate_bounds(bounds={:?}, substs={:?}) = {:?}", bounds, substs, result); + debug!("instantiate_bounds(bounds={:?}, args={:?}) = {:?}", bounds, args, result); result } @@ -397,11 +389,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty.normalized } - pub(super) fn user_substs_for_adt(ty: RawTy<'tcx>) -> UserSubsts<'tcx> { + pub(super) fn user_args_for_adt(ty: RawTy<'tcx>) -> UserArgs<'tcx> { match (ty.raw.kind(), ty.normalized.kind()) { - (ty::Adt(_, substs), _) => UserSubsts { substs, user_self_ty: None }, - (_, ty::Adt(adt, substs)) => UserSubsts { - substs, + (ty::Adt(_, args), _) => UserArgs { args, user_self_ty: None }, + (_, ty::Adt(adt, args)) => UserArgs { + args, user_self_ty: Some(UserSelfTy { impl_def_id: adt.did(), self_ty: ty.raw }), }, _ => bug!("non-adt type {:?}", ty), @@ -489,9 +481,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); } - /// Registers obligations that all `substs` are well-formed. - pub fn add_wf_bounds(&self, substs: SubstsRef<'tcx>, expr: &hir::Expr<'_>) { - for arg in substs.iter().filter(|arg| { + /// Registers obligations that all `args` are well-formed. + pub fn add_wf_bounds(&self, args: GenericArgsRef<'tcx>, expr: &hir::Expr<'_>) { + for arg in args.iter().filter(|arg| { matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..)) }) { self.register_wf_obligation(arg, expr.span, traits::WellFormed(None)); @@ -505,9 +497,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, span: Span, field: &'tcx ty::FieldDef, - substs: SubstsRef<'tcx>, + args: GenericArgsRef<'tcx>, ) -> Ty<'tcx> { - self.normalize(span, field.ty(self.tcx, substs)) + self.normalize(span, field.ty(self.tcx, args)) } pub(in super::super) fn resolve_rvalue_scopes(&self, def_id: DefId) { @@ -554,11 +546,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!(?expr_def_id); // Create the `GeneratorWitness` type that we will unify with `interior`. - let substs = ty::InternalSubsts::identity_for_item( + let args = ty::GenericArgs::identity_for_item( self.tcx, self.tcx.typeck_root_def_id(expr_def_id.to_def_id()), ); - let witness = Ty::new_generator_witness_mir(self.tcx, expr_def_id.to_def_id(), substs); + let witness = Ty::new_generator_witness_mir(self.tcx, expr_def_id.to_def_id(), args); // Unify `interior` with `witness` and collect all the resulting obligations. let span = self.tcx.hir().body(body_id).value.span; @@ -626,8 +618,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match *self_ty.kind() { ty::Infer(ty::TyVar(found_vid)) => { - // FIXME: consider using `sub_root_var` here so we - // can see through subtyping. let found_vid = self.root_var(found_vid); debug!("self_type_matches_expected_vid - found_vid={:?}", found_vid); expected_vid == found_vid @@ -642,8 +632,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self_ty: ty::TyVid, ) -> impl DoubleEndedIterator> + Captures<'tcx> + 'b { - // FIXME: consider using `sub_root_var` here so we - // can see through subtyping. let ty_var_root = self.root_var(self_ty); trace!("pending_obligations = {:#?}", self.fulfillment_cx.borrow().pending_obligations()); @@ -737,7 +725,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // tests/ui/impl-trait/hidden-type-is-opaque-2.rs for examples that hit this path. if formal_ret.has_infer_types() { for ty in ret_ty.walk() { - if let ty::subst::GenericArgKind::Type(ty) = ty.unpack() + if let ty::GenericArgKind::Type(ty) = ty.unpack() && let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *ty.kind() && let Some(def_id) = def_id.as_local() && self.opaque_type_origin(def_id).is_some() { @@ -784,8 +772,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { self.tcx.type_of(def_id) }; - let substs = self.fresh_substs_for_item(span, def_id); - let ty = item_ty.subst(self.tcx, substs); + let args = self.fresh_args_for_item(span, def_id); + let ty = item_ty.instantiate(self.tcx, args); self.write_resolution(hir_id, Ok((def_kind, def_id))); @@ -802,9 +790,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => None, }; if let Some(code) = code { - self.add_required_obligations_with_code(span, def_id, substs, move |_, _| code.clone()); + self.add_required_obligations_with_code(span, def_id, args, move |_, _| code.clone()); } else { - self.add_required_obligations_for_hir(span, def_id, substs, hir_id); + self.add_required_obligations_for_hir(span, def_id, args, hir_id); } (Res::Def(def_kind, def_id), ty) @@ -860,7 +848,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .resolve_fully_qualified_call(span, item_name, ty.normalized, qself.span, hir_id) .and_then(|r| { // lint bare trait if the method is found in the trait - if span.edition().rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) { + if span.edition().at_least_rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) { diag.emit(); } Ok(r) @@ -890,7 +878,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // emit or cancel the diagnostic for bare traits - if span.edition().rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) { + if span.edition().at_least_rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) { if trait_missing_method { // cancel the diag for bare traits when meeting `MyTrait::missing_method` diag.cancel(); @@ -908,7 +896,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { error, None, Expectation::NoExpectation, - trait_missing_method && span.edition().rust_2021(), // emits missing method for trait only after edition 2021 + trait_missing_method && span.edition().at_least_rust_2021(), // emits missing method for trait only after edition 2021 ) { e.emit(); } @@ -1069,7 +1057,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else if let ExprKind::MethodCall(..) = rcvr.kind { err.span_note( sp, - modifies_rcvr_note.clone() + ", it is not meant to be used in method chains.", + modifies_rcvr_note + ", it is not meant to be used in method chains.", ); } else { err.span_note(sp, modifies_rcvr_note); @@ -1205,8 +1193,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let has_self = path_segs.last().is_some_and(|PathSeg(def_id, _)| tcx.generics_of(*def_id).has_self); - let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res { - let ty = self.handle_raw_ty(span, tcx.at(span).type_of(impl_def_id).subst_identity()); + let (res, self_ctor_args) = if let Res::SelfCtor(impl_def_id) = res { + let ty = + self.handle_raw_ty(span, tcx.at(span).type_of(impl_def_id).instantiate_identity()); match ty.normalized.ty_adt_def() { Some(adt_def) if adt_def.has_ctor() => { let (ctor_kind, ctor_def_id) = adt_def.non_enum_variant().ctor.unwrap(); @@ -1217,9 +1206,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .emit_err(CtorIsPrivate { span, def: tcx.def_path_str(adt_def.did()) }); } let new_res = Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id); - let user_substs = Self::user_substs_for_adt(ty); - user_self_ty = user_substs.user_self_ty; - (new_res, Some(user_substs.substs)) + let user_args = Self::user_args_for_adt(ty); + user_self_ty = user_args.user_self_ty; + (new_res, Some(user_args.args)) } _ => { let mut err = tcx.sess.struct_span_err( @@ -1324,7 +1313,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn inferred_kind( &mut self, - substs: Option<&[ty::GenericArg<'tcx>]>, + args: Option<&[ty::GenericArg<'tcx>]>, param: &ty::GenericParamDef, infer_args: bool, ) -> ty::GenericArg<'tcx> { @@ -1338,7 +1327,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If we have a default, then we it doesn't matter that we're not // inferring the type arguments: we provide the default where any // is missing. - tcx.type_of(param.def_id).subst(tcx, substs.unwrap()).into() + tcx.type_of(param.def_id).instantiate(tcx, args.unwrap()).into() } else { // If no type arguments were provided, we have to infer them. // This case also occurs as a result of some malformed input, e.g. @@ -1348,8 +1337,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } GenericParamDefKind::Const { has_default } => { - if !infer_args && has_default { - tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into() + if !infer_args + && has_default + && !tcx.has_attr(param.def_id, sym::rustc_host) + { + tcx.const_param_default(param.def_id) + .instantiate(tcx, args.unwrap()) + .into() } else { self.fcx.var_for_def(self.span, param) } @@ -1358,8 +1352,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - let substs_raw = self_ctor_substs.unwrap_or_else(|| { - create_substs_for_generic_args( + let args_raw = self_ctor_args.unwrap_or_else(|| { + create_args_for_parent_generic_args( tcx, def_id, &[], @@ -1376,20 +1370,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) }); - // First, store the "user substs" for later. - self.write_user_type_annotation_from_substs(hir_id, def_id, substs_raw, user_self_ty); + // First, store the "user args" for later. + self.write_user_type_annotation_from_args(hir_id, def_id, args_raw, user_self_ty); // Normalize only after registering type annotations. - let substs = self.normalize(span, substs_raw); + let args = self.normalize(span, args_raw); - self.add_required_obligations_for_hir(span, def_id, &substs, 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. let ty = tcx.type_of(def_id); - assert!(!substs.has_escaping_bound_vars()); + assert!(!args.has_escaping_bound_vars()); assert!(!ty.skip_binder().has_escaping_bound_vars()); - let ty_substituted = self.normalize(span, ty.subst(tcx, substs)); + let ty_substituted = self.normalize(span, ty.instantiate(tcx, args)); if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty { // In the case of `Foo::method` and `>::method`, if `method` @@ -1397,7 +1391,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // type parameters, which we can infer by unifying the provided `Self` // with the substituted impl type. // This also occurs for an enum variant on a type alias. - let impl_ty = self.normalize(span, tcx.type_of(impl_def_id).subst(tcx, substs)); + let impl_ty = self.normalize(span, tcx.type_of(impl_def_id).instantiate(tcx, args)); let self_ty = self.normalize(span, self_ty); match self.at(&self.misc(span), self.param_env).eq( DefineOpaqueTypes::No, @@ -1409,9 +1403,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.sess.delay_span_bug( span, format!( - "instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?", - self_ty, - impl_ty, + "instantiate_value_path: (UFCS) {self_ty:?} was a subtype of {impl_ty:?} but now is not?", ), ); } @@ -1419,7 +1411,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } debug!("instantiate_value_path: type of {:?} is {:?}", hir_id, ty_substituted); - self.write_substs(hir_id, substs); + self.write_args(hir_id, args); (ty_substituted, res) } @@ -1429,10 +1421,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, span: Span, def_id: DefId, - substs: SubstsRef<'tcx>, + args: GenericArgsRef<'tcx>, hir_id: hir::HirId, ) { - self.add_required_obligations_with_code(span, def_id, substs, |idx, span| { + self.add_required_obligations_with_code(span, def_id, args, |idx, span| { if span.is_dummy() { ObligationCauseCode::ExprItemObligation(def_id, hir_id, idx) } else { @@ -1441,17 +1433,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) } - #[instrument(level = "debug", skip(self, code, span, substs))] + #[instrument(level = "debug", skip(self, code, span, args))] fn add_required_obligations_with_code( &self, span: Span, def_id: DefId, - substs: SubstsRef<'tcx>, + args: GenericArgsRef<'tcx>, code: impl Fn(usize, Span) -> ObligationCauseCode<'tcx>, ) { let param_env = self.param_env; - let bounds = self.instantiate_bounds(span, def_id, &substs); + let bounds = self.instantiate_bounds(span, def_id, &args); for obligation in traits::predicates_for_generics( |idx, predicate_span| { @@ -1460,10 +1452,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { param_env, bounds, ) { - // N.B. We are remapping all predicates to non-const since we don't know if we just - // want them as function pointers or we are calling them from a const-context. The - // actual checking will occur in `rustc_const_eval::transform::check_consts`. - self.register_predicate(obligation.without_const(self.tcx)); + self.register_predicate(obligation); } } @@ -1476,7 +1465,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.kind() + && let ty::Alias(ty::Projection | ty::Inherent | ty::Weak, _) = 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 ed9bb4945..c44d12e61 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 @@ -2,7 +2,7 @@ use crate::FnCtxt; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::DefId; -use rustc_infer::traits::ObligationCauseCode; +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_trait_selection::traits; @@ -14,19 +14,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, error: &mut traits::FulfillmentError<'tcx>, ) -> bool { - let (traits::ExprItemObligation(def_id, hir_id, idx) | traits::ExprBindingObligation(def_id, _, hir_id, idx)) - = *error.obligation.cause.code().peel_derives() else { return false; }; + let (traits::ExprItemObligation(def_id, hir_id, idx) + | traits::ExprBindingObligation(def_id, _, hir_id, idx)) = + *error.obligation.cause.code().peel_derives() + else { + return false; + }; let hir = self.tcx.hir(); - let hir::Node::Expr(expr) = hir.get(hir_id) else { return false; }; + let hir::Node::Expr(expr) = hir.get(hir_id) else { + return false; + }; - let Some(unsubstituted_pred) = - self.tcx.predicates_of(def_id).instantiate_identity(self.tcx).predicates.into_iter().nth(idx) - else { return false; }; + let Some(unsubstituted_pred) = self + .tcx + .predicates_of(def_id) + .instantiate_identity(self.tcx) + .predicates + .into_iter() + .nth(idx) + else { + return false; + }; let generics = self.tcx.generics_of(def_id); - let predicate_substs = match unsubstituted_pred.kind().skip_binder() { - ty::ClauseKind::Trait(pred) => pred.trait_ref.substs.to_vec(), - ty::ClauseKind::Projection(pred) => pred.projection_ty.substs.to_vec(), + let predicate_args = match unsubstituted_pred.kind().skip_binder() { + ty::ClauseKind::Trait(pred) => pred.trait_ref.args.to_vec(), + ty::ClauseKind::Projection(pred) => pred.projection_ty.args.to_vec(), ty::ClauseKind::ConstArgHasType(arg, ty) => { vec![ty.into(), arg.into()] } @@ -35,7 +48,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let find_param_matching = |matches: &dyn Fn(ty::ParamTerm) -> bool| { - predicate_substs.iter().find_map(|arg| { + predicate_args.iter().find_map(|arg| { arg.walk().find_map(|arg| { if let ty::GenericArgKind::Type(ty) = arg.unpack() && let ty::Param(param_ty) = *ty.kind() @@ -225,18 +238,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { param_to_point_at: ty::GenericArg<'tcx>, segment: &hir::PathSegment<'tcx>, ) -> bool { - let own_substs = self + let own_args = self .tcx .generics_of(def_id) - .own_substs(ty::InternalSubsts::identity_for_item(self.tcx, def_id)); - let Some((index, _)) = own_substs - .iter() - .enumerate() - .find(|(_, arg)| **arg == param_to_point_at) else { return false }; - let Some(arg) = segment - .args() - .args - .get(index) else { return false; }; + .own_args(ty::GenericArgs::identity_for_item(self.tcx, def_id)); + let Some((index, _)) = + own_args.iter().enumerate().find(|(_, arg)| **arg == param_to_point_at) + else { + return false; + }; + let Some(arg) = segment.args().args.get(index) else { + return false; + }; error.obligation.cause.span = arg .span() .find_ancestor_in_same_ctxt(error.obligation.cause.span) @@ -254,11 +267,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { type BreakTy = ty::GenericArg<'tcx>; fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow { if let Some(origin) = self.0.type_var_origin(ty) - && let rustc_infer::infer::type_variable::TypeVariableOriginKind::TypeParameterDefinition(_, def_id) = - origin.kind + && let TypeVariableOriginKind::TypeParameterDefinition(_, def_id) = origin.kind && let generics = self.0.tcx.generics_of(self.1) && let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id) - && let Some(subst) = ty::InternalSubsts::identity_for_item(self.0.tcx, self.1) + && let Some(subst) = ty::GenericArgs::identity_for_item(self.0.tcx, self.1) .get(index as usize) { ControlFlow::Break(*subst) @@ -298,13 +310,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)> { let def = self.tcx.adt_def(def_id); - let identity_substs = ty::InternalSubsts::identity_for_item(self.tcx, def_id); + let identity_args = ty::GenericArgs::identity_for_item(self.tcx, def_id); let fields_referencing_param: Vec<_> = def .variant_with_id(variant_def_id) .fields .iter() .filter(|field| { - let field_ty = field.ty(self.tcx, identity_substs); + let field_ty = field.ty(self.tcx, identity_args); find_param_in_ty(field_ty.into(), param_to_point_at) }) .collect(); @@ -315,7 +327,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // same rules that check_expr_struct uses for macro hygiene. if self.tcx.adjust_ident(expr_field.ident, variant_def_id) == field.ident(self.tcx) { - return Some((expr_field.expr, self.tcx.type_of(field.did).subst_identity())); + return Some(( + expr_field.expr, + self.tcx.type_of(field.did).instantiate_identity(), + )); } } } @@ -342,7 +357,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { receiver: Option<&'tcx hir::Expr<'tcx>>, args: &'tcx [hir::Expr<'tcx>], ) -> bool { - let ty = self.tcx.type_of(def_id).subst_identity(); + let ty = self.tcx.type_of(def_id).instantiate_identity(); if !ty.is_fn() { return false; } @@ -484,7 +499,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::TraitRef::new( self.tcx, obligation.impl_or_alias_def_id, - ty::InternalSubsts::identity_for_item(self.tcx, obligation.impl_or_alias_def_id), + ty::GenericArgs::identity_for_item(self.tcx, obligation.impl_or_alias_def_id), ) } else { self.tcx @@ -573,9 +588,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Find out which of `in_ty_elements` refer to `param`. // FIXME: It may be better to take the first if there are multiple, // just so that the error points to a smaller expression. - let Some((drill_expr, drill_ty)) = is_iterator_singleton(expr_elements.iter().zip( in_ty_elements.iter()).filter(|(_expr_elem, in_ty_elem)| { - find_param_in_ty((*in_ty_elem).into(), param) - })) else { + let Some((drill_expr, drill_ty)) = + is_iterator_singleton(expr_elements.iter().zip(in_ty_elements.iter()).filter( + |(_expr_elem, in_ty_elem)| find_param_in_ty((*in_ty_elem).into(), param), + )) + else { // The param is not mentioned, or it is mentioned in multiple indexes. return Err(expr); }; @@ -594,7 +611,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { // First, confirm that this struct is the same one as in the types, and if so, // find the right variant. - let Res::Def(expr_struct_def_kind, expr_struct_def_id) = self.typeck_results.borrow().qpath_res(expr_struct_path, expr.hir_id) else { + let Res::Def(expr_struct_def_kind, expr_struct_def_id) = + self.typeck_results.borrow().qpath_res(expr_struct_path, expr.hir_id) + else { return Err(expr); }; @@ -621,16 +640,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We need to know which of the generic parameters mentions our target param. // We expect that at least one of them does, since it is expected to be mentioned. - let Some((drill_generic_index, generic_argument_type)) = - is_iterator_singleton( - in_ty_adt_generic_args.iter().enumerate().filter( - |(_index, in_ty_generic)| { - find_param_in_ty(*in_ty_generic, param) - }, - ), - ) else { - return Err(expr); - }; + let Some((drill_generic_index, generic_argument_type)) = is_iterator_singleton( + in_ty_adt_generic_args + .iter() + .enumerate() + .filter(|(_index, in_ty_generic)| find_param_in_ty(*in_ty_generic, param)), + ) else { + return Err(expr); + }; let struct_generic_parameters: &ty::Generics = self.tcx.generics_of(in_ty_adt.did()); if drill_generic_index >= struct_generic_parameters.params.len() { @@ -703,7 +720,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // This is (possibly) a constructor call, like `Some(...)` or `MyStruct(a, b, c)`. - let Res::Def(expr_struct_def_kind, expr_ctor_def_id) = self.typeck_results.borrow().qpath_res(expr_callee_path, expr_callee.hir_id) else { + let Res::Def(expr_struct_def_kind, expr_ctor_def_id) = + self.typeck_results.borrow().qpath_res(expr_callee_path, expr_callee.hir_id) + else { return Err(expr); }; @@ -744,16 +763,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We need to know which of the generic parameters mentions our target param. // We expect that at least one of them does, since it is expected to be mentioned. - let Some((drill_generic_index, generic_argument_type)) = - is_iterator_singleton( - in_ty_adt_generic_args.iter().enumerate().filter( - |(_index, in_ty_generic)| { - find_param_in_ty(*in_ty_generic, param) - }, - ), - ) else { - return Err(expr); - }; + let Some((drill_generic_index, generic_argument_type)) = is_iterator_singleton( + in_ty_adt_generic_args + .iter() + .enumerate() + .filter(|(_index, in_ty_generic)| find_param_in_ty(*in_ty_generic, param)), + ) else { + return Err(expr); + }; let struct_generic_parameters: &ty::Generics = self.tcx.generics_of(in_ty_adt.did()); if drill_generic_index >= struct_generic_parameters.params.len() { @@ -794,7 +811,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter() .map(|field| field.ty(self.tcx, *in_ty_adt_generic_args)) .enumerate() - .filter(|(_index, field_type)| find_param_in_ty((*field_type).into(), param)) + .filter(|(_index, field_type)| find_param_in_ty((*field_type).into(), param)), ) else { return Err(expr); }; @@ -846,7 +863,7 @@ fn find_param_in_ty<'tcx>( // This logic may seem a bit strange, but typically when // we have a projection type in a function signature, the // argument that's being passed into that signature is - // not actually constraining that projection's substs in + // not actually constraining that projection's args in // a meaningful way. So we skip it, and see improvements // in some UI tests. walk.skip_current_subtree(); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 41f5fafe7..4def78673 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -45,12 +45,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("FnCtxt::check_casts: {} deferred checks", deferred_cast_checks.len()); for cast in deferred_cast_checks.drain(..) { - let prev_env = self.param_env; - self.param_env = self.param_env.with_constness(cast.constness); - cast.check(self); - - self.param_env = prev_env; } *self.deferred_cast_checks.borrow_mut() = deferred_cast_checks; @@ -93,7 +88,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Expectation<'tcx>, ) -> Ty<'tcx> { let has_error = match method { - Ok(method) => method.substs.references_error() || method.sig.references_error(), + Ok(method) => method.args.references_error() || method.sig.references_error(), Err(_) => true, }; if has_error { @@ -265,9 +260,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // fulfillment error to be more accurate. let coerced_ty = self.resolve_vars_with_obligations(coerced_ty); - let coerce_error = self - .try_coerce(provided_arg, checked_ty, coerced_ty, AllowTwoPhase::Yes, None) - .err(); + let coerce_error = + self.coerce(provided_arg, checked_ty, coerced_ty, AllowTwoPhase::Yes, None).err(); if coerce_error.is_some() { return Compatibility::Incompatible(coerce_error); @@ -524,7 +518,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // suggestions and labels are (more) correct when an arg is a // macro invocation. let normalize_span = |span: Span| -> Span { - let normalized_span = span.find_ancestor_inside(error_span).unwrap_or(span); + let normalized_span = span.find_ancestor_inside_same_ctxt(error_span).unwrap_or(span); // Sometimes macros mess up the spans, so do not normalize the // arg span to equal the error span, because that's less useful // than pointing out the arg expr in the wrong context. @@ -689,7 +683,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); err.span_label( full_call_span, - format!("arguments to this {} are incorrect", call_name), + format!("arguments to this {call_name} are incorrect"), ); } else { err = tcx.sess.struct_span_err_with_code( @@ -753,11 +747,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } errors.retain(|error| { - let Error::Invalid( - provided_idx, - expected_idx, - Compatibility::Incompatible(Some(e)), - ) = error else { return true }; + let Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(e))) = + error + else { + return true; + }; let (provided_ty, provided_span) = provided_arg_tys[*provided_idx]; let trace = mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty); @@ -796,10 +790,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None, None, ); - err.span_label( - full_call_span, - format!("arguments to this {} are incorrect", call_name), - ); + err.span_label(full_call_span, format!("arguments to this {call_name} are incorrect")); if let hir::ExprKind::MethodCall(_, rcvr, _, _) = call_expr.kind && provided_idx.as_usize() == expected_idx.as_usize() @@ -874,7 +865,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if ty.is_unit() { "()".to_string() } else if ty.is_suggestable(tcx, false) { - format!("/* {} */", ty) + format!("/* {ty} */") } else if let Some(fn_def_id) = fn_def_id && self.tcx.def_kind(fn_def_id).is_fn_like() && let self_implicit = @@ -931,14 +922,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (provided_ty, provided_span) = provided_arg_tys[arg_idx]; let provided_ty_name = if !has_error_or_infer([provided_ty]) { // FIXME: not suggestable, use something else - format!(" of type `{}`", provided_ty) + format!(" of type `{provided_ty}`") } else { "".to_string() }; - labels - .push((provided_span, format!("unexpected argument{}", provided_ty_name))); + labels.push((provided_span, format!("unexpected argument{provided_ty_name}"))); let mut span = provided_span; - if span.can_be_used_for_suggestions() { + if span.can_be_used_for_suggestions() + && error_span.can_be_used_for_suggestions() + { if arg_idx.index() > 0 && let Some((_, prev)) = provided_arg_tys .get(ProvidedIdx::from_usize(arg_idx.index() - 1) @@ -1009,11 +1001,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { args_span }; let rendered = if !has_error_or_infer([input_ty]) { - format!(" of type `{}`", input_ty) + format!(" of type `{input_ty}`") } else { "".to_string() }; - labels.push((span, format!("an argument{} is missing", rendered))); + labels.push((span, format!("an argument{rendered} is missing"))); suggestion_text = match suggestion_text { SuggestionText::None => SuggestionText::Provide(false), SuggestionText::Provide(_) => SuggestionText::Provide(true), @@ -1034,13 +1026,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let rendered = if !has_error_or_infer([first_expected_ty, second_expected_ty]) { format!( - " of type `{}` and `{}`", - first_expected_ty, second_expected_ty + " of type `{first_expected_ty}` and `{second_expected_ty}`" ) } else { "".to_string() }; - labels.push((span, format!("two arguments{} are missing", rendered))); + labels.push((span, format!("two arguments{rendered} are missing"))); suggestion_text = match suggestion_text { SuggestionText::None | SuggestionText::Provide(_) => { SuggestionText::Provide(true) @@ -1066,13 +1057,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { third_expected_ty, ]) { format!( - " of type `{}`, `{}`, and `{}`", - first_expected_ty, second_expected_ty, third_expected_ty + " of type `{first_expected_ty}`, `{second_expected_ty}`, and `{third_expected_ty}`" ) } else { "".to_string() }; - labels.push((span, format!("three arguments{} are missing", rendered))); + labels.push((span, format!("three arguments{rendered} are missing"))); suggestion_text = match suggestion_text { SuggestionText::None | SuggestionText::Provide(_) => { SuggestionText::Provide(true) @@ -1113,25 +1103,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (first_provided_ty, first_span) = provided_arg_tys[first_provided_idx]; let (_, first_expected_ty) = formal_and_expected_inputs[first_expected_idx]; let first_provided_ty_name = if !has_error_or_infer([first_provided_ty]) { - format!(", found `{}`", first_provided_ty) + format!(", found `{first_provided_ty}`") } else { String::new() }; labels.push(( first_span, - format!("expected `{}`{}", first_expected_ty, first_provided_ty_name), + format!("expected `{first_expected_ty}`{first_provided_ty_name}"), )); let (second_provided_ty, second_span) = provided_arg_tys[second_provided_idx]; let (_, second_expected_ty) = formal_and_expected_inputs[second_expected_idx]; let second_provided_ty_name = if !has_error_or_infer([second_provided_ty]) { - format!(", found `{}`", second_provided_ty) + format!(", found `{second_provided_ty}`") } else { String::new() }; labels.push(( second_span, - format!("expected `{}`{}", second_expected_ty, second_provided_ty_name), + format!("expected `{second_expected_ty}`{second_provided_ty_name}"), )); suggestion_text = match suggestion_text { @@ -1144,13 +1134,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (_, expected_ty) = formal_and_expected_inputs[dst_arg]; let (provided_ty, provided_span) = provided_arg_tys[dest_input]; let provided_ty_name = if !has_error_or_infer([provided_ty]) { - format!(", found `{}`", provided_ty) + format!(", found `{provided_ty}`") } else { String::new() }; labels.push(( provided_span, - format!("expected `{}`{}", expected_ty, provided_ty_name), + format!("expected `{expected_ty}`{provided_ty_name}"), )); } @@ -1231,22 +1221,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if let Some(suggestion_text) = suggestion_text { let source_map = self.sess().source_map(); - let (mut suggestion, suggestion_span) = - if let Some(call_span) = full_call_span.find_ancestor_inside(error_span) { - ("(".to_string(), call_span.shrink_to_hi().to(error_span.shrink_to_hi())) - } else { - ( - format!( - "{}(", - source_map.span_to_snippet(full_call_span).unwrap_or_else(|_| { - fn_def_id.map_or("".to_string(), |fn_def_id| { - tcx.item_name(fn_def_id).to_string() - }) + let (mut suggestion, suggestion_span) = if let Some(call_span) = + full_call_span.find_ancestor_inside_same_ctxt(error_span) + { + ("(".to_string(), call_span.shrink_to_hi().to(error_span.shrink_to_hi())) + } else { + ( + format!( + "{}(", + source_map.span_to_snippet(full_call_span).unwrap_or_else(|_| { + fn_def_id.map_or("".to_string(), |fn_def_id| { + tcx.item_name(fn_def_id).to_string() }) - ), - error_span, - ) - }; + }) + ), + error_span, + ) + }; let mut needs_comma = false; for (expected_idx, provided_idx) in matched_inputs.iter_enumerated() { if needs_comma { @@ -1366,29 +1357,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } Res::Def(DefKind::Variant, _) => match ty.normalized.ty_adt_def() { Some(adt) => { - Some((adt.variant_of_res(def), adt.did(), Self::user_substs_for_adt(ty))) + Some((adt.variant_of_res(def), adt.did(), Self::user_args_for_adt(ty))) } _ => bug!("unexpected type: {:?}", ty.normalized), }, - Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _) + Res::Def( + DefKind::Struct | DefKind::Union | DefKind::TyAlias { .. } | DefKind::AssocTy, + _, + ) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => match ty.normalized.ty_adt_def() { Some(adt) if !adt.is_enum() => { - Some((adt.non_enum_variant(), adt.did(), Self::user_substs_for_adt(ty))) + Some((adt.non_enum_variant(), adt.did(), Self::user_args_for_adt(ty))) } _ => None, }, _ => bug!("unexpected definition: {:?}", def), }; - if let Some((variant, did, ty::UserSubsts { substs, user_self_ty })) = variant { - debug!("check_struct_path: did={:?} substs={:?}", did, substs); + if let Some((variant, did, ty::UserArgs { args, user_self_ty })) = variant { + debug!("check_struct_path: did={:?} args={:?}", did, args); // Register type annotation. - self.write_user_type_annotation_from_substs(hir_id, did, substs, user_self_ty); + self.write_user_type_annotation_from_args(hir_id, did, args, user_self_ty); // Check bounds on type arguments used in the path. - self.add_required_obligations_for_hir(path_span, did, substs, hir_id); + self.add_required_obligations_for_hir(path_span, did, args, hir_id); Ok((variant, ty.normalized)) } else { @@ -1474,11 +1468,11 @@ 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); + 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); - if let Some(blk) = decl.els { + if let Some(blk) = decl.origin.try_get_else() { let previous_diverges = self.diverges.get(); let else_ty = self.check_block_with_expected(blk, NoExpectation); let cause = self.cause(blk.span, ObligationCauseCode::LetElse); @@ -1496,7 +1490,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_decl(local.into()); } - pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>, is_last: bool) { + pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>) { // Don't do all the complex logic below for `DeclItem`. match stmt.kind { hir::StmtKind::Item(..) => return, @@ -1523,14 +1517,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); } hir::StmtKind::Semi(ref expr) => { - // All of this is equivalent to calling `check_expr`, but it is inlined out here - // in order to capture the fact that this `match` is the last statement in its - // function. This is done for better suggestions to remove the `;`. - let expectation = match expr.kind { - hir::ExprKind::Match(..) if is_last => IsLast(stmt.span), - _ => NoExpectation, - }; - self.check_expr_with_expectation(expr, expectation); + self.check_expr(expr); } } @@ -1581,8 +1568,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ctxt = BreakableCtxt { coerce: Some(coerce), may_break: false }; let (ctxt, ()) = self.with_breakable_ctxt(blk.hir_id, ctxt, || { - for (pos, s) in blk.stmts.iter().enumerate() { - self.check_stmt(s, blk.stmts.len() - 1 == pos); + for s in blk.stmts { + self.check_stmt(s); } // check the tail expression **without** holding the @@ -1595,7 +1582,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let coerce = ctxt.coerce.as_mut().unwrap(); if let Some((tail_expr, tail_expr_ty)) = tail_expr_ty { let span = self.get_expr_coercion_span(tail_expr); - let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id)); + let cause = self.cause( + span, + ObligationCauseCode::BlockTailExpression(blk.hir_id, hir::MatchSource::Normal), + ); let ty_for_diagnostic = coerce.merged_ty(); // We use coerce_inner here because we want to augment the error // suggesting to wrap the block in square brackets if it might've @@ -1605,9 +1595,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &cause, Some(tail_expr), tail_expr_ty, - Some(&mut |diag: &mut Diagnostic| { + |diag| { self.suggest_block_to_brackets(diag, blk, tail_expr_ty, ty_for_diagnostic); - }), + }, false, ); } else { @@ -1644,7 +1634,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { coerce.coerce_forced_unit( self, &self.misc(sp), - &mut |err| { + |err| { if let Some(expected_ty) = expected.only_has_type(self) { if blk.stmts.is_empty() && blk.expr.is_none() { self.suggest_boxing_when_appropriate( @@ -1867,19 +1857,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if self.adjust_fulfillment_error_for_expr_obligation(error) || before_span != error.obligation.cause.span { - // Store both the predicate and the predicate *without constness* - // since sometimes we instantiate and check both of these in a - // method call, for example. remap_cause.insert(( before_span, error.obligation.predicate, error.obligation.cause.clone(), )); - remap_cause.insert(( - before_span, - error.obligation.predicate.without_const(self.tcx), - error.obligation.cause.clone(), - )); } else { // If it failed to be adjusted once around, it may be adjusted // via the "remap cause" mapping the second time... @@ -2031,7 +2013,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { ("closure", self.tcx.def_span(def_id)) }; - err.span_note(span, format!("{} defined here", kind)); + err.span_note(span, format!("{kind} defined here")); } else { err.span_note( self.tcx.def_span(def_id), diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 20b34df99..6a82b0021 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -288,21 +288,23 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { poly_trait_ref, ); - let item_substs = self.astconv().create_substs_for_associated_item( + let item_args = self.astconv().create_args_for_associated_item( span, item_def_id, item_segment, - trait_ref.substs, + trait_ref.args, ); - Ty::new_projection(self.tcx(), item_def_id, item_substs) + Ty::new_projection(self.tcx(), item_def_id, item_args) } fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option> { match ty.kind() { ty::Adt(adt_def, _) => Some(*adt_def), // FIXME(#104767): Should we handle bound regions here? - ty::Alias(ty::Projection | ty::Inherent, _) if !ty.has_escaping_bound_vars() => { + ty::Alias(ty::Projection | ty::Inherent | ty::Weak, _) + if !ty.has_escaping_bound_vars() => + { self.normalize(span, ty).ty_adt_def() } _ => None, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 79a7c0161..d2a53ee8b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1,8 +1,6 @@ use super::FnCtxt; -use crate::errors::{ - AddReturnTypeSuggestion, ExpectedReturnTypeLabel, SuggestBoxing, SuggestConvertViaMethod, -}; +use crate::errors; use crate::fluent_generated as fluent; use crate::method::probe::{IsSuggestion, Mode, ProbeScope}; use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX}; @@ -97,8 +95,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { found: Ty<'tcx>, can_satisfy: impl FnOnce(Ty<'tcx>) -> bool, ) -> bool { - let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(found) - else { return false; }; + let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(found) else { + return false; + }; if can_satisfy(output) { let (sugg_call, mut applicability) = match inputs.len() { 0 => ("".to_string(), Applicability::MachineApplicable), @@ -180,10 +179,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rhs_ty: Ty<'tcx>, can_satisfy: impl FnOnce(Ty<'tcx>, Ty<'tcx>) -> bool, ) -> bool { - let Some((_, lhs_output_ty, lhs_inputs)) = self.extract_callable_info(lhs_ty) - else { return false; }; - let Some((_, rhs_output_ty, rhs_inputs)) = self.extract_callable_info(rhs_ty) - else { return false; }; + let Some((_, lhs_output_ty, lhs_inputs)) = self.extract_callable_info(lhs_ty) else { + return false; + }; + let Some((_, rhs_output_ty, rhs_inputs)) = self.extract_callable_info(rhs_ty) else { + return false; + }; if can_satisfy(lhs_output_ty, rhs_output_ty) { let mut sugg = vec![]; @@ -392,9 +393,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { vec![(expr.span.shrink_to_hi(), format!(".{}()", conversion_method.name))] }; let struct_pat_shorthand_field = - self.maybe_get_struct_pattern_shorthand_field(expr); + self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr); if let Some(name) = struct_pat_shorthand_field { - sugg.insert(0, (expr.span.shrink_to_lo(), format!("{}: ", name))); + sugg.insert(0, (expr.span.shrink_to_lo(), format!("{name}: "))); } Some(sugg) }) @@ -431,7 +432,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 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 { - err.subdiagnostic(SuggestConvertViaMethod { + err.subdiagnostic(errors::SuggestConvertViaMethod { span: expr.span.shrink_to_hi(), sugg: ".as_ref()", expected, @@ -444,7 +445,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && self.can_eq(self.param_env, deref_ty, peeled) && error_tys_equate_as_ref { - err.subdiagnostic(SuggestConvertViaMethod { + err.subdiagnostic(errors::SuggestConvertViaMethod { span: expr.span.shrink_to_hi(), sugg: ".as_deref()", expected, @@ -478,23 +479,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { found_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, ) -> Option<(Ty<'tcx>, Ty<'tcx>, Option<(Ty<'tcx>, Ty<'tcx>)>)> { - let ty::Adt(found_adt, found_substs) = found_ty.peel_refs().kind() else { + let ty::Adt(found_adt, found_args) = found_ty.peel_refs().kind() else { return None; }; - let ty::Adt(expected_adt, expected_substs) = expected_ty.kind() else { + let ty::Adt(expected_adt, expected_args) = expected_ty.kind() else { return None; }; if self.tcx.is_diagnostic_item(sym::Option, found_adt.did()) && self.tcx.is_diagnostic_item(sym::Option, expected_adt.did()) { - Some((found_substs.type_at(0), expected_substs.type_at(0), None)) + Some((found_args.type_at(0), expected_args.type_at(0), None)) } else if self.tcx.is_diagnostic_item(sym::Result, found_adt.did()) && self.tcx.is_diagnostic_item(sym::Result, expected_adt.did()) { Some(( - found_substs.type_at(0), - expected_substs.type_at(0), - Some((found_substs.type_at(1), expected_substs.type_at(1))), + found_args.type_at(0), + expected_args.type_at(0), + Some((found_args.type_at(1), expected_args.type_at(1))), )) } else { None @@ -518,7 +519,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if self.can_coerce(Ty::new_box(self.tcx, found), expected) { let suggest_boxing = match found.kind() { ty::Tuple(tuple) if tuple.is_empty() => { - SuggestBoxing::Unit { start: span.shrink_to_lo(), end: span } + errors::SuggestBoxing::Unit { start: span.shrink_to_lo(), end: span } } ty::Generator(def_id, ..) if matches!( @@ -526,9 +527,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(GeneratorKind::Async(AsyncGeneratorKind::Closure)) ) => { - SuggestBoxing::AsyncBody + errors::SuggestBoxing::AsyncBody } - _ => SuggestBoxing::Other { start: span.shrink_to_lo(), end: span.shrink_to_hi() }, + _ => errors::SuggestBoxing::Other { + start: span.shrink_to_lo(), + end: span.shrink_to_hi(), + }, }; err.subdiagnostic(suggest_boxing); @@ -555,7 +559,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .take(4) .map(|(var_hir_id, upvar)| { let var_name = self.tcx.hir().name(*var_hir_id).to_string(); - let msg = format!("`{}` captured here", var_name); + let msg = format!("`{var_name}` captured here"); (upvar.span, msg) }) .collect::>(); @@ -635,7 +639,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // is and we were expecting a Box, ergo Pin>, we // 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) else { + let Some(Node::Expr(Expr { kind: ExprKind::Call(fn_name, _), .. })) = + self.tcx.hir().find(parent) + else { return false; }; match fn_name.kind { @@ -751,23 +757,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match &fn_decl.output { &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() && !can_suggest => { // `fn main()` must return `()`, do not suggest changing return type - err.subdiagnostic(ExpectedReturnTypeLabel::Unit { span }); + err.subdiagnostic(errors::ExpectedReturnTypeLabel::Unit { span }); return true; } &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => { if let Some(found) = found.make_suggestable(self.tcx, false) { - err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found: found.to_string() }); + err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span, found: found.to_string() }); return true; - } else if let ty::Closure(_, substs) = found.kind() + } else if let ty::Closure(_, args) = found.kind() // FIXME(compiler-errors): Get better at printing binders... - && let closure = substs.as_closure() + && let closure = args.as_closure() && closure.sig().is_suggestable(self.tcx, false) { - err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found: closure.print_as_impl_trait().to_string() }); + err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span, found: closure.print_as_impl_trait().to_string() }); return true; } else { // FIXME: if `found` could be `impl Iterator` we should suggest that. - err.subdiagnostic(AddReturnTypeSuggestion::MissingHere { span }); + err.subdiagnostic(errors::AddReturnTypeSuggestion::MissingHere { span }); return true } } @@ -789,10 +795,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!(?found); if found.is_suggestable(self.tcx, false) { if term.span.is_empty() { - err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found: found.to_string() }); + err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span, found: found.to_string() }); return true; } else { - err.subdiagnostic(ExpectedReturnTypeLabel::Other { span, expected }); + err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other { span, expected }); } } } @@ -808,7 +814,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = self.normalize(span, ty); let ty = self.tcx.erase_late_bound_regions(ty); if self.can_coerce(expected, ty) { - err.subdiagnostic(ExpectedReturnTypeLabel::Other { span, expected }); + err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other { span, expected }); self.try_suggest_return_impl_trait(err, expected, ty, fn_id); return true; } @@ -850,12 +856,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn( - hir::FnSig { decl: hir::FnDecl { inputs: fn_parameters, output: fn_return, .. }, .. }, + hir::FnSig { + decl: hir::FnDecl { inputs: fn_parameters, output: fn_return, .. }, + .. + }, hir::Generics { params, predicates, .. }, _body_id, ), .. - })) = fn_node else { return }; + })) = fn_node + else { + return; + }; if params.get(expected_ty_as_param.index as usize).is_none() { return; @@ -920,7 +932,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_suggestion( fn_return.span(), "consider using an impl return type", - format!("impl {}", all_bounds_str), + format!("impl {all_bounds_str}"), Applicability::MaybeIncorrect, ); } @@ -938,7 +950,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !expected.is_unit() { return; } - let found = self.resolve_vars_with_obligations(found); + let found = self.resolve_vars_if_possible(found); let in_loop = self.is_loop(id) || self @@ -982,14 +994,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let ty = self.normalize(expr.span, ty); if self.can_coerce(found, ty) { - err.multipart_suggestion( - "you might have meant to return this value", - vec![ - (expr.span.shrink_to_lo(), "return ".to_string()), - (expr.span.shrink_to_hi(), ";".to_string()), - ], - Applicability::MaybeIncorrect, - ); + if let Some(node) = self.tcx.hir().find(fn_id) + && let Some(owner_node) = node.as_owner() + && let Some(span) = expr.span.find_ancestor_inside(owner_node.span()) + { + err.multipart_suggestion( + "you might have meant to return this value", + vec![ + (span.shrink_to_lo(), "return ".to_string()), + (span.shrink_to_hi(), ";".to_string()), + ], + Applicability::MaybeIncorrect, + ); + } } } } @@ -1058,8 +1075,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) .must_apply_modulo_regions() { - let suggestion = match self.maybe_get_struct_pattern_shorthand_field(expr) { - Some(ident) => format!(": {}.clone()", ident), + let suggestion = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) { + Some(ident) => format!(": {ident}.clone()"), None => ".clone()".to_string() }; @@ -1074,68 +1091,55 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false } - pub(crate) fn suggest_copied_or_cloned( + pub(crate) fn suggest_copied_cloned_or_as_ref( &self, diag: &mut Diagnostic, expr: &hir::Expr<'_>, expr_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, ) -> bool { - let ty::Adt(adt_def, substs) = expr_ty.kind() else { return false; }; - let ty::Adt(expected_adt_def, expected_substs) = expected_ty.kind() else { return false; }; + let ty::Adt(adt_def, args) = expr_ty.kind() else { + return false; + }; + let ty::Adt(expected_adt_def, expected_args) = expected_ty.kind() else { + return false; + }; if adt_def != expected_adt_def { return false; } - let mut suggest_copied_or_cloned = || { - let expr_inner_ty = substs.type_at(0); - let expected_inner_ty = expected_substs.type_at(0); - if let &ty::Ref(_, ty, hir::Mutability::Not) = expr_inner_ty.kind() - && self.can_eq(self.param_env, ty, expected_inner_ty) - { - let def_path = self.tcx.def_path_str(adt_def.did()); - if self.type_is_copy_modulo_regions(self.param_env, ty) { - diag.span_suggestion_verbose( - expr.span.shrink_to_hi(), - format!( - "use `{def_path}::copied` to copy the value inside the `{def_path}`" - ), - ".copied()", - Applicability::MachineApplicable, - ); - return true; - } else if let Some(clone_did) = self.tcx.lang_items().clone_trait() - && rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions( - self, - self.param_env, - ty, - clone_did, - ) + if Some(adt_def.did()) == self.tcx.get_diagnostic_item(sym::Result) + && self.can_eq(self.param_env, args.type_at(1), expected_args.type_at(1)) + || Some(adt_def.did()) == self.tcx.get_diagnostic_item(sym::Option) + { + let expr_inner_ty = args.type_at(0); + let expected_inner_ty = expected_args.type_at(0); + if let &ty::Ref(_, ty, _mutability) = expr_inner_ty.kind() + && self.can_eq(self.param_env, ty, expected_inner_ty) { - diag.span_suggestion_verbose( - expr.span.shrink_to_hi(), - format!( - "use `{def_path}::cloned` to clone the value inside the `{def_path}`" - ), - ".cloned()", - Applicability::MachineApplicable, - ); + let def_path = self.tcx.def_path_str(adt_def.did()); + let span = expr.span.shrink_to_hi(); + let subdiag = if self.type_is_copy_modulo_regions(self.param_env, ty) { + errors::OptionResultRefMismatch::Copied { + span, def_path + } + } else if let Some(clone_did) = self.tcx.lang_items().clone_trait() + && rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions( + self, + self.param_env, + ty, + clone_did, + ) + { + errors::OptionResultRefMismatch::Cloned { + span, def_path + } + } else { + return false; + }; + diag.subdiagnostic(subdiag); return true; } - } - false - }; - - if let Some(result_did) = self.tcx.get_diagnostic_item(sym::Result) - && adt_def.did() == result_did - // Check that the error types are equal - && self.can_eq(self.param_env, substs.type_at(1), expected_substs.type_at(1)) - { - return suggest_copied_or_cloned(); - } else if let Some(option_did) = self.tcx.get_diagnostic_item(sym::Option) - && adt_def.did() == option_did - { - return suggest_copied_or_cloned(); } false @@ -1177,10 +1181,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ), )) { + let mut span = expr.span; + while expr.span.eq_ctxt(span) && let Some(parent_callsite) = span.parent_callsite() + { + span = parent_callsite; + } + let sugg = if expr.precedence().order() >= PREC_POSTFIX { - vec![(expr.span.shrink_to_hi(), ".into()".to_owned())] + vec![(span.shrink_to_hi(), ".into()".to_owned())] } else { - vec![(expr.span.shrink_to_lo(), "(".to_owned()), (expr.span.shrink_to_hi(), ").into()".to_owned())] + vec![(span.shrink_to_lo(), "(".to_owned()), (span.shrink_to_hi(), ").into()".to_owned())] }; diag.multipart_suggestion( format!("call `Into::into` on this expression to convert `{expr_ty}` into `{expected_ty}`"), @@ -1205,7 +1215,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return false; } - let ty::Adt(def, _) = expr_ty.peel_refs().kind() else { return false; }; + let ty::Adt(def, _) = expr_ty.peel_refs().kind() else { + return false; + }; if !self.tcx.is_diagnostic_item(sym::Option, def.did()) { return false; } @@ -1230,8 +1242,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return false; } - let suggestion = match self.maybe_get_struct_pattern_shorthand_field(expr) { - Some(ident) => format!(": {}.is_some()", ident), + let suggestion = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) { + Some(ident) => format!(": {ident}.is_some()"), None => ".is_some()".to_string(), }; @@ -1327,7 +1339,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { node: rustc_ast::LitKind::Int(lit, rustc_ast::LitIntType::Unsuffixed), span, }) => { - let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(*span) else { return false; }; + let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(*span) else { + return false; + }; if !(snippet.starts_with("0x") || snippet.starts_with("0X")) { return false; } @@ -1367,10 +1381,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Provided expression needs to be a literal `0`. - let ExprKind::Lit(Spanned { - node: rustc_ast::LitKind::Int(0, _), - span, - }) = expr.kind else { + let ExprKind::Lit(Spanned { node: rustc_ast::LitKind::Int(0, _), span }) = expr.kind else { return false; }; @@ -1401,7 +1412,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &hir::Expr<'_>, expected_ty: Ty<'tcx>, ) -> bool { - let Some((DefKind::AssocFn, old_def_id)) = self.typeck_results.borrow().type_dependent_def(expr.hir_id) else { + let Some((DefKind::AssocFn, old_def_id)) = + self.typeck_results.borrow().type_dependent_def(expr.hir_id) + else { return false; }; let old_item_name = self.tcx.item_name(old_def_id); @@ -1457,7 +1470,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Same item return false; } - let item_ty = self.tcx.type_of(item.def_id).subst_identity(); + let item_ty = self.tcx.type_of(item.def_id).instantiate_identity(); // FIXME(compiler-errors): This check is *so* rudimentary if item_ty.has_param() { return false; @@ -1494,8 +1507,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { found_ty: Ty<'tcx>, expr: &hir::Expr<'_>, ) { - let hir::ExprKind::MethodCall(segment, callee_expr, &[], _) = expr.kind else { return; }; - let Some(clone_trait_did) = self.tcx.lang_items().clone_trait() else { return; }; + // When `expr` is `x` in something like `let x = foo.clone(); x`, need to recurse up to get + // `foo` and `clone`. + let expr = self.note_type_is_not_clone_inner_expr(expr); + + // If we've recursed to an `expr` of `foo.clone()`, get `foo` and `clone`. + let hir::ExprKind::MethodCall(segment, callee_expr, &[], _) = expr.kind else { + return; + }; + + let Some(clone_trait_did) = self.tcx.lang_items().clone_trait() else { + return; + }; let ty::Ref(_, pointee_ty, _) = found_ty.kind() else { return }; let results = self.typeck_results.borrow(); // First, look for a `Clone::clone` call @@ -1545,6 +1568,83 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + /// Given a type mismatch error caused by `&T` being cloned instead of `T`, and + /// the `expr` as the source of this type mismatch, try to find the method call + /// as the source of this error and return that instead. Otherwise, return the + /// original expression. + fn note_type_is_not_clone_inner_expr<'b>( + &'b self, + expr: &'b hir::Expr<'b>, + ) -> &'b hir::Expr<'b> { + match expr.peel_blocks().kind { + hir::ExprKind::Path(hir::QPath::Resolved( + None, + hir::Path { segments: [_], res: crate::Res::Local(binding), .. }, + )) => { + let Some(hir::Node::Pat(hir::Pat { hir_id, .. })) = self.tcx.hir().find(*binding) + else { + return expr; + }; + let Some(parent) = self.tcx.hir().find(self.tcx.hir().parent_id(*hir_id)) else { + return expr; + }; + + match parent { + // foo.clone() + hir::Node::Local(hir::Local { init: Some(init), .. }) => { + self.note_type_is_not_clone_inner_expr(init) + } + // When `expr` is more complex like a tuple + hir::Node::Pat(hir::Pat { + hir_id: pat_hir_id, + kind: hir::PatKind::Tuple(pats, ..), + .. + }) => { + let Some(hir::Node::Local(hir::Local { init: Some(init), .. })) = + self.tcx.hir().find(self.tcx.hir().parent_id(*pat_hir_id)) else { + return expr; + }; + + match init.peel_blocks().kind { + ExprKind::Tup(init_tup) => { + if let Some(init) = pats + .iter() + .enumerate() + .filter(|x| x.1.hir_id == *hir_id) + .find_map(|(i, _)| init_tup.get(i)) + { + self.note_type_is_not_clone_inner_expr(init) + } else { + expr + } + } + _ => expr, + } + } + _ => expr, + } + } + // If we're calling into a closure that may not be typed recurse into that call. no need + // to worry if it's a call to a typed function or closure as this would ne handled + // previously. + hir::ExprKind::Call(Expr { kind: call_expr_kind, .. }, _) => { + if let hir::ExprKind::Path(hir::QPath::Resolved(None, call_expr_path)) = call_expr_kind + && 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)) + && let hir::Node::Local(hir::Local { init: Some(init), .. }) = closure + && let Expr { kind: hir::ExprKind::Closure(hir::Closure { body: body_id, .. }), ..} = init + { + let hir::Body { value: body_expr, .. } = self.tcx.hir().body(*body_id); + self.note_type_is_not_clone_inner_expr(body_expr) + } else { + expr + } + } + _ => expr, + } + } + /// A common error is to add an extra semicolon: /// /// ```compile_fail,E0308 diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 4f45a24b2..ed4c63f17 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -9,6 +9,26 @@ use rustc_span::def_id::LocalDefId; use rustc_span::Span; use rustc_trait_selection::traits; +/// Provides context for checking patterns in declarations. More specifically this +/// allows us to infer array types if the pattern is irrefutable and allows us to infer +/// the size of the array. See issue #76342. +#[derive(Debug, Copy, Clone)] +pub(super) enum DeclOrigin<'a> { + // from an `if let` expression + LetExpr, + // from `let x = ..` + LocalDecl { els: Option<&'a hir::Block<'a>> }, +} + +impl<'a> DeclOrigin<'a> { + pub(super) fn try_get_else(&self) -> Option<&'a hir::Block<'a>> { + match self { + Self::LocalDecl { els } => *els, + Self::LetExpr => None, + } + } +} + /// A declaration is an abstraction of [hir::Local] and [hir::Let]. /// /// It must have a hir_id, as this is how we connect gather_locals to the check functions. @@ -18,20 +38,20 @@ pub(super) struct Declaration<'a> { pub ty: Option<&'a hir::Ty<'a>>, pub span: Span, pub init: Option<&'a hir::Expr<'a>>, - pub els: Option<&'a hir::Block<'a>>, + pub origin: DeclOrigin<'a>, } impl<'a> From<&'a hir::Local<'a>> for Declaration<'a> { fn from(local: &'a hir::Local<'a>) -> Self { let hir::Local { hir_id, pat, ty, span, init, els, source: _ } = *local; - Declaration { hir_id, pat, ty, span, init, els } + Declaration { hir_id, pat, ty, span, init, origin: DeclOrigin::LocalDecl { els } } } } impl<'a> From<&'a hir::Let<'a>> for Declaration<'a> { fn from(let_expr: &'a hir::Let<'a>) -> Self { let hir::Let { hir_id, pat, ty, span, init } = *let_expr; - Declaration { hir_id, pat, ty, span, init: Some(init), els: None } + Declaration { hir_id, pat, ty, span, init: Some(init), origin: DeclOrigin::LetExpr } } } diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs index b84c49186..cfedcee99 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs @@ -6,7 +6,7 @@ use hir::{ intravisit::{self, Visitor}, Body, Expr, ExprKind, Guard, HirId, LoopIdError, }; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir as hir; use rustc_index::IndexVec; use rustc_infer::infer::InferCtxt; @@ -28,7 +28,7 @@ pub(super) fn build_control_flow_graph<'tcx>( consumed_borrowed_places: ConsumedAndBorrowedPlaces, body: &'tcx Body<'tcx>, num_exprs: usize, -) -> (DropRangesBuilder, FxHashSet) { +) -> (DropRangesBuilder, UnordSet) { let mut drop_range_visitor = DropRangeVisitor::new( infcx, typeck_results, @@ -443,9 +443,9 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> { // We add an edge to the hir_id of the expression/block we are breaking out of, and // then in process_deferred_edges we will map this hir_id to its PostOrderId, which // will refer to the end of the block due to the post order traversal. - self.find_target_expression_from_destination(destination).map_or((), |target| { + if let Ok(target) = self.find_target_expression_from_destination(destination) { self.drop_ranges.add_control_edge_hir_id(self.expr_index, target) - }); + } if let Some(value) = value { self.visit_expr(value); @@ -528,7 +528,7 @@ impl DropRangesBuilder { hir: Map<'_>, num_exprs: usize, ) -> Self { - let mut tracked_value_map = FxHashMap::<_, TrackedValueIndex>::default(); + let mut tracked_value_map = UnordMap::<_, TrackedValueIndex>::default(); let mut next = <_>::from(0u32); for value in tracked_values { for_each_consumable(hir, value, |value| { diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs index ecafbd668..e563bd40b 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs @@ -17,7 +17,7 @@ use self::record_consumed_borrow::find_consumed_and_borrowed; use crate::FnCtxt; use hir::def_id::DefId; use hir::{Body, HirId, HirIdMap, Node}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir as hir; use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; @@ -63,7 +63,7 @@ pub fn compute_drop_ranges<'a, 'tcx>( // If drop range tracking is not enabled, skip all the analysis and produce an // empty set of DropRanges. DropRanges { - tracked_value_map: FxHashMap::default(), + tracked_value_map: UnordMap::default(), nodes: IndexVec::new(), borrowed_temporaries: None, } @@ -125,8 +125,8 @@ impl Debug for TrackedValue { write!(f, "{}", tcx.hir().node_to_string(self.hir_id())) } else { match self { - Self::Variable(hir_id) => write!(f, "Variable({:?})", hir_id), - Self::Temporary(hir_id) => write!(f, "Temporary({:?})", hir_id), + Self::Variable(hir_id) => write!(f, "Variable({hir_id:?})"), + Self::Temporary(hir_id) => write!(f, "Temporary({hir_id:?})"), } } }) @@ -182,9 +182,9 @@ impl TryFrom<&PlaceWithHirId<'_>> for TrackedValue { } pub struct DropRanges { - tracked_value_map: FxHashMap, + tracked_value_map: UnordMap, nodes: IndexVec, - borrowed_temporaries: Option>, + borrowed_temporaries: Option>, } impl DropRanges { @@ -227,7 +227,7 @@ struct DropRangesBuilder { /// (see NodeInfo::drop_state). The hir_id_map field stores the mapping /// from HirIds to the HirIdIndex that is used to represent that value in /// bitvector. - tracked_value_map: FxHashMap, + tracked_value_map: UnordMap, /// When building the control flow graph, we don't always know the /// post-order index of the target node at the point we encounter it. diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs index 8ab0bd535..29413f080 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs @@ -4,7 +4,7 @@ use crate::{ FnCtxt, }; use hir::{def_id::DefId, Body, HirId, HirIdMap}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::{fx::FxIndexSet, unord::UnordSet}; use rustc_hir as hir; use rustc_middle::ty::{ParamEnv, TyCtxt}; use rustc_middle::{ @@ -30,13 +30,13 @@ pub(super) struct ConsumedAndBorrowedPlaces { /// /// Note that this set excludes "partial drops" -- for example, a statement like `drop(x.y)` is /// not considered a drop of `x`, although it would be a drop of `x.y`. - pub(super) consumed: HirIdMap>, + pub(super) consumed: HirIdMap>, /// A set of hir-ids of values or variables that are borrowed at some point within the body. - pub(super) borrowed: FxHashSet, + pub(super) borrowed: UnordSet, /// A set of hir-ids of values or variables that are borrowed at some point within the body. - pub(super) borrowed_temporaries: FxHashSet, + pub(super) borrowed_temporaries: UnordSet, } /// Works with ExprUseVisitor to find interesting values for the drop range analysis. @@ -150,9 +150,10 @@ impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> { hir.node_to_string(diag_expr_id), hir.node_to_string(parent) ); - place_with_id - .try_into() - .map_or((), |tracked_value| self.mark_consumed(parent, tracked_value)); + + if let Ok(tracked_value) = place_with_id.try_into() { + self.mark_consumed(parent, tracked_value) + } } fn borrow( diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index 86ea092bc..6a8171224 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -112,7 +112,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { self.fcx .tcx .sess - .delay_span_bug(span, format!("Encountered var {:?}", unresolved_term)); + .delay_span_bug(span, format!("Encountered var {unresolved_term:?}")); } else { let note = format!( "the type is part of the {} because of this {}", diff --git a/compiler/rustc_hir_typeck/src/inherited.rs b/compiler/rustc_hir_typeck/src/inherited.rs index d5619af2a..7064484a4 100644 --- a/compiler/rustc_hir_typeck/src/inherited.rs +++ b/compiler/rustc_hir_typeck/src/inherited.rs @@ -1,6 +1,6 @@ use super::callee::DeferredCallResolution; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::HirIdMap; @@ -61,9 +61,9 @@ pub struct Inherited<'tcx> { /// Whenever we introduce an adjustment from `!` into a type variable, /// we record that type variable here. This is later used to inform /// fallback. See the `fallback` module for details. - pub(super) diverging_type_vars: RefCell>>, + pub(super) diverging_type_vars: RefCell>>, - pub(super) infer_var_info: RefCell>, + pub(super) infer_var_info: RefCell>, } impl<'tcx> Deref for Inherited<'tcx> { diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index e58efc9d1..4e65182f1 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -11,7 +11,7 @@ use super::FnCtxt; /// If the type is `Option`, it will return `T`, otherwise /// the type itself. Works on most `Option`-like types. fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - let ty::Adt(def, substs) = *ty.kind() else { return ty }; + let ty::Adt(def, args) = *ty.kind() else { return ty }; if def.variants().len() == 2 && !def.repr().c() && def.repr().int.is_none() { let data_idx; @@ -28,7 +28,7 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { } if def.variant(data_idx).fields.len() == 1 { - return def.variant(data_idx).single_field().ty(tcx, substs); + return def.variant(data_idx).single_field().ty(tcx, args); } } @@ -85,7 +85,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"), Ok(SizeSkeleton::Known(size)) => { if let Some(v) = u128::from(size.bytes()).checked_mul(8) { - format!("{} bits", v) + format!("{v} bits") } else { // `u128` should definitely be able to hold the size of different architectures // larger sizes should be reported as error `are too big for the current architecture` @@ -122,14 +122,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { err.note(format!("source type: `{}` ({})", from, skeleton_string(from, sk_from))) .note(format!("target type: `{}` ({})", to, skeleton_string(to, sk_to))); - let mut should_delay_as_bug = false; - if let Err(LayoutError::Unknown(bad_from)) = sk_from && bad_from.references_error() { - should_delay_as_bug = true; - } - if let Err(LayoutError::Unknown(bad_to)) = sk_to && bad_to.references_error() { - should_delay_as_bug = true; - } - if should_delay_as_bug { + if let Err(LayoutError::ReferencesError(_)) = sk_from { + err.delay_as_bug(); + } else if let Err(LayoutError::ReferencesError(_)) = sk_to { err.delay_as_bug(); } } diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 6f82ffcfe..c4d3cbc9f 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -6,7 +6,6 @@ #![feature(min_specialization)] #![feature(control_flow_enum)] #![feature(option_as_slice)] -#![allow(rustc::potential_query_instability)] #![recursion_limit = "256"] #[macro_use] @@ -72,7 +71,7 @@ use rustc_middle::traits; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::config; use rustc_span::def_id::{DefId, LocalDefId}; -use rustc_span::{sym, Span}; +use rustc_span::Span; fluent_messages! { "../messages.ftl" } @@ -102,7 +101,7 @@ fn primary_body_of( ) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> { match node { Node::Item(item) => match item.kind { - hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => { + hir::ItemKind::Const(ty, _, body) | hir::ItemKind::Static(ty, _, body) => { Some((body, Some(ty), None)) } hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))), @@ -141,11 +140,11 @@ fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool { } fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &UnordSet { - &*tcx.typeck(def_id).used_trait_imports + &tcx.typeck(def_id).used_trait_imports } fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> { - let fallback = move || tcx.type_of(def_id.to_def_id()).subst_identity(); + let fallback = move || tcx.type_of(def_id.to_def_id()).instantiate_identity(); typeck_with_fallback(tcx, def_id, fallback) } @@ -183,11 +182,7 @@ fn typeck_with_fallback<'tcx>( let body = tcx.hir().body(body_id); let param_env = tcx.param_env(def_id); - let param_env = if tcx.has_attr(def_id, sym::rustc_do_not_const_check) { - param_env.without_const() - } else { - param_env - }; + let inh = Inherited::new(tcx, def_id); let mut fcx = FnCtxt::new(&inh, param_env, def_id); @@ -195,7 +190,7 @@ fn typeck_with_fallback<'tcx>( let fn_sig = if rustc_hir_analysis::collect::get_infer_ret_ty(&decl.output).is_some() { fcx.astconv().ty_of_fn(id, header.unsafety, header.abi, decl, None, None) } else { - tcx.fn_sig(def_id).subst_identity() + tcx.fn_sig(def_id).instantiate_identity() }; check_abi(tcx, id, span, fn_sig.abi()); @@ -264,11 +259,7 @@ fn typeck_with_fallback<'tcx>( // Closure and generator analysis may run after fallback // because they don't constrain other type variables. - // Closure analysis only runs on closures. Therefore they only need to fulfill non-const predicates (as of now) - let prev_constness = fcx.param_env.constness(); - fcx.param_env = fcx.param_env.without_const(); fcx.closure_analyze(body); - fcx.param_env = fcx.param_env.with_constness(prev_constness); assert!(fcx.deferred_call_resolutions.borrow().is_empty()); // Before the generator analysis, temporary scopes shall be marked to provide more // precise information on types to be captured. diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs index a1aa09084..9574da021 100644 --- a/compiler/rustc_hir_typeck/src/mem_categorization.rs +++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs @@ -198,13 +198,14 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { } /// Like `pat_ty`, but ignores implicit `&` patterns. + #[instrument(level = "debug", skip(self), ret)] fn pat_ty_unadjusted(&self, pat: &hir::Pat<'_>) -> McResult> { let base_ty = self.node_ty(pat.hir_id)?; - debug!("pat_ty(pat={:?}) base_ty={:?}", pat, base_ty); + trace!(?base_ty); // This code detects whether we are looking at a `ref x`, // and if so, figures out what the type *being borrowed* is. - let ret_ty = match pat.kind { + match pat.kind { PatKind::Binding(..) => { let bm = *self .typeck_results @@ -217,21 +218,18 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { // but what we want here is the type of the underlying value being borrowed. // So peel off one-level, turning the &T into T. match base_ty.builtin_deref(false) { - Some(t) => t.ty, + Some(t) => Ok(t.ty), None => { - debug!("By-ref binding of non-derefable type {:?}", base_ty); - return Err(()); + debug!("By-ref binding of non-derefable type"); + Err(()) } } } else { - base_ty + Ok(base_ty) } } - _ => base_ty, - }; - debug!("pat_ty(pat={:?}) ret_ty={:?}", pat, ret_ty); - - Ok(ret_ty) + _ => Ok(base_ty), + } } pub(crate) fn cat_expr(&self, expr: &hir::Expr<'_>) -> McResult> { @@ -299,13 +297,11 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { } } - #[instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self), ret)] pub(crate) fn cat_expr_unadjusted( &self, expr: &hir::Expr<'_>, ) -> McResult> { - debug!("cat_expr: id={} expr={:?}", expr.hir_id, expr); - let expr_ty = self.expr_ty(expr)?; match expr.kind { hir::ExprKind::Unary(hir::UnOp::Deref, ref e_base) => { @@ -319,7 +315,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { hir::ExprKind::Field(ref base, _) => { let base = self.cat_expr(base)?; - debug!("cat_expr(cat_field): id={} expr={:?} base={:?}", expr.hir_id, expr, base); + debug!(?base); let field_idx = self .typeck_results @@ -336,7 +332,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { )) } - hir::ExprKind::Index(ref base, _) => { + hir::ExprKind::Index(ref 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. @@ -389,7 +385,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { } } - #[instrument(level = "debug", skip(self, span))] + #[instrument(level = "debug", skip(self, span), ret)] pub(crate) fn cat_res( &self, hir_id: hir::HirId, @@ -430,6 +426,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { /// Note: the actual upvar access contains invisible derefs of closure /// environment and upvar reference as appropriate. Only regionck cares /// about these dereferences, so we let it compute them as needed. + #[instrument(level = "debug", skip(self), ret)] fn cat_upvar(&self, hir_id: hir::HirId, var_id: hir::HirId) -> McResult> { let closure_expr_def_id = self.body_owner; @@ -439,24 +436,20 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { }; let var_ty = self.node_ty(var_id)?; - let ret = PlaceWithHirId::new(hir_id, var_ty, PlaceBase::Upvar(upvar_id), Vec::new()); - - debug!("cat_upvar ret={:?}", ret); - Ok(ret) + Ok(PlaceWithHirId::new(hir_id, var_ty, PlaceBase::Upvar(upvar_id), Vec::new())) } + #[instrument(level = "debug", skip(self), ret)] pub(crate) fn cat_rvalue( &self, hir_id: hir::HirId, span: Span, expr_ty: Ty<'tcx>, ) -> PlaceWithHirId<'tcx> { - debug!("cat_rvalue hir_id={:?}, expr_ty={:?}, span={:?}", hir_id, expr_ty, span); - let ret = PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new()); - debug!("cat_rvalue ret={:?}", ret); - ret + PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new()) } + #[instrument(level = "debug", skip(self, node), ret)] pub(crate) fn cat_projection( &self, node: &N, @@ -464,16 +457,23 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { ty: Ty<'tcx>, kind: ProjectionKind, ) -> PlaceWithHirId<'tcx> { + let place_ty = base_place.place.ty(); let mut projections = base_place.place.projections; + + let node_ty = self.typeck_results.node_type(node.hir_id()); + // Opaque types can't have field projections, but we can instead convert + // the current place in-place (heh) to the hidden type, and then apply all + // follow up projections on that. + if node_ty != place_ty && matches!(place_ty.kind(), ty::Alias(ty::Opaque, ..)) { + projections.push(Projection { kind: ProjectionKind::OpaqueCast, ty: node_ty }); + } projections.push(Projection { kind, ty }); - let ret = PlaceWithHirId::new( + PlaceWithHirId::new( node.hir_id(), base_place.place.base_ty, base_place.place.base, projections, - ); - debug!("cat_field ret {:?}", ret); - ret + ) } #[instrument(level = "debug", skip(self))] @@ -497,7 +497,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { self.cat_deref(expr, base) } - #[instrument(level = "debug", skip(self, node))] + #[instrument(level = "debug", skip(self, node), ret)] fn cat_deref( &self, node: &impl HirNode, @@ -514,14 +514,12 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { let mut projections = base_place.place.projections; projections.push(Projection { kind: ProjectionKind::Deref, ty: deref_ty }); - let ret = PlaceWithHirId::new( + Ok(PlaceWithHirId::new( node.hir_id(), base_place.place.base_ty, base_place.place.base, projections, - ); - debug!("cat_deref ret {:?}", ret); - Ok(ret) + )) } pub(crate) fn cat_pattern( @@ -559,7 +557,10 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { Ok(adt_def.variant_index_with_ctor_id(variant_ctor_id)) } Res::Def(DefKind::Ctor(CtorOf::Struct, ..), _) - | Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _) + | Res::Def( + DefKind::Struct | DefKind::Union | DefKind::TyAlias { .. } | DefKind::AssocTy, + _, + ) | Res::SelfCtor(..) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => { @@ -595,7 +596,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { fn total_fields_in_tuple(&self, pat_hir_id: hir::HirId, span: Span) -> McResult { let ty = self.typeck_results.node_type(pat_hir_id); match ty.kind() { - ty::Tuple(substs) => Ok(substs.len()), + ty::Tuple(args) => Ok(args.len()), _ => { self.tcx().sess.delay_span_bug(span, "tuple pattern not applied to a tuple"); Err(()) @@ -603,6 +604,13 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { } } + /// Here, `place` is the `PlaceWithHirId` being matched and pat is the pattern it + /// is being matched against. + /// + /// In general, the way that this works is that we walk down the pattern, + /// constructing a `PlaceWithHirId` that represents the path that will be taken + /// to reach the value being matched. + #[instrument(skip(self, op), ret, level = "debug")] fn cat_pattern_( &self, mut place_with_id: PlaceWithHirId<'tcx>, @@ -612,15 +620,6 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { where F: FnMut(&PlaceWithHirId<'tcx>, &hir::Pat<'_>), { - // Here, `place` is the `PlaceWithHirId` being matched and pat is the pattern it - // is being matched against. - // - // In general, the way that this works is that we walk down the pattern, - // constructing a `PlaceWithHirId` that represents the path that will be taken - // to reach the value being matched. - - debug!("cat_pattern(pat={:?}, place_with_id={:?})", pat, place_with_id); - // If (pattern) adjustments are active for this pattern, adjust the `PlaceWithHirId` correspondingly. // `PlaceWithHirId`s are constructed differently from patterns. For example, in // @@ -654,11 +653,11 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { // `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)` // and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`. for _ in 0..self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(0, |v| v.len()) { - debug!("cat_pattern: applying adjustment to place_with_id={:?}", place_with_id); + debug!("applying adjustment to place_with_id={:?}", place_with_id); place_with_id = self.cat_deref(pat, place_with_id)?; } let place_with_id = place_with_id; // lose mutability - debug!("cat_pattern: applied adjustment derefs to get place_with_id={:?}", place_with_id); + debug!("applied adjustment derefs to get place_with_id={:?}", place_with_id); // Invoke the callback, but only now, after the `place_with_id` has adjusted. // diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 87edb8031..7c73f6a89 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -5,7 +5,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::GenericArg; use rustc_hir_analysis::astconv::generics::{ - check_generic_arg_count_for_call, create_substs_for_generic_args, + check_generic_arg_count_for_call, create_args_for_parent_generic_args, }; use rustc_hir_analysis::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall}; use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk}; @@ -13,9 +13,9 @@ use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion}; use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::subst::{self, SubstsRef}; -use rustc_middle::ty::{self, GenericParamDefKind, Ty, TyCtxt}; -use rustc_middle::ty::{InternalSubsts, UserSubsts, UserType}; +use rustc_middle::ty::{ + self, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, UserArgs, UserType, +}; use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::traits; @@ -96,13 +96,13 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick); // Create substitutions for the method's type parameters. - let rcvr_substs = self.fresh_receiver_substs(self_ty, &pick); - let all_substs = self.instantiate_method_substs(&pick, segment, rcvr_substs); + let rcvr_args = self.fresh_receiver_args(self_ty, &pick); + let all_args = self.instantiate_method_args(&pick, segment, rcvr_args); - debug!("rcvr_substs={rcvr_substs:?}, all_substs={all_substs:?}"); + 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_substs); + 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 @@ -112,10 +112,10 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // In that case, we'll error anyway, but we'll also re-run the search with all traits // in scope, and if we find another method which can be used, we'll output an // appropriate hint suggesting to import the trait. - let filler_substs = rcvr_substs + let filler_args = rcvr_args .extend_to(self.tcx, pick.item.def_id, |def, _| self.tcx.mk_param_from_def(def)); let illegal_sized_bound = self.predicates_require_illegal_sized_bound( - self.tcx.predicates_of(pick.item.def_id).instantiate(self.tcx, filler_substs), + self.tcx.predicates_of(pick.item.def_id).instantiate(self.tcx, filler_args), ); // Unify the (adjusted) self type with what the method expects. @@ -129,7 +129,7 @@ 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_substs); + self.unify_receivers(self_ty, method_sig_rcvr, &pick, all_args); let (method_sig, method_predicates) = self.normalize(self.span, (method_sig, method_predicates)); @@ -144,7 +144,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { if illegal_sized_bound.is_none() { self.add_obligations( Ty::new_fn_ptr(self.tcx, method_sig), - all_substs, + all_args, method_predicates, pick.item.def_id, ); @@ -153,7 +153,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // Create the final `MethodCallee`. let callee = MethodCallee { def_id: pick.item.def_id, - substs: all_substs, + args: all_args, sig: method_sig.skip_binder(), }; ConfirmResult { callee, illegal_sized_bound } @@ -171,7 +171,8 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // time writing the results into the various typeck results. let mut autoderef = self.autoderef(self.call_expr.span, unadjusted_self_ty); let Some((ty, n)) = autoderef.nth(pick.autoderefs) else { - return Ty::new_error_with_message(self.tcx, + return Ty::new_error_with_message( + self.tcx, rustc_span::DUMMY_SP, format!("failed autoderef {}", pick.autoderefs), ); @@ -224,7 +225,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { assert!(mutbl.is_mut()); Ty::new_ptr(self.tcx, ty::TypeAndMut { mutbl: hir::Mutability::Not, ty }) } - other => panic!("Cannot adjust receiver type {:?} to const ptr", other), + other => panic!("Cannot adjust receiver type {other:?} to const ptr"), }; adjustments.push(Adjustment { @@ -251,20 +252,19 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { /// /// Note that this substitution may include late-bound regions from the impl level. If so, /// these are instantiated later in the `instantiate_method_sig` routine. - fn fresh_receiver_substs( + fn fresh_receiver_args( &mut self, self_ty: Ty<'tcx>, pick: &probe::Pick<'tcx>, - ) -> SubstsRef<'tcx> { + ) -> GenericArgsRef<'tcx> { match pick.kind { probe::InherentImplPick => { let impl_def_id = pick.item.container_id(self.tcx); assert!( self.tcx.impl_trait_ref(impl_def_id).is_none(), - "impl {:?} is not an inherent impl", - impl_def_id + "impl {impl_def_id:?} is not an inherent impl" ); - self.fresh_substs_for_item(self.span, impl_def_id) + self.fresh_args_for_item(self.span, impl_def_id) } probe::ObjectPick => { @@ -288,7 +288,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { "original_poly_trait_ref={:?} upcast_trait_ref={:?} target_trait={:?}", original_poly_trait_ref, upcast_trait_ref, trait_def_id ); - upcast_trait_ref.substs + upcast_trait_ref.args }) } @@ -300,13 +300,13 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // the process we will unify the transformed-self-type // of the method with the actual type in order to // unify some of these variables. - self.fresh_substs_for_item(self.span, trait_def_id) + self.fresh_args_for_item(self.span, trait_def_id) } probe::WhereClausePick(poly_trait_ref) => { // Where clauses can have bound regions in them. We need to instantiate // those to convert from a poly-trait-ref to a trait-ref. - self.instantiate_binder_with_fresh_vars(poly_trait_ref).substs + self.instantiate_binder_with_fresh_vars(poly_trait_ref).args } } } @@ -343,12 +343,12 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { }) } - fn instantiate_method_substs( + fn instantiate_method_args( &mut self, pick: &probe::Pick<'tcx>, seg: &hir::PathSegment<'_>, - parent_substs: SubstsRef<'tcx>, - ) -> SubstsRef<'tcx> { + parent_args: GenericArgsRef<'tcx>, + ) -> GenericArgsRef<'tcx> { // Determine the values for the generic parameters of the method. // If they were not explicitly supplied, just construct fresh // variables. @@ -365,7 +365,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // Create subst for early-bound lifetime parameters, combining // parameters from the type and those from the method. - assert_eq!(generics.parent_count, parent_substs.len()); + assert_eq!(generics.parent_count, parent_args.len()); struct MethodSubstsCtxt<'a, 'tcx> { cfcx: &'a ConfirmContext<'a, 'tcx>, @@ -389,7 +389,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { &mut self, param: &ty::GenericParamDef, arg: &GenericArg<'_>, - ) -> subst::GenericArg<'tcx> { + ) -> ty::GenericArg<'tcx> { match (¶m.kind, arg) { (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { self.cfcx.fcx.astconv().ast_region_to_region(lt, Some(param)).into() @@ -421,31 +421,31 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { fn inferred_kind( &mut self, - _substs: Option<&[subst::GenericArg<'tcx>]>, + _args: Option<&[ty::GenericArg<'tcx>]>, param: &ty::GenericParamDef, _infer_args: bool, - ) -> subst::GenericArg<'tcx> { + ) -> ty::GenericArg<'tcx> { self.cfcx.var_for_def(self.cfcx.span, param) } } - let substs = create_substs_for_generic_args( + let args = create_args_for_parent_generic_args( self.tcx, pick.item.def_id, - parent_substs, + parent_args, false, None, &arg_count_correct, &mut MethodSubstsCtxt { cfcx: self, pick, seg }, ); - // When the method is confirmed, the `substs` includes + // When the method is confirmed, the `args` includes // parameters from not just the method, but also the impl of // the method -- in particular, the `Self` type will be fully // resolved. However, those are not something that the "user // specified" -- i.e., those types come from the inferred type // of the receiver, not something the user wrote. So when we - // create the user-substs, we want to replace those earlier + // create the user-args, we want to replace those earlier // types with just the types that the user actually wrote -- // that is, those that appear on the *method itself*. // @@ -453,15 +453,15 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // `foo.bar::(...)` -- the `Self` type here will be the // type of `foo` (possibly adjusted), but we don't want to // include that. We want just the `[_, u32]` part. - if !substs.is_empty() && !generics.params.is_empty() { + if !args.is_empty() && !generics.params.is_empty() { let user_type_annotation = self.probe(|_| { - let user_substs = UserSubsts { - substs: InternalSubsts::for_item(self.tcx, pick.item.def_id, |param, _| { + let user_args = UserArgs { + args: GenericArgs::for_item(self.tcx, pick.item.def_id, |param, _| { let i = param.index as usize; if i < generics.parent_count { self.fcx.var_for_def(DUMMY_SP, param) } else { - substs[i] + args[i] } }), user_self_ty: None, // not relevant here @@ -469,18 +469,18 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self.fcx.canonicalize_user_type_annotation(UserType::TypeOf( pick.item.def_id, - user_substs, + user_args, )) }); - debug!("instantiate_method_substs: user_type_annotation={:?}", user_type_annotation); + debug!("instantiate_method_args: user_type_annotation={:?}", user_type_annotation); if !self.skip_record_for_diagnostics { self.fcx.write_user_type_annotation(self.call_expr.hir_id, user_type_annotation); } } - self.normalize(self.span, substs) + self.normalize(self.span, args) } fn unify_receivers( @@ -488,7 +488,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self_ty: Ty<'tcx>, method_self_ty: Ty<'tcx>, pick: &probe::Pick<'tcx>, - substs: SubstsRef<'tcx>, + args: GenericArgsRef<'tcx>, ) { debug!( "unify_receivers: self_ty={:?} method_self_ty={:?} span={:?} pick={:?}", @@ -499,7 +499,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { ObligationCauseCode::UnifyReceiver(Box::new(UnifyReceiverContext { assoc_item: pick.item, param_env: self.param_env, - substs, + args, })), ); match self.at(&cause, self.param_env).sup(DefineOpaqueTypes::No, method_self_ty, self_ty) { @@ -509,7 +509,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { Err(terr) => { // FIXME(arbitrary_self_types): We probably should limit the // situations where this can occur by adding additional restrictions - // to the feature, like the self type can't reference method substs. + // to the feature, like the self type can't reference method args. if self.tcx.features().arbitrary_self_types { self.err_ctxt() .report_mismatched_types(&cause, method_self_ty, self_ty, terr) @@ -532,19 +532,19 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { fn instantiate_method_sig( &mut self, pick: &probe::Pick<'tcx>, - all_substs: SubstsRef<'tcx>, + all_args: GenericArgsRef<'tcx>, ) -> (ty::FnSig<'tcx>, ty::InstantiatedPredicates<'tcx>) { - debug!("instantiate_method_sig(pick={:?}, all_substs={:?})", pick, all_substs); + debug!("instantiate_method_sig(pick={:?}, all_args={:?})", pick, all_args); // Instantiate the bounds on the method with the // type/early-bound-regions substitutions performed. There can // be no late-bound regions appearing here. let def_id = pick.item.def_id; - let method_predicates = self.tcx.predicates_of(def_id).instantiate(self.tcx, all_substs); + let method_predicates = self.tcx.predicates_of(def_id).instantiate(self.tcx, all_args); debug!("method_predicates after subst = {:?}", method_predicates); - let sig = self.tcx.fn_sig(def_id).subst(self.tcx, all_substs); + let sig = self.tcx.fn_sig(def_id).instantiate(self.tcx, all_args); debug!("type scheme substituted, sig={:?}", sig); let sig = self.instantiate_binder_with_fresh_vars(sig); @@ -556,18 +556,18 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { fn add_obligations( &mut self, fty: Ty<'tcx>, - all_substs: SubstsRef<'tcx>, + all_args: GenericArgsRef<'tcx>, method_predicates: ty::InstantiatedPredicates<'tcx>, def_id: DefId, ) { debug!( - "add_obligations: fty={:?} all_substs={:?} method_predicates={:?} def_id={:?}", - fty, all_substs, method_predicates, def_id + "add_obligations: fty={:?} all_args={:?} method_predicates={:?} def_id={:?}", + fty, all_args, method_predicates, def_id ); // FIXME: could replace with the following, but we already calculated `method_predicates`, // so we just call `predicates_for_generics` directly to avoid redoing work. - // `self.add_required_obligations(self.span, def_id, &all_substs);` + // `self.add_required_obligations(self.span, def_id, &all_args);` for obligation in traits::predicates_for_generics( |idx, span| { let code = if span.is_dummy() { @@ -590,10 +590,10 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // this is a projection from a trait reference, so we have to // make sure that the trait reference inputs are well-formed. - self.add_wf_bounds(all_substs, self.call_expr); + self.add_wf_bounds(all_args, self.call_expr); // the function type must also be well-formed (this is not - // implied by the substs being well-formed because of inherent + // implied by the args being well-formed because of inherent // impls and late-bound regions - see issue #28609). self.register_wf_obligation(fty.into(), self.span, traits::WellFormed(None)); } diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index e52cea188..6dd131aa2 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -7,12 +7,11 @@ mod prelude2021; pub mod probe; mod suggest; -pub use self::suggest::SelfSource; +pub use self::suggest::{MethodCallComponents, SelfSource}; pub use self::MethodError::*; use crate::errors::OpMethodGenericParams; use crate::FnCtxt; -use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, Diagnostic, SubdiagnosticMessage}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace}; @@ -20,8 +19,8 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::{self, InferOk}; use rustc_middle::query::Providers; use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; use rustc_middle::ty::{self, GenericParamDefKind, Ty, TypeVisitableExt}; +use rustc_middle::ty::{GenericArgs, GenericArgsRef}; use rustc_span::symbol::Ident; use rustc_span::Span; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; @@ -37,7 +36,7 @@ pub fn provide(providers: &mut Providers) { pub struct MethodCallee<'tcx> { /// Impl method ID, for inherent methods, or trait method ID, otherwise. pub def_id: DefId, - pub substs: SubstsRef<'tcx>, + pub args: GenericArgsRef<'tcx>, /// Instantiated method signature, i.e., it has been /// substituted, normalized, and has had late-bound @@ -190,11 +189,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.lint_dot_call_from_2018(self_ty, segment, span, call_expr, self_expr, &pick, args); - for import_id in &pick.import_ids { + for &import_id in &pick.import_ids { debug!("used_trait_import: {:?}", import_id); - Lrc::get_mut(&mut self.typeck_results.borrow_mut().used_trait_imports) - .unwrap() - .insert(*import_id); + self.typeck_results.borrow_mut().used_trait_imports.insert(import_id); } self.tcx.check_stability(pick.item.def_id, Some(call_expr.hir_id), span, None); @@ -324,9 +321,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { trait_def_id: DefId, self_ty: Ty<'tcx>, opt_input_types: Option<&[Ty<'tcx>]>, - ) -> (traits::PredicateObligation<'tcx>, &'tcx ty::List>) { + ) -> (traits::PredicateObligation<'tcx>, &'tcx ty::List>) { // Construct a trait-reference `self_ty : Trait` - let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| { + let args = GenericArgs::for_item(self.tcx, trait_def_id, |param, _| { match param.kind { GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => {} GenericParamDefKind::Type { .. } => { @@ -340,19 +337,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.var_for_def(cause.span, param) }); - let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, substs); + let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, args); // Construct an obligation let poly_trait_ref = ty::Binder::dummy(trait_ref); - ( - traits::Obligation::new( - self.tcx, - cause, - self.param_env, - poly_trait_ref.without_const(), - ), - substs, - ) + (traits::Obligation::new(self.tcx, cause, self.param_env, poly_trait_ref), args) } /// `lookup_method_in_trait` is used for overloaded operators. @@ -369,9 +358,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self_ty: Ty<'tcx>, opt_input_types: Option<&[Ty<'tcx>]>, ) -> Option>> { - let (obligation, substs) = + let (obligation, args) = self.obligation_for_method(cause, trait_def_id, self_ty, opt_input_types); - self.construct_obligation_for_trait(m_name, trait_def_id, obligation, substs) + self.construct_obligation_for_trait(m_name, trait_def_id, obligation, args) } // FIXME(#18741): it seems likely that we can consolidate some of this @@ -382,7 +371,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { m_name: Ident, trait_def_id: DefId, obligation: traits::PredicateObligation<'tcx>, - substs: &'tcx ty::List>, + args: &'tcx ty::List>, ) -> Option>> { debug!(?obligation); @@ -428,7 +417,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // N.B., instantiate late-bound regions before normalizing the // function signature so that normalization does not need to deal // with bound regions. - let fn_sig = tcx.fn_sig(def_id).subst(self.tcx, substs); + let fn_sig = tcx.fn_sig(def_id).instantiate(self.tcx, args); let fn_sig = self.instantiate_binder_with_fresh_vars(obligation.cause.span, infer::FnCall, fn_sig); @@ -447,7 +436,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // // Note that as the method comes from a trait, it should not have // any late-bound regions appearing in its bounds. - let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, substs); + let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, args); let InferOk { value, obligations: o } = self.at(&obligation.cause, self.param_env).normalize(bounds); @@ -480,7 +469,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ))), )); - let callee = MethodCallee { def_id, substs, sig: fn_sig }; + let callee = MethodCallee { def_id, args, sig: fn_sig }; debug!("callee = {:?}", callee); @@ -567,10 +556,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!(?pick); { let mut typeck_results = self.typeck_results.borrow_mut(); - let used_trait_imports = Lrc::get_mut(&mut typeck_results.used_trait_imports).unwrap(); for import_id in pick.import_ids { debug!(used_trait_import=?import_id); - used_trait_imports.insert(import_id); + typeck_results.used_trait_imports.insert(import_id); } } diff --git a/compiler/rustc_hir_typeck/src/method/prelude2021.rs b/compiler/rustc_hir_typeck/src/method/prelude2021.rs index ec4e7f7f8..3f1dca5b1 100644 --- a/compiler/rustc_hir_typeck/src/method/prelude2021.rs +++ b/compiler/rustc_hir_typeck/src/method/prelude2021.rs @@ -14,6 +14,7 @@ use rustc_span::symbol::kw::{Empty, Underscore}; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; use rustc_trait_selection::infer::InferCtxtExt; +use std::fmt::Write; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(super) fn lint_dot_call_from_2018( @@ -32,7 +33,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); // Rust 2021 and later is already using the new prelude - if span.rust_2021() { + if span.at_least_rust_2021() { return; } @@ -97,28 +98,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) = pick.autoref_or_ptr_adjustment { - format!("{}{} as *const _", derefs, self_expr) + format!("{derefs}{self_expr} as *const _") } else { - format!("{}{}{}", autoref, derefs, self_expr) + format!("{autoref}{derefs}{self_expr}") }; lint.span_suggestion( sp, "disambiguate the method call", - format!("({})", self_adjusted), + format!("({self_adjusted})"), Applicability::MachineApplicable, ); } else { let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) = pick.autoref_or_ptr_adjustment { - format!("{}(...) as *const _", derefs) + format!("{derefs}(...) as *const _") } else { - format!("{}{}...", autoref, derefs) + format!("{autoref}{derefs}...") }; lint.span_help( sp, - format!("disambiguate the method call with `({})`", self_adjusted,), + format!("disambiguate the method call with `({self_adjusted})`",), ); } @@ -143,16 +144,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (self_adjusted, precise) = self.adjust_expr(pick, self_expr, sp); if precise { - let args = args - .iter() - .map(|arg| { - let span = arg.span.find_ancestor_inside(sp).unwrap_or_default(); - format!( - ", {}", - self.sess().source_map().span_to_snippet(span).unwrap() - ) - }) - .collect::(); + let args = args.iter().fold(String::new(), |mut string, arg| { + let span = arg.span.find_ancestor_inside(sp).unwrap_or_default(); + write!( + string, + ", {}", + self.sess().source_map().span_to_snippet(span).unwrap() + ) + .unwrap(); + string + }); lint.span_suggestion( sp, @@ -168,7 +169,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .ok()) { // Keep turbofish. - format!("::{}", args) + format!("::{args}") } else { String::new() }, @@ -203,7 +204,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pick: &Pick<'tcx>, ) { // Rust 2021 and later is already using the new prelude - if span.rust_2021() { + if span.at_least_rust_2021() { return; } @@ -347,7 +348,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Glob import, so just use its name. return None; } else { - return Some(format!("{}", any_id)); + return Some(format!("{any_id}")); } } @@ -396,9 +397,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) = pick.autoref_or_ptr_adjustment { - format!("{}{} as *const _", derefs, expr_text) + format!("{derefs}{expr_text} as *const _") } else { - format!("{}{}{}", autoref, derefs, expr_text) + format!("{autoref}{derefs}{expr_text}") }; (adjusted_text, precise) diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 03a3eebbd..7164102a3 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -22,7 +22,7 @@ use rustc_middle::ty::AssocItem; use rustc_middle::ty::GenericParamDefKind; use rustc_middle::ty::ToPredicate; use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; -use rustc_middle::ty::{InternalSubsts, SubstsRef}; +use rustc_middle::ty::{GenericArgs, GenericArgsRef}; use rustc_session::lint; use rustc_span::def_id::DefId; use rustc_span::def_id::LocalDefId; @@ -100,10 +100,10 @@ impl<'a, 'tcx> Deref for ProbeContext<'a, 'tcx> { #[derive(Debug, Clone)] pub(crate) struct Candidate<'tcx> { // Candidates are (I'm not quite sure, but they are mostly) basically - // some metadata on top of a `ty::AssocItem` (without substs). + // some metadata on top of a `ty::AssocItem` (without args). // // However, method probing wants to be able to evaluate the predicates - // for a function with the substs applied - for example, if a function + // for a function with the args applied - for example, if a function // has `where Self: Sized`, we don't want to consider it unless `Self` // is actually `Sized`, and similarly, return-type suggestions want // to consider the "actual" return type. @@ -140,7 +140,7 @@ pub(crate) struct Candidate<'tcx> { #[derive(Debug, Clone)] pub(crate) enum CandidateKind<'tcx> { InherentImplCandidate( - SubstsRef<'tcx>, + GenericArgsRef<'tcx>, // Normalize obligations Vec>, ), @@ -437,7 +437,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // this case used to be allowed by the compiler, // so we do a future-compat lint here for the 2015 edition // (see https://github.com/rust-lang/rust/issues/46906) - if self.tcx.sess.rust_2018() { + if self.tcx.sess.at_least_rust_2018() { self.tcx.sess.emit_err(MethodCallOnUnknownRawPointee { span }); } else { self.tcx.struct_span_lint_hir( @@ -738,13 +738,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { continue; } - let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id); - let impl_ty = impl_ty.subst(self.tcx, impl_substs); + let (impl_ty, impl_args) = self.impl_ty_and_args(impl_def_id); + let impl_ty = impl_ty.instantiate(self.tcx, impl_args); debug!("impl_ty: {:?}", impl_ty); // Determine the receiver type that the method itself expects. - let (xform_self_ty, xform_ret_ty) = self.xform_self_ty(item, impl_ty, impl_substs); + let (xform_self_ty, xform_ret_ty) = self.xform_self_ty(item, impl_ty, impl_args); debug!("xform_self_ty: {:?}, xform_ret_ty: {:?}", xform_self_ty, xform_ret_ty); // We can't use normalize_associated_types_in as it will pollute the @@ -770,7 +770,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { xform_self_ty, xform_ret_ty, item, - kind: InherentImplCandidate(impl_substs, obligations), + kind: InherentImplCandidate(impl_args, obligations), import_ids: smallvec![], }, true, @@ -813,7 +813,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let new_trait_ref = this.erase_late_bound_regions(new_trait_ref); let (xform_self_ty, xform_ret_ty) = - this.xform_self_ty(item, new_trait_ref.self_ty(), new_trait_ref.substs); + this.xform_self_ty(item, new_trait_ref.self_ty(), new_trait_ref.args); this.push_candidate( Candidate { xform_self_ty, @@ -859,7 +859,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { ); let (xform_self_ty, xform_ret_ty) = - this.xform_self_ty(item, trait_ref.self_ty(), trait_ref.substs); + this.xform_self_ty(item, trait_ref.self_ty(), trait_ref.args); this.push_candidate( Candidate { @@ -929,8 +929,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { ) -> bool { match method.kind { ty::AssocKind::Fn => self.probe(|_| { - let substs = self.fresh_substs_for_item(self.span, method.def_id); - let fty = self.tcx.fn_sig(method.def_id).subst(self.tcx, substs); + let args = self.fresh_args_for_item(self.span, method.def_id); + let fty = self.tcx.fn_sig(method.def_id).instantiate(self.tcx, args); let fty = self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, fty); if let Some(self_ty) = self_ty { @@ -954,8 +954,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { trait_def_id: DefId, ) { debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id); - let trait_substs = self.fresh_substs_for_item(self.span, trait_def_id); - let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, trait_substs); + let trait_args = self.fresh_args_for_item(self.span, trait_def_id); + let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, trait_args); if self.tcx.is_trait_alias(trait_def_id) { // For trait aliases, recursively assume all explicitly named traits are relevant @@ -977,7 +977,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { ); let (xform_self_ty, xform_ret_ty) = - self.xform_self_ty(item, new_trait_ref.self_ty(), new_trait_ref.substs); + self.xform_self_ty(item, new_trait_ref.self_ty(), new_trait_ref.args); self.push_candidate( Candidate { xform_self_ty, @@ -1005,7 +1005,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } let (xform_self_ty, xform_ret_ty) = - self.xform_self_ty(item, trait_ref.self_ty(), trait_substs); + self.xform_self_ty(item, trait_ref.self_ty(), trait_args); self.push_candidate( Candidate { xform_self_ty, @@ -1510,7 +1510,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 substs, ref ref_obligations) => { + InherentImplCandidate(ref 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 @@ -1524,7 +1524,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // Check whether the impl imposes obligations we have to worry about. let impl_def_id = probe.item.container_id(self.tcx); let impl_bounds = self.tcx.predicates_of(impl_def_id); - let impl_bounds = impl_bounds.instantiate(self.tcx, substs); + let impl_bounds = impl_bounds.instantiate(self.tcx, args); let InferOk { value: impl_bounds, obligations: norm_obligations } = self.fcx.at(&cause, self.param_env).normalize(impl_bounds); @@ -1592,15 +1592,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { if let Some(method_name) = self.method_name { // Some trait methods are excluded for arrays before 2021. // (`array.into_iter()` wants a slice iterator for compatibility.) - if self_ty.is_array() && !method_name.span.rust_2021() { + if self_ty.is_array() && !method_name.span.at_least_rust_2021() { let trait_def = self.tcx.trait_def(trait_ref.def_id); if trait_def.skip_array_during_method_dispatch { return ProbeResult::NoMatch; } } } - let predicate = - ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx); + let predicate = ty::Binder::dummy(trait_ref).to_predicate(self.tcx); parent_pred = Some(predicate); let obligation = traits::Obligation::new(self.tcx, cause.clone(), self.param_env, predicate); @@ -1843,10 +1842,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { &self, item: ty::AssocItem, impl_ty: Ty<'tcx>, - substs: SubstsRef<'tcx>, + args: GenericArgsRef<'tcx>, ) -> (Ty<'tcx>, Option>) { if item.kind == ty::AssocKind::Fn && self.mode == Mode::MethodCall { - let sig = self.xform_method_sig(item.def_id, substs); + let sig = self.xform_method_sig(item.def_id, args); (sig.inputs()[0], Some(sig.output())) } else { (impl_ty, None) @@ -1854,11 +1853,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } #[instrument(level = "debug", skip(self))] - fn xform_method_sig(&self, method: DefId, substs: SubstsRef<'tcx>) -> ty::FnSig<'tcx> { + fn xform_method_sig(&self, method: DefId, args: GenericArgsRef<'tcx>) -> ty::FnSig<'tcx> { let fn_sig = self.tcx.fn_sig(method); debug!(?fn_sig); - assert!(!substs.has_escaping_bound_vars()); + assert!(!args.has_escaping_bound_vars()); // It is possible for type parameters or early-bound lifetimes // to appear in the signature of `self`. The substitutions we @@ -1866,15 +1865,15 @@ 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!(substs.len(), generics.parent_count as usize); + assert_eq!(args.len(), generics.parent_count as usize); let xform_fn_sig = if generics.params.is_empty() { - fn_sig.subst(self.tcx, substs) + fn_sig.instantiate(self.tcx, args) } else { - let substs = InternalSubsts::for_item(self.tcx, method, |param, _| { + let args = GenericArgs::for_item(self.tcx, method, |param, _| { let i = param.index as usize; - if i < substs.len() { - substs[i] + if i < args.len() { + args[i] } else { match param.kind { GenericParamDefKind::Lifetime => { @@ -1887,18 +1886,18 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } }); - fn_sig.subst(self.tcx, substs) + fn_sig.instantiate(self.tcx, args) }; self.erase_late_bound_regions(xform_fn_sig) } /// Gets the type of an impl and generate substitutions with inference vars. - fn impl_ty_and_substs( + fn impl_ty_and_args( &self, impl_def_id: DefId, - ) -> (ty::EarlyBinder>, SubstsRef<'tcx>) { - (self.tcx.type_of(impl_def_id), self.fresh_substs_for_item(self.span, impl_def_id)) + ) -> (ty::EarlyBinder>, GenericArgsRef<'tcx>) { + (self.tcx.type_of(impl_def_id), self.fresh_args_for_item(self.span, impl_def_id)) } /// Replaces late-bound-regions bound by `value` with `'static` using @@ -1938,13 +1937,21 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { /// Determine if the associated item withe the given DefId matches /// the desired name via a doc alias. fn matches_by_doc_alias(&self, def_id: DefId) -> bool { - let Some(name) = self.method_name else { return false; }; - let Some(local_def_id) = def_id.as_local() else { return false; }; + let Some(name) = self.method_name else { + return false; + }; + 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 attrs = self.fcx.tcx.hir().attrs(hir_id); for attr in attrs { - let sym::doc = attr.name_or_empty() else { continue; }; - let Some(values) = attr.meta_item_list() else { continue; }; + let sym::doc = attr.name_or_empty() else { + continue; + }; + let Some(values) = attr.meta_item_list() else { + continue; + }; for v in values { if v.name_or_empty() != sym::alias { continue; @@ -2032,8 +2039,8 @@ impl<'tcx> Candidate<'tcx> { // means they are safe to put into the // `WhereClausePick`. assert!( - !trait_ref.skip_binder().substs.has_infer() - && !trait_ref.skip_binder().substs.has_placeholders() + !trait_ref.skip_binder().args.has_infer() + && !trait_ref.skip_binder().args.has_placeholders() ); WhereClausePick(*trait_ref) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 5f924f309..72a04a02b 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -2,12 +2,13 @@ //! found or is otherwise invalid. use crate::errors; -use crate::errors::CandidateTraitNote; -use crate::errors::NoAssociatedItem; +use crate::errors::{CandidateTraitNote, NoAssociatedItem}; use crate::Expectation; use crate::FnCtxt; use rustc_ast::ast::Mutability; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_attr::parse_confusables; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use rustc_data_structures::unord::UnordSet; use rustc_errors::StashKey; use rustc_errors::{ pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, @@ -31,6 +32,7 @@ use rustc_middle::ty::fast_reject::{simplify_type, TreatParams}; use rustc_middle::ty::print::{with_crate_prefix, with_forced_trimmed_paths}; use rustc_middle::ty::IsSuggestable; use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeVisitableExt}; +use rustc_span::def_id::DefIdSet; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Symbol; use rustc_span::{edit_distance, source_map, ExpnKind, FileName, MacroKind, Span}; @@ -48,6 +50,15 @@ use rustc_hir::intravisit::Visitor; use std::cmp::{self, Ordering}; use std::iter; +/// After identifying that `full_expr` is a method call, we use this type to keep the expression's +/// components readily available to us to point at the right place in diagnostics. +#[derive(Debug, Clone, Copy)] +pub struct MethodCallComponents<'tcx> { + pub receiver: &'tcx hir::Expr<'tcx>, + pub args: &'tcx [hir::Expr<'tcx>], + pub full_expr: &'tcx hir::Expr<'tcx>, +} + impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool { let tcx = self.tcx; @@ -92,7 +103,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, self.body_id, self.param_env, - poly_trait_ref.without_const(), + poly_trait_ref, ); self.predicate_may_hold(&obligation) }) @@ -113,7 +124,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item_name: Ident, source: SelfSource<'tcx>, error: MethodError<'tcx>, - args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>, + args: Option>, expected: Expectation<'tcx>, trait_missing_method: bool, ) -> Option> { @@ -151,7 +162,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { E0034, "multiple applicable items in scope" ); - err.span_label(item_name.span, format!("multiple `{}` found", item_name)); + err.span_label(item_name.span, format!("multiple `{item_name}` found")); self.note_candidates_on_method_error( rcvr_ty, @@ -175,13 +186,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { kind, item_name ); - err.span_label(item_name.span, format!("private {}", kind)); + err.span_label(item_name.span, format!("private {kind}")); let sp = self .tcx .hir() .span_if_local(def_id) .unwrap_or_else(|| self.tcx.def_span(def_id)); - err.span_label(sp, format!("private {} defined here", kind)); + err.span_label(sp, format!("private {kind} defined here")); self.suggest_valid_traits(&mut err, out_of_scope_traits); err.emit(); } @@ -216,7 +227,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { *region, ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() }, ); - let msg = format!("you need `{}` instead of `{}`", trait_type, rcvr_ty); + let msg = format!("you need `{trait_type}` instead of `{rcvr_ty}`"); let mut kind = &self_expr.kind; while let hir::ExprKind::AddrOf(_, _, expr) | hir::ExprKind::Unary(hir::UnOp::Deref, expr) = kind @@ -255,18 +266,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn suggest_missing_writer( &self, rcvr_ty: Ty<'tcx>, - args: (&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>]), + args: MethodCallComponents<'tcx>, ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { let (ty_str, _ty_file) = self.tcx.short_ty_string(rcvr_ty); - let mut err = - struct_span_err!(self.tcx.sess, args.0.span, E0599, "cannot write into `{}`", ty_str); + let mut err = struct_span_err!( + self.tcx.sess, + args.receiver.span, + E0599, + "cannot write into `{}`", + ty_str + ); err.span_note( - args.0.span, + args.receiver.span, "must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method", ); - if let ExprKind::Lit(_) = args.0.kind { + if let ExprKind::Lit(_) = args.receiver.kind { err.span_help( - args.0.span.shrink_to_lo(), + args.receiver.span.shrink_to_lo(), "a writer is needed before this format string", ); }; @@ -280,7 +296,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rcvr_ty: Ty<'tcx>, item_name: Ident, source: SelfSource<'tcx>, - args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>, + args: Option>, sugg_span: Span, no_match_data: &mut NoMatchData<'tcx>, expected: Expectation<'tcx>, @@ -536,11 +552,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); } } else if !unsatisfied_predicates.is_empty() { - let mut type_params = FxHashMap::default(); + let mut type_params = FxIndexMap::default(); // Pick out the list of unimplemented traits on the receiver. // This is used for custom error messages with the `#[rustc_on_unimplemented]` attribute. - let mut unimplemented_traits = FxHashMap::default(); + let mut unimplemented_traits = FxIndexMap::default(); let mut unimplemented_traits_only = true; for (predicate, _parent_pred, cause) in unsatisfied_predicates { if let (ty::PredicateKind::Clause(ty::ClauseKind::Trait(p)), Some(cause)) = @@ -606,7 +622,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); type_params .entry(key) - .or_insert_with(FxHashSet::default) + .or_insert_with(UnordSet::default) .insert(obligation.to_owned()); return true; } @@ -635,7 +651,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // Point at the closure that couldn't satisfy the bound. ty::Closure(def_id, _) => bound_spans - .push((tcx.def_span(*def_id), format!("doesn't satisfy `{}`", quiet))), + .push((tcx.def_span(*def_id), format!("doesn't satisfy `{quiet}`"))), _ => {} } }; @@ -647,17 +663,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `::Item = String`. let projection_ty = pred.skip_binder().projection_ty; - let substs_with_infer_self = tcx.mk_substs_from_iter( + let args_with_infer_self = tcx.mk_args_from_iter( iter::once(Ty::new_var(tcx, ty::TyVid::from_u32(0)).into()) - .chain(projection_ty.substs.iter().skip(1)), + .chain(projection_ty.args.iter().skip(1)), ); let quiet_projection_ty = - tcx.mk_alias_ty(projection_ty.def_id, substs_with_infer_self); + tcx.mk_alias_ty(projection_ty.def_id, args_with_infer_self); let term = pred.skip_binder().term; - let obligation = format!("{} = {}", projection_ty, term); + let obligation = format!("{projection_ty} = {term}"); let quiet = with_forced_trimmed_paths!(format!( "{} = {}", quiet_projection_ty, term @@ -670,7 +686,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let p = poly_trait_ref.trait_ref; let self_ty = p.self_ty(); let path = p.print_only_trait_path(); - let obligation = format!("{}: {}", self_ty, path); + let obligation = format!("{self_ty}: {path}"); let quiet = with_forced_trimmed_paths!(format!("_: {}", path)); bound_span_label(self_ty, &obligation, &quiet); Some((obligation, self_ty)) @@ -680,8 +696,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Find all the requirements that come from a local `impl` block. - let mut skip_list: FxHashSet<_> = Default::default(); - let mut spanned_predicates = FxHashMap::default(); + let mut skip_list: UnordSet<_> = Default::default(); + let mut spanned_predicates = FxIndexMap::default(); for (p, parent_p, cause) in unsatisfied_predicates { // Extract the predicate span and parent def id of the cause, // if we have one. @@ -723,7 +739,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let span = self_ty.span.ctxt().outer_expn_data().call_site; let entry = spanned_predicates.entry(span); let entry = entry.or_insert_with(|| { - (FxHashSet::default(), FxHashSet::default(), Vec::new()) + (FxIndexSet::default(), FxIndexSet::default(), Vec::new()) }); entry.0.insert(span); entry.1.insert(( @@ -771,7 +787,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { skip_list.insert(p); let entry = spanned_predicates.entry(self_ty.span); let entry = entry.or_insert_with(|| { - (FxHashSet::default(), FxHashSet::default(), Vec::new()) + (FxIndexSet::default(), FxIndexSet::default(), Vec::new()) }); entry.2.push(p); if cause_span != *item_span { @@ -806,7 +822,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { skip_list.insert(p); let entry = spanned_predicates.entry(ident.span); let entry = entry.or_insert_with(|| { - (FxHashSet::default(), FxHashSet::default(), Vec::new()) + (FxIndexSet::default(), FxIndexSet::default(), Vec::new()) }); entry.0.insert(cause_span); entry.1.insert((ident.span, "")); @@ -823,12 +839,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut preds: Vec<_> = predicates .iter() .filter_map(|pred| format_pred(**pred)) - .map(|(p, _)| format!("`{}`", p)) + .map(|(p, _)| format!("`{p}`")) .collect(); preds.sort(); preds.dedup(); let msg = if let [pred] = &preds[..] { - format!("trait bound {} was not satisfied", pred) + format!("trait bound {pred} was not satisfied") } else { format!("the following trait bounds were not satisfied:\n{}", preds.join("\n"),) }; @@ -840,7 +856,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { unsatisfied_bounds = true; } - let mut suggested_bounds = FxHashSet::default(); + let mut suggested_bounds = UnordSet::default(); // The requirements that didn't have an `impl` span to show. let mut bound_list = unsatisfied_predicates .iter() @@ -873,7 +889,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { suggested_bounds.insert(pred); } } - format!("`{}`\nwhich is required by `{}`", p, parent_p) + format!("`{p}`\nwhich is required by `{parent_p}`") } }, }, @@ -889,8 +905,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for ((span, add_where_or_comma), obligations) in type_params.into_iter() { restrict_type_params = true; // #74886: Sort here so that the output is always the same. - let mut obligations = obligations.into_iter().collect::>(); - obligations.sort(); + let obligations = obligations.to_sorted_stable_ord(); err.span_suggestion_verbose( span, format!( @@ -952,6 +967,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { unsatisfied_bounds = true; } + } else if let ty::Adt(def, targs) = rcvr_ty.kind() && let Some(args) = args { + // This is useful for methods on arbitrary self types that might have a simple + // mutability difference, like calling a method on `Pin<&mut Self>` that is on + // `Pin<&Self>`. + if targs.len() == 1 { + let mut item_segment = hir::PathSegment::invalid(); + item_segment.ident = item_name; + for t in [Ty::new_mut_ref, Ty::new_imm_ref, |_, _, t| t] { + let new_args = tcx.mk_args_from_iter( + targs + .iter() + .map(|arg| match arg.as_type() { + Some(ty) => ty::GenericArg::from( + t(tcx, tcx.lifetimes.re_erased, ty.peel_refs()), + ), + _ => arg, + }) + ); + let rcvr_ty = Ty::new_adt(tcx, *def, new_args); + if let Ok(method) = self.lookup_method_for_diagnostic( + rcvr_ty, + &item_segment, + span, + args.full_expr, + args.receiver, + ) { + err.span_note( + tcx.def_span(method.def_id), + format!("{item_kind} is available for `{rcvr_ty}`"), + ); + } + } + } } let label_span_not_found = |err: &mut Diagnostic| { @@ -993,9 +1041,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // different from the received one // So we avoid suggestion method with Box // for instance - self.tcx.at(span).type_of(*def_id).subst_identity() + self.tcx.at(span).type_of(*def_id).instantiate_identity() != rcvr_ty - && self.tcx.at(span).type_of(*def_id).subst_identity() + && self + .tcx + .at(span) + .type_of(*def_id) + .instantiate_identity() != rcvr_ty } (Mode::Path, false, _) => true, @@ -1018,7 +1070,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .map(|impl_item| { format!( "- `{}`", - self.tcx.at(span).type_of(*impl_item).subst_identity() + self.tcx.at(span).type_of(*impl_item).instantiate_identity() ) }) .collect::>() @@ -1029,9 +1081,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "".to_string() }; err.note(format!( - "the {item_kind} was found for\n{}{}", - type_candidates, additional_types + "the {item_kind} was found for\n{type_candidates}{additional_types}" )); + } else { + 'outer: for inherent_impl_did in self.tcx.inherent_impls(adt.did()) { + for inherent_method in + self.tcx.associated_items(inherent_impl_did).in_definition_order() + { + if let Some(attr) = self.tcx.get_attr(inherent_method.def_id, sym::rustc_confusables) + && let Some(candidates) = parse_confusables(attr) + && candidates.contains(&item_name.name) + { + err.span_suggestion_verbose( + item_name.span, + format!( + "you might have meant to use `{}`", + inherent_method.name.as_str() + ), + inherent_method.name.as_str(), + Applicability::MaybeIncorrect, + ); + break 'outer; + } + } + } } } } else { @@ -1085,7 +1158,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, rcvr_ty, item_name, - args.map(|(_, args)| args.len() + 1), + args.map(|MethodCallComponents { args, .. }| args.len() + 1), source, no_match_data.out_of_scope_traits.clone(), &unsatisfied_predicates, @@ -1166,7 +1239,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, rcvr_ty: Ty<'tcx>, item_name: Ident, - args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>, + args: Option>, span: Span, err: &mut Diagnostic, sources: &mut Vec, @@ -1197,7 +1270,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None }; - let impl_ty = self.tcx.at(span).type_of(impl_did).subst_identity(); + let impl_ty = self.tcx.at(span).type_of(impl_did).instantiate_identity(); let insertion = match self.tcx.impl_trait_ref(impl_did) { None => String::new(), @@ -1222,8 +1295,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { ( format!( - "the candidate is defined in an impl{} for the type `{}`", - insertion, impl_ty, + "the candidate is defined in an impl{insertion} for the type `{impl_ty}`", ), None, ) @@ -1243,7 +1315,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::AssocKind::Fn => self .tcx .fn_sig(item.def_id) - .subst_identity() + .instantiate_identity() .inputs() .skip_binder() .get(0) @@ -1318,7 +1390,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rcvr_ty: Ty<'tcx>, source: SelfSource<'tcx>, item_name: Ident, - args: Option<(&hir::Expr<'tcx>, &[hir::Expr<'tcx>])>, + args: Option>, sugg_span: Span, ) { let mut has_unsuggestable_args = false; @@ -1326,7 +1398,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // When the "method" is resolved through dereferencing, we really want the // original type that has the associated function for accurate suggestions. // (#61411) - let impl_ty = self.tcx.type_of(*impl_did).subst_identity(); + let impl_ty = self.tcx.type_of(*impl_did).instantiate_identity(); let target_ty = self .autoderef(sugg_span, rcvr_ty) .find(|(rcvr_ty, _)| { @@ -1335,10 +1407,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) .map_or(impl_ty, |(ty, _)| ty) .peel_refs(); - if let ty::Adt(def, substs) = target_ty.kind() { + if let ty::Adt(def, args) = target_ty.kind() { // If there are any inferred arguments, (`{integer}`), we should replace // them with underscores to allow the compiler to infer them - let infer_substs = self.tcx.mk_substs_from_iter(substs.into_iter().map(|arg| { + let infer_args = self.tcx.mk_args_from_iter(args.into_iter().map(|arg| { if !arg.is_suggestable(self.tcx, true) { has_unsuggestable_args = true; match arg.unpack() { @@ -1368,7 +1440,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } })); - self.tcx.value_path_str_with_substs(def.did(), infer_substs) + self.tcx.value_path_str_with_args(def.did(), infer_args) } else { self.ty_to_value_string(target_ty) } @@ -1380,7 +1452,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let Some(assoc) = self.associated_value(*impl_did, item_name) && assoc.kind == ty::AssocKind::Fn { - let sig = self.tcx.fn_sig(assoc.def_id).subst_identity(); + 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 { @@ -1390,7 +1462,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None }; let mut applicability = Applicability::MachineApplicable; - let args = if let Some((receiver, args)) = args { + let args = if let Some(MethodCallComponents { receiver, 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::>() @@ -1425,11 +1497,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_suggestion( sugg_span, "use associated function syntax instead", - format!("{}::{}{}", ty_str, item_name, args), + format!("{ty_str}::{item_name}{args}"), applicability, ); } else { - err.help(format!("try with `{}::{}`", ty_str, item_name,)); + err.help(format!("try with `{ty_str}::{item_name}`",)); } } @@ -1445,11 +1517,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> bool { let tcx = self.tcx; let field_receiver = self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() { - ty::Adt(def, substs) if !def.is_enum() => { + ty::Adt(def, args) if !def.is_enum() => { let variant = &def.non_enum_variant(); tcx.find_field_index(item_name, variant).map(|index| { let field = &variant.fields[index]; - let field_ty = field.ty(tcx, substs); + let field_ty = field.ty(tcx, args); (field, field_ty) }) } @@ -1464,9 +1536,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let expr_span = expr.span.to(item_name.span); err.multipart_suggestion( format!( - "to call the function stored in `{}`, \ + "to call the function stored in `{item_name}`, \ surround the field access with parentheses", - item_name, ), vec![ (expr_span.shrink_to_lo(), '('.to_string()), @@ -1489,7 +1560,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let field_kind = if is_accessible { "field" } else { "private field" }; - err.span_label(item_name.span, format!("{}, not a method", field_kind)); + err.span_label(item_name.span, format!("{field_kind}, not a method")); return true; } false @@ -1546,7 +1617,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let range_def_id = self.tcx.require_lang_item(lang_item.unwrap(), None); - let range_ty = self.tcx.type_of(range_def_id).subst(self.tcx, &[actual.into()]); + let range_ty = + self.tcx.type_of(range_def_id).instantiate(self.tcx, &[actual.into()]); let pick = self.lookup_probe_for_diagnostic( item_name, @@ -1609,7 +1681,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { || found_assoc(tcx.types.u64) || found_assoc(tcx.types.u128) || found_assoc(tcx.types.f32) - || found_assoc(tcx.types.f32); + || found_assoc(tcx.types.f64); if found_candidate && actual.is_numeric() && !actual.has_concrete_skeleton() @@ -1641,8 +1713,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lit.span, format!( "you must specify a concrete type for this numeric value, \ - like `{}`", - concrete_type + like `{concrete_type}`" ), format!("{snippet}_{concrete_type}"), Applicability::MaybeIncorrect, @@ -1657,8 +1728,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let parent_node = self.tcx.hir().get_parent(hir_id); let msg = format!( - "you must specify a type for this binding, like `{}`", - concrete_type, + "you must specify a type for this binding, like `{concrete_type}`", ); match (filename, parent_node) { @@ -1699,10 +1769,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// we try to suggest `rect.area()` pub(crate) fn suggest_assoc_method_call(&self, segs: &[PathSegment<'_>]) { debug!("suggest_assoc_method_call segs: {:?}", segs); - let [seg1, seg2] = segs else { return; }; + let [seg1, seg2] = segs else { + return; + }; let Some(mut diag) = - self.tcx.sess.diagnostic().steal_diagnostic(seg1.ident.span, StashKey::CallAssocMethod) - else { return }; + self.tcx.sess.diagnostic().steal_diagnostic(seg1.ident.span, StashKey::CallAssocMethod) + else { + return; + }; let map = self.infcx.tcx.hir(); let body_id = self.tcx.hir().body_owned_by(self.body_id); @@ -1766,7 +1840,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { if let SelfSource::MethodCall(expr) = source && let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id() - && let Some((fields, substs)) = + && 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)); @@ -1801,7 +1875,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) }, candidate_field, - substs, + args, vec![], mod_id, ) @@ -1839,18 +1913,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item_name: Ident, ) { let tcx = self.tcx; - let SelfSource::MethodCall(expr) = source else { return; }; + let SelfSource::MethodCall(expr) = source else { + return; + }; let call_expr = tcx.hir().expect_expr(tcx.hir().parent_id(expr.hir_id)); - let ty::Adt(kind, substs) = actual.kind() else { return; }; + let ty::Adt(kind, args) = actual.kind() else { + return; + }; match kind.adt_kind() { ty::AdtKind::Enum => { let matching_variants: Vec<_> = kind .variants() .iter() .flat_map(|variant| { - let [field] = &variant.fields.raw[..] else { return None; }; - let field_ty = field.ty(tcx, substs); + let [field] = &variant.fields.raw[..] else { + return None; + }; + let field_ty = field.ty(tcx, args); // Skip `_`, since that'll just lead to ambiguity. if self.resolve_vars_if_possible(field_ty).is_ty_var() { @@ -1885,7 +1965,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match &matching_variants[..] { [(_, field, pick)] => { - let self_ty = field.ty(tcx, substs); + let self_ty = field.ty(tcx, args); err.span_note( tcx.def_span(pick.item.def_id), format!("the method `{item_name}` exists on the type `{self_ty}`"), @@ -1927,15 +2007,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Target wrapper types - types that wrap or pretend to wrap another type, // perhaps this inner type is meant to be called? ty::AdtKind::Struct | ty::AdtKind::Union => { - let [first] = ***substs else { return; }; - let ty::GenericArgKind::Type(ty) = first.unpack() else { return; }; + let [first] = ***args else { + return; + }; + let ty::GenericArgKind::Type(ty) = first.unpack() else { + return; + }; let Ok(pick) = self.lookup_probe_for_diagnostic( item_name, ty, call_expr, ProbeScope::TraitsInScope, None, - ) else { return; }; + ) else { + return; + }; let name = self.ty_to_value_string(actual); let inner_id = kind.did(); @@ -2037,7 +2123,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Adt(def, _) => Some(def.did()), _ => None, }) - .collect::>(); + .collect::>(); let mut spans: MultiSpan = def_ids .iter() .filter_map(|def_id| { @@ -2100,7 +2186,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred))) = pred.kind().no_bound_vars() else { - continue + continue; }; let adt = match trait_pred.self_ty().ty_adt_def() { Some(adt) if adt.did().is_local() => adt, @@ -2150,7 +2236,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some((last_self_name, _, ref mut last_trait_names)) = derives_grouped.last_mut() { if last_self_name == &self_name { - last_trait_names.push_str(format!(", {}", trait_name).as_str()); + last_trait_names.push_str(format!(", {trait_name}").as_str()); continue; } } @@ -2182,8 +2268,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for (self_name, self_span, traits) in &derives_grouped { err.span_suggestion_verbose( self_span.shrink_to_lo(), - format!("consider annotating `{}` with `#[derive({})]`", self_name, traits), - format!("#[derive({})]\n", traits), + format!("consider annotating `{self_name}` with `#[derive({traits})]`"), + format!("#[derive({traits})]\n"), Applicability::MaybeIncorrect, ); } @@ -2197,7 +2283,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item_name: Ident, expected: Expectation<'tcx>, ) { - let SelfSource::QPath(ty) = self_source else { return; }; + let SelfSource::QPath(ty) = self_source else { + return; + }; for (deref_ty, _) in self.autoderef(rustc_span::DUMMY_SP, rcvr_ty).skip(1) { if let Ok(pick) = self.probe_for_name( Mode::Path, @@ -2214,7 +2302,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // just changing the path. && pick.item.fn_has_self_parameter && let Some(self_ty) = - self.tcx.fn_sig(pick.item.def_id).subst_identity().inputs().skip_binder().get(0) + self.tcx.fn_sig(pick.item.def_id).instantiate_identity().inputs().skip_binder().get(0) && self_ty.is_ref() { let suggested_path = match deref_ty.kind() { @@ -2255,7 +2343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Print out the type for use in value namespace. fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String { match ty.kind() { - ty::Adt(def, substs) => self.tcx.def_path_str_with_substs(def.did(), substs), + ty::Adt(def, args) => self.tcx.def_path_str_with_args(def.did(), args), _ => self.ty_to_string(ty), } } @@ -2429,7 +2517,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if pick.autoderefs == 0 && !skip { err.span_label( pick.item.ident(self.tcx).span, - format!("the method is available for `{}` here", rcvr_ty), + format!("the method is available for `{rcvr_ty}` here"), ); } break; @@ -2475,13 +2563,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if pick.autoderefs == 0 && !skip { err.span_label( pick.item.ident(self.tcx).span, - format!("the method is available for `{}` here", new_rcvr_t), + format!("the method is available for `{new_rcvr_t}` here"), ); err.multipart_suggestion( "consider wrapping the receiver expression with the \ appropriate type", vec![ - (rcvr.span.shrink_to_lo(), format!("{}({}", pre, post)), + (rcvr.span.shrink_to_lo(), format!("{pre}({post}")), (rcvr.span.shrink_to_hi(), ")".to_string()), ], Applicability::MaybeIncorrect, @@ -2651,7 +2739,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Nothing, } let ast_generics = hir.get_generics(id.owner.def_id).unwrap(); - let trait_def_ids: FxHashSet = ast_generics + let trait_def_ids: DefIdSet = ast_generics .bounds_for_param(def_id) .flat_map(|bp| bp.bounds.iter()) .filter_map(|bound| bound.trait_ref()?.trait_def_id()) @@ -2721,7 +2809,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; err.span_suggestions( sp, - message(format!("add {} supertrait for", article)), + message(format!("add {article} supertrait for")), candidates.iter().map(|t| { format!("{} {}", sep, self.tcx.def_path_str(t.def_id),) }), @@ -2752,7 +2840,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.impl_polarity(*imp_did) == ty::ImplPolarity::Negative }) .any(|imp_did| { - let imp = self.tcx.impl_trait_ref(imp_did).unwrap().subst_identity(); + let imp = + self.tcx.impl_trait_ref(imp_did).unwrap().instantiate_identity(); let imp_simp = simplify_type(self.tcx, imp.self_ty(), TreatParams::ForLookup); imp_simp.is_some_and(|s| s == simp_rcvr_ty) @@ -2789,7 +2878,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { trait_infos => { let mut msg = message(param_type.map_or_else( || "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented. - |param| format!("restrict type parameter `{}` with", param), + |param| format!("restrict type parameter `{param}` with"), )); for (i, trait_info) in trait_infos.iter().enumerate() { msg.push_str(&format!( @@ -2813,8 +2902,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } trait_infos => { let mut msg = format!( - "the following traits define an item `{}`, but are explicitly unimplemented:", - item_name + "the following traits define an item `{item_name}`, but are explicitly unimplemented:" ); for trait_info in trait_infos { msg.push_str(&format!("\n{}", self.tcx.def_path_str(trait_info.def_id))); @@ -2834,9 +2922,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { found: Ty<'tcx>, expected: Ty<'tcx>, ) -> bool { - let Some((_def_id_or_name, output, _inputs)) = - self.extract_callable_info(found) else { - return false; + let Some((_def_id_or_name, output, _inputs)) = self.extract_callable_info(found) else { + return false; }; if !self.can_coerce(output, expected) { @@ -2907,7 +2994,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This occurs for UFCS desugaring of `T::method`, where there is no // receiver expression for the method call, and thus no autoderef. if let SelfSource::QPath(_) = source { - return is_local(self.resolve_vars_with_obligations(rcvr_ty)); + return is_local(rcvr_ty); } self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty)) @@ -2955,7 +3042,7 @@ pub fn all_traits(tcx: TyCtxt<'_>) -> Vec { fn print_disambiguation_help<'tcx>( item_name: Ident, - args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>, + args: Option>, err: &mut Diagnostic, trait_name: String, rcvr_ty: Ty<'_>, @@ -2967,7 +3054,11 @@ fn print_disambiguation_help<'tcx>( fn_has_self_parameter: bool, ) { let mut applicability = Applicability::MachineApplicable; - let (span, sugg) = if let (ty::AssocKind::Fn, Some((receiver, args))) = (kind, args) { + let (span, sugg) = if let ( + ty::AssocKind::Fn, + Some(MethodCallComponents { receiver, args, .. }), + ) = (kind, args) + { let args = format!( "({}{})", rcvr_ty.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str()), @@ -2981,13 +3072,13 @@ fn print_disambiguation_help<'tcx>( .join(", "), ); let trait_name = if !fn_has_self_parameter { - format!("<{} as {}>", rcvr_ty, trait_name) + format!("<{rcvr_ty} as {trait_name}>") } else { trait_name }; - (span, format!("{}::{}{}", trait_name, item_name, args)) + (span, format!("{trait_name}::{item_name}{args}")) } else { - (span.with_hi(item_name.span.lo()), format!("<{} as {}>::", rcvr_ty, trait_name)) + (span.with_hi(item_name.span.lo()), format!("<{rcvr_ty} as {trait_name}>::")) }; err.span_suggestion_verbose( span, @@ -2995,7 +3086,7 @@ fn print_disambiguation_help<'tcx>( "disambiguate the {} for {}", def_kind_descr, if let Some(candidate) = candidate { - format!("candidate #{}", candidate) + format!("candidate #{candidate}") } else { "the candidate".to_string() }, diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 1eae258c1..a283cd1ab 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}; +use rustc_errors::{self, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder}; use rustc_hir as hir; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::traits::ObligationCauseCode; @@ -380,33 +380,93 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; - let mut suggest_deref_binop = |lhs_deref_ty: Ty<'tcx>| { - if self - .lookup_op_method( - lhs_deref_ty, - Some((rhs_expr, rhs_ty)), - Op::Binary(op, is_assign), - expected, - ) - .is_ok() - { - let msg = format!( - "`{}{}` can be used on `{}` if you dereference the left-hand side", - op.node.as_str(), - match is_assign { - IsAssign::Yes => "=", - IsAssign::No => "", - }, - lhs_deref_ty, - ); - err.span_suggestion_verbose( - lhs_expr.span.shrink_to_lo(), - msg, - "*", - rustc_errors::Applicability::MachineApplicable, - ); - } - }; + let suggest_deref_binop = + |err: &mut DiagnosticBuilder<'_, _>, lhs_deref_ty: Ty<'tcx>| { + if self + .lookup_op_method( + lhs_deref_ty, + Some((rhs_expr, rhs_ty)), + Op::Binary(op, is_assign), + expected, + ) + .is_ok() + { + let msg = format!( + "`{}{}` can be used on `{}` if you dereference the left-hand side", + op.node.as_str(), + match is_assign { + IsAssign::Yes => "=", + IsAssign::No => "", + }, + lhs_deref_ty, + ); + err.span_suggestion_verbose( + lhs_expr.span.shrink_to_lo(), + msg, + "*", + rustc_errors::Applicability::MachineApplicable, + ); + } + }; + + let suggest_different_borrow = + |err: &mut DiagnosticBuilder<'_, _>, + lhs_adjusted_ty, + lhs_new_mutbl: Option, + rhs_adjusted_ty, + rhs_new_mutbl: Option| { + if self + .lookup_op_method( + lhs_adjusted_ty, + Some((rhs_expr, rhs_adjusted_ty)), + Op::Binary(op, is_assign), + expected, + ) + .is_ok() + { + let op_str = op.node.as_str(); + err.note(format!("an implementation for `{lhs_adjusted_ty} {op_str} {rhs_adjusted_ty}` exists")); + + if let Some(lhs_new_mutbl) = lhs_new_mutbl + && let Some(rhs_new_mutbl) = rhs_new_mutbl + && lhs_new_mutbl.is_not() + && rhs_new_mutbl.is_not() { + err.multipart_suggestion_verbose( + "consider reborrowing both sides", + vec![ + (lhs_expr.span.shrink_to_lo(), "&*".to_string()), + (rhs_expr.span.shrink_to_lo(), "&*".to_string()) + ], + rustc_errors::Applicability::MachineApplicable, + ); + } else { + let mut suggest_new_borrow = |new_mutbl: ast::Mutability, sp: Span| { + // Can reborrow (&mut -> &) + if new_mutbl.is_not() { + err.span_suggestion_verbose( + sp.shrink_to_lo(), + "consider reborrowing this side", + "&*", + rustc_errors::Applicability::MachineApplicable, + ); + // Works on &mut but have & + } else { + err.span_help( + sp, + "consider making this expression a mutable borrow", + ); + } + }; + + if let Some(lhs_new_mutbl) = lhs_new_mutbl { + suggest_new_borrow(lhs_new_mutbl, lhs_expr.span); + } + if let Some(rhs_new_mutbl) = rhs_new_mutbl { + suggest_new_borrow(rhs_new_mutbl, rhs_expr.span); + } + } + } + }; let is_compatible_after_call = |lhs_ty, rhs_ty| { self.lookup_op_method( @@ -429,15 +489,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else if is_assign == IsAssign::Yes && let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) { - suggest_deref_binop(lhs_deref_ty); + suggest_deref_binop(&mut err, lhs_deref_ty); } else if is_assign == IsAssign::No - && let Ref(_, lhs_deref_ty, _) = lhs_ty.kind() + && let Ref(region, lhs_deref_ty, mutbl) = lhs_ty.kind() { if self.type_is_copy_modulo_regions( self.param_env, *lhs_deref_ty, ) { - suggest_deref_binop(*lhs_deref_ty); + suggest_deref_binop(&mut err, *lhs_deref_ty); + } else { + let lhs_inv_mutbl = mutbl.invert(); + let lhs_inv_mutbl_ty = Ty::new_ref( + self.tcx, + *region, + ty::TypeAndMut { + ty: *lhs_deref_ty, + mutbl: lhs_inv_mutbl, + }, + ); + + suggest_different_borrow( + &mut err, + lhs_inv_mutbl_ty, + Some(lhs_inv_mutbl), + rhs_ty, + None, + ); + + if let Ref(region, rhs_deref_ty, mutbl) = rhs_ty.kind() { + let rhs_inv_mutbl = mutbl.invert(); + let rhs_inv_mutbl_ty = Ty::new_ref( + self.tcx, + *region, + ty::TypeAndMut { + ty: *rhs_deref_ty, + mutbl: rhs_inv_mutbl, + }, + ); + + suggest_different_borrow( + &mut err, + lhs_ty, + None, + rhs_inv_mutbl_ty, + Some(rhs_inv_mutbl), + ); + suggest_different_borrow( + &mut err, + lhs_inv_mutbl_ty, + Some(lhs_inv_mutbl), + rhs_inv_mutbl_ty, + Some(rhs_inv_mutbl), + ); + } } } else if self.suggest_fn_call(&mut err, lhs_expr, lhs_ty, |lhs_ty| { is_compatible_after_call(lhs_ty, rhs_ty) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 42f4531c0..8fc236f46 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1,3 +1,4 @@ +use crate::gather_locals::DeclOrigin; use crate::{errors, FnCtxt, RawTy}; use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; @@ -77,6 +78,13 @@ struct TopInfo<'tcx> { span: Option, } +#[derive(Copy, Clone)] +struct PatInfo<'tcx, 'a> { + binding_mode: BindingMode, + top_info: TopInfo<'tcx>, + decl_origin: Option>, +} + impl<'tcx> FnCtxt<'_, 'tcx> { fn pattern_cause(&self, ti: TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> { let code = @@ -135,15 +143,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// Otherwise, `Some(span)` represents the span of a type expression /// which originated the `expected` type. - pub fn check_pat_top( + pub(crate) fn check_pat_top( &self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, span: Option, origin_expr: Option<&'tcx hir::Expr<'tcx>>, + decl_origin: Option>, ) { let info = TopInfo { expected, origin_expr, span }; - self.check_pat(pat, expected, INITIAL_BM, info); + let pat_info = PatInfo { binding_mode: INITIAL_BM, top_info: info, decl_origin }; + self.check_pat(pat, expected, pat_info); } /// Type check the given `pat` against the `expected` type @@ -151,14 +161,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// Outside of this module, `check_pat_top` should always be used. /// Conversely, inside this module, `check_pat_top` should never be used. - #[instrument(level = "debug", skip(self, ti))] - fn check_pat( - &self, - pat: &'tcx Pat<'tcx>, - expected: Ty<'tcx>, - def_bm: BindingMode, - ti: TopInfo<'tcx>, - ) { + #[instrument(level = "debug", skip(self, pat_info))] + fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>) { + let PatInfo { binding_mode: def_bm, top_info: ti, .. } = pat_info; let path_res = match &pat.kind { PatKind::Path(qpath) => { Some(self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span)) @@ -167,38 +172,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res)); let (expected, def_bm) = self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode); + let pat_info = + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin: pat_info.decl_origin }; let ty = match pat.kind { PatKind::Wild => 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) => { - self.check_pat_ident(pat, ba, var_id, sub, expected, def_bm, ti) + self.check_pat_ident(pat, ba, var_id, sub, expected, pat_info) } PatKind::TupleStruct(ref qpath, subpats, ddpos) => { - self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, def_bm, ti) + self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, pat_info) } PatKind::Path(ref qpath) => { self.check_pat_path(pat, qpath, path_res.unwrap(), expected, ti) } PatKind::Struct(ref qpath, fields, has_rest_pat) => { - self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, def_bm, ti) + self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, pat_info) } PatKind::Or(pats) => { for pat in pats { - self.check_pat(pat, expected, def_bm, ti); + self.check_pat(pat, expected, pat_info); } expected } PatKind::Tuple(elements, ddpos) => { - self.check_pat_tuple(pat.span, elements, ddpos, expected, def_bm, ti) - } - PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, def_bm, ti), - PatKind::Ref(inner, mutbl) => { - self.check_pat_ref(pat, inner, mutbl, expected, def_bm, ti) + self.check_pat_tuple(pat.span, elements, ddpos, expected, pat_info) } + PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info), + PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info), PatKind::Slice(before, slice, after) => { - self.check_pat_slice(pat.span, before, slice, after, expected, def_bm, ti) + self.check_pat_slice(pat.span, before, slice, after, expected, pat_info) } }; @@ -335,8 +340,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, mut def_bm: BindingMode, ) -> (Ty<'tcx>, BindingMode) { - let mut expected = self.resolve_vars_with_obligations(expected); - + let mut expected = self.try_structurally_resolve_type(pat.span, expected); // Peel off as many `&` or `&mut` from the scrutinee type as possible. For example, // for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches // the `Some(5)` which is not of type Ref. @@ -353,7 +357,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Preserve the reference type. We'll need it later during THIR lowering. pat_adjustments.push(expected); - expected = inner_ty; + expected = self.try_structurally_resolve_type(pat.span, inner_ty); def_bm = ty::BindByReference(match def_bm { // If default binding mode is by value, make it `ref` or `ref mut` // (depending on whether we observe `&` or `&mut`). @@ -517,7 +521,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn endpoint_has_type(&self, err: &mut Diagnostic, span: Span, ty: Ty<'_>) { if !ty.references_error() { - err.span_label(span, format!("this is of type `{}`", ty)); + err.span_label(span, format!("this is of type `{ty}`")); } } @@ -541,7 +545,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); let msg = |ty| { let ty = self.resolve_vars_if_possible(ty); - format!("this is of type `{}` but it should be `char` or numeric", ty) + format!("this is of type `{ty}` but it should be `char` or numeric") }; let mut one_side_err = |first_span, first_ty, second: Option<(bool, Ty<'tcx>, Span)>| { err.span_label(first_span, msg(first_ty)); @@ -581,9 +585,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { var_id: HirId, sub: Option<&'tcx Pat<'tcx>>, expected: Ty<'tcx>, - def_bm: BindingMode, - ti: TopInfo<'tcx>, + pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { + let PatInfo { binding_mode: def_bm, top_info: ti, .. } = pat_info; + // Determine the binding mode... let bm = match ba { hir::BindingAnnotation::NONE => def_bm, @@ -621,12 +626,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if let Some(p) = sub { - self.check_pat(p, expected, def_bm, ti); + self.check_pat(p, expected, pat_info); } local_ty } + /// When a variable is bound several times in a `PatKind::Or`, it'll resolve all of the + /// subsequent bindings of the same name to the first usage. Verify that all of these + /// bindings have the same type by comparing them all against the type of that first pat. fn check_binding_alt_eq_ty( &self, ba: hir::BindingAnnotation, @@ -638,7 +646,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let var_ty = self.local_ty(span, var_id); if let Some(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) { let hir = self.tcx.hir(); - let var_ty = self.resolve_vars_with_obligations(var_ty); + let var_ty = self.resolve_vars_if_possible(var_ty); let msg = format!("first introduced with type `{var_ty}` here"); err.span_label(hir.span(var_id), msg); let in_match = hir.parent_iter(var_id).any(|(_, n)| { @@ -651,12 +659,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) }); let pre = if in_match { "in the same arm, " } else { "" }; - err.note(format!("{}a binding must have the same type in all alternatives", pre)); + err.note(format!("{pre}a binding must have the same type in all alternatives")); self.suggest_adding_missing_ref_or_removing_ref( &mut err, span, var_ty, - self.resolve_vars_with_obligations(ty), + self.resolve_vars_if_possible(ty), ba, ); err.emit(); @@ -753,7 +761,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match binding_parent { // Check that there is explicit type (ie this is not a closure param with inferred type) // so we don't suggest moving something to the type that does not exist - hir::Node::Param(hir::Param { ty_span, .. }) if binding.span != *ty_span => { + hir::Node::Param(hir::Param { ty_span, pat, .. }) if pat.span != *ty_span => { err.multipart_suggestion_verbose( format!("to take parameter `{binding}` by reference, move `&{mutability}` to the type"), vec![ @@ -841,8 +849,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fields: &'tcx [hir::PatField<'tcx>], has_rest_pat: bool, expected: Ty<'tcx>, - def_bm: BindingMode, - ti: TopInfo<'tcx>, + pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { // Resolve the path and check the definition for errors. let (variant, pat_ty) = match self.check_struct_path(qpath, pat.hir_id) { @@ -850,18 +857,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Err(guar) => { let err = Ty::new_error(self.tcx, guar); for field in fields { - let ti = ti; - self.check_pat(field.pat, err, def_bm, ti); + self.check_pat(field.pat, err, pat_info); } return err; } }; // Type-check the path. - self.demand_eqtype_pat(pat.span, expected, pat_ty, ti); + 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, def_bm, ti) { + 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) @@ -922,7 +928,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match opt_def_id { Some(def_id) => match self.tcx.hir().get_if_local(def_id) { Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Const(_, body_id), .. + kind: hir::ItemKind::Const(_, _, body_id), + .. })) => match self.tcx.hir().get(body_id.hir_id) { hir::Node::Expr(expr) => { if hir::is_range_literal(expr) { @@ -1026,13 +1033,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { subpats: &'tcx [Pat<'tcx>], ddpos: hir::DotDotPos, expected: Ty<'tcx>, - def_bm: BindingMode, - ti: TopInfo<'tcx>, + pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { + let PatInfo { binding_mode: def_bm, top_info: ti, decl_origin } = pat_info; let tcx = self.tcx; let on_error = |e| { for pat in subpats { - self.check_pat(pat, Ty::new_error(tcx, e), def_bm, ti); + self.check_pat( + pat, + Ty::new_error(tcx, e), + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, + ); } }; let report_unexpected_res = |res: Res| { @@ -1092,13 +1103,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if subpats.len() == variant.fields.len() || subpats.len() < variant.fields.len() && ddpos.as_opt_usize().is_some() { - let ty::Adt(_, substs) = pat_ty.kind() else { + let ty::Adt(_, args) = pat_ty.kind() else { bug!("unexpected pattern type {:?}", pat_ty); }; for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) { let field = &variant.fields[FieldIdx::from_usize(i)]; - let field_ty = self.field_ty(subpat.span, field, substs); - self.check_pat(subpat, field_ty, def_bm, ti); + let field_ty = self.field_ty(subpat.span, field, args); + self.check_pat( + subpat, + field_ty, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, + ); self.tcx.check_stability( variant.fields[FieldIdx::from_usize(i)].did, @@ -1180,10 +1195,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // with the subpatterns directly in the tuple variant pattern, e.g., `V_i(p_0, .., p_N)`. let missing_parentheses = match (&expected.kind(), fields, had_err) { // #67037: only do this if we could successfully type-check the expected type against - // the tuple struct pattern. Otherwise the substs could get out of range on e.g., + // the tuple struct pattern. Otherwise the args could get out of range on e.g., // `let P() = U;` where `P != U` with `struct P(T);`. - (ty::Adt(_, substs), [field], false) => { - let field_ty = self.field_ty(pat_span, field, substs); + (ty::Adt(_, args), [field], false) => { + let field_ty = self.field_ty(pat_span, field, args); match field_ty.kind() { ty::Tuple(fields) => fields.len() == subpats.len(), _ => false, @@ -1282,8 +1297,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { elements: &'tcx [Pat<'tcx>], ddpos: hir::DotDotPos, expected: Ty<'tcx>, - def_bm: BindingMode, - ti: TopInfo<'tcx>, + pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { let tcx = self.tcx; let mut expected_len = elements.len(); @@ -1304,18 +1318,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); let element_tys = tcx.mk_type_list_from_iter(element_tys_iter); let pat_ty = Ty::new_tup(tcx, element_tys); - if let Some(mut err) = self.demand_eqtype_pat_diag(span, expected, pat_ty, ti) { + if let Some(mut err) = + self.demand_eqtype_pat_diag(span, expected, pat_ty, pat_info.top_info) + { let reported = err.emit(); // Walk subpatterns with an expected type of `err` in this case to silence // further errors being emitted when using the bindings. #50333 let element_tys_iter = (0..max_len).map(|_| Ty::new_error(tcx, reported)); for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { - self.check_pat(elem, Ty::new_error(tcx, reported), def_bm, ti); + self.check_pat(elem, Ty::new_error(tcx, reported), pat_info); } Ty::new_tup_from_iter(tcx, element_tys_iter) } else { for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { - self.check_pat(elem, element_tys[i], def_bm, ti); + self.check_pat(elem, element_tys[i], pat_info); } pat_ty } @@ -1328,12 +1344,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { variant: &'tcx ty::VariantDef, fields: &'tcx [hir::PatField<'tcx>], has_rest_pat: bool, - def_bm: BindingMode, - ti: TopInfo<'tcx>, + pat_info: PatInfo<'tcx, '_>, ) -> bool { let tcx = self.tcx; - let ty::Adt(adt, substs) = adt_ty.kind() else { + let ty::Adt(adt, args) = adt_ty.kind() else { span_bug!(pat.span, "struct pattern is not an ADT"); }; @@ -1366,7 +1381,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .map(|(i, f)| { self.write_field_index(field.hir_id, *i); self.tcx.check_stability(f.did, Some(pat.hir_id), span, None); - self.field_ty(span, f, substs) + self.field_ty(span, f, args) }) .unwrap_or_else(|| { inexistent_fields.push(field); @@ -1376,7 +1391,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; - self.check_pat(field.pat, field_ty, def_bm, ti); + self.check_pat(field.pat, field_ty, pat_info); } let mut unmentioned_fields = variant @@ -1394,7 +1409,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &inexistent_fields, &mut unmentioned_fields, variant, - substs, + args, )) } else { None @@ -1564,7 +1579,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { inexistent_fields: &[&hir::PatField<'tcx>], unmentioned_fields: &mut Vec<(&'tcx ty::FieldDef, Ident)>, variant: &ty::VariantDef, - substs: &'tcx ty::List>, + args: &'tcx ty::List>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let tcx = self.tcx; let (field_names, t, plural) = if inexistent_fields.len() == 1 { @@ -1634,7 +1649,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.field_ty( unmentioned_fields[0].1.span, unmentioned_fields[0].0, - substs, + args, ), ) => {} _ => { @@ -1708,7 +1723,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_suggestion_verbose( qpath.span().shrink_to_hi().to(pat.span.shrink_to_hi()), "use the tuple variant pattern syntax instead", - format!("({})", sugg), + format!("({sugg})"), appl, ); return Some(err); @@ -1810,7 +1825,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { const LIMIT: usize = 3; match witnesses { [] => bug!(), - [witness] => format!("`{}`", witness), + [witness] => format!("`{witness}`"), [head @ .., tail] if head.len() < LIMIT => { let head: Vec<_> = head.iter().map(<_>::to_string).collect(); format!("`{}` and `{}`", head.join("`, `"), tail) @@ -1832,8 +1847,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "ensure that all fields are mentioned explicitly by adding the suggested fields", ); lint.note(format!( - "the pattern is of type `{}` and the `non_exhaustive_omitted_patterns` attribute was found", - ty, + "the pattern is of type `{ty}` and the `non_exhaustive_omitted_patterns` attribute was found", )); lint @@ -1862,10 +1876,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { let fields = unmentioned_fields .iter() - .map(|(_, name)| format!("`{}`", name)) + .map(|(_, name)| format!("`{name}`")) .collect::>() .join(", "); - format!("fields {}{}", fields, inaccessible) + format!("fields {fields}{inaccessible}") }; let mut err = struct_span_err!( self.tcx.sess, @@ -1874,7 +1888,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "pattern does not mention {}", field_names ); - err.span_label(pat.span, format!("missing {}", field_names)); + err.span_label(pat.span, format!("missing {field_names}")); let len = unmentioned_fields.len(); let (prefix, postfix, sp) = match fields { [] => match &pat.kind { @@ -1907,11 +1921,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter() .map(|(_, name)| { let field_name = name.to_string(); - if is_number(&field_name) { - format!("{}: _", field_name) - } else { - field_name - } + if is_number(&field_name) { format!("{field_name}: _") } else { field_name } }) .collect::>() .join(", "), @@ -1928,7 +1938,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { s = pluralize!(len), them = if len == 1 { "it" } else { "them" }, ), - format!("{}..{}", prefix, postfix), + format!("{prefix}..{postfix}"), Applicability::MachineApplicable, ); err @@ -1939,8 +1949,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, inner: &'tcx Pat<'tcx>, expected: Ty<'tcx>, - def_bm: BindingMode, - ti: TopInfo<'tcx>, + pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { let tcx = self.tcx; let (box_ty, inner_ty) = match self.check_dereferenceable(span, expected, inner) { @@ -1952,7 +1961,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: inner.span, }); let box_ty = Ty::new_box(tcx, inner_ty); - self.demand_eqtype_pat(span, expected, box_ty, ti); + self.demand_eqtype_pat(span, expected, box_ty, pat_info.top_info); (box_ty, inner_ty) } Err(guar) => { @@ -1960,7 +1969,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (err, err) } }; - self.check_pat(inner, inner_ty, def_bm, ti); + self.check_pat(inner, inner_ty, pat_info); box_ty } @@ -1971,8 +1980,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { inner: &'tcx Pat<'tcx>, mutbl: hir::Mutability, expected: Ty<'tcx>, - def_bm: BindingMode, - ti: TopInfo<'tcx>, + pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { let tcx = self.tcx; let expected = self.shallow_resolve(expected); @@ -1994,7 +2002,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty); debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty); - let err = self.demand_eqtype_pat_diag(pat.span, expected, ref_ty, ti); + let err = self.demand_eqtype_pat_diag( + pat.span, + expected, + ref_ty, + pat_info.top_info, + ); // Look for a case like `fn foo(&foo: u32)` and suggest // `fn foo(foo: &u32)` @@ -2011,7 +2024,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (err, err) } }; - self.check_pat(inner, inner_ty, def_bm, ti); + self.check_pat(inner, inner_ty, pat_info); ref_ty } @@ -2022,6 +2035,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ty::new_ref(self.tcx, region, mt) } + fn try_resolve_slice_ty_to_array_ty( + &self, + before: &'tcx [Pat<'tcx>], + slice: Option<&'tcx Pat<'tcx>>, + span: Span, + ) -> Option> { + if !slice.is_none() { + return None; + } + + let tcx = self.tcx; + let len = before.len(); + let ty_var_origin = + TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span }; + let inner_ty = self.next_ty_var(ty_var_origin); + + Some(Ty::new_array(tcx, inner_ty, len.try_into().unwrap())) + } + + /// Used to determines whether we can infer the expected type in the slice pattern to be of type array. + /// This is only possible if we're in an irrefutable pattern. If we were to allow this in refutable + /// patterns we wouldn't e.g. report ambiguity in the following situation: + /// + /// ```ignore(rust) + /// struct Zeroes; + /// const ARR: [usize; 2] = [0; 2]; + /// const ARR2: [usize; 2] = [2; 2]; + /// + /// impl Into<&'static [usize; 2]> for Zeroes { + /// fn into(self) -> &'static [usize; 2] { + /// &ARR + /// } + /// } + /// + /// impl Into<&'static [usize]> for Zeroes { + /// fn into(self) -> &'static [usize] { + /// &ARR2 + /// } + /// } + /// + /// fn main() { + /// let &[a, b]: &[usize] = Zeroes.into() else { + /// .. + /// }; + /// } + /// ``` + /// + /// If we're in an irrefutable pattern we prefer the array impl candidate given that + /// the slice impl candidate would be be rejected anyway (if no ambiguity existed). + fn pat_is_irrefutable(&self, decl_origin: Option>) -> bool { + match decl_origin { + Some(DeclOrigin::LocalDecl { els: None }) => true, + Some(DeclOrigin::LocalDecl { els: Some(_) } | DeclOrigin::LetExpr) | None => false, + } + } + /// Type check a slice pattern. /// /// Syntactically, these look like `[pat_0, ..., pat_n]`. @@ -2039,10 +2108,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { slice: Option<&'tcx Pat<'tcx>>, after: &'tcx [Pat<'tcx>], expected: Ty<'tcx>, - def_bm: BindingMode, - ti: TopInfo<'tcx>, + pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { + let expected = self.try_structurally_resolve_type(span, expected); + + // If the pattern is irrefutable and `expected` is an infer ty, we try to equate it + // to an array if the given pattern allows it. See issue #76342 + if self.pat_is_irrefutable(pat_info.decl_origin) && expected.is_ty_var() { + if let Some(resolved_arr_ty) = + self.try_resolve_slice_ty_to_array_ty(before, slice, span) + { + debug!(?resolved_arr_ty); + self.demand_eqtype(span, expected, resolved_arr_ty); + } + } + let expected = self.structurally_resolve_type(span, expected); + debug!(?expected); + let (element_ty, opt_slice_ty, inferred) = match *expected.kind() { // An array, so we might have something like `let [a, b, c] = [0, 1, 2];`. ty::Array(element_ty, len) => { @@ -2057,10 +2140,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Slice(element_ty) => (element_ty, Some(expected), expected), // The expected type must be an array or slice, but was neither, so error. _ => { - let guar = expected - .error_reported() - .err() - .unwrap_or_else(|| self.error_expected_array_or_slice(span, expected, ti)); + let guar = expected.error_reported().err().unwrap_or_else(|| { + self.error_expected_array_or_slice(span, expected, pat_info.top_info) + }); let err = Ty::new_error(self.tcx, guar); (err, Some(err), err) } @@ -2068,15 +2150,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Type check all the patterns before `slice`. for elt in before { - self.check_pat(elt, element_ty, def_bm, ti); + self.check_pat(elt, element_ty, pat_info); } // Type check the `slice`, if present, against its expected type. if let Some(slice) = slice { - self.check_pat(slice, opt_slice_ty.unwrap(), def_bm, ti); + self.check_pat(slice, opt_slice_ty.unwrap(), pat_info); } // Type check the elements after `slice`, if present. for elt in after { - self.check_pat(elt, element_ty, def_bm, ti); + self.check_pat(elt, element_ty, pat_info); } inferred } diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index fd43b475e..406434e09 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -284,7 +284,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut exprs = vec![expr]; while let hir::ExprKind::Field(ref expr, _) - | hir::ExprKind::Index(ref expr, _) + | hir::ExprKind::Index(ref expr, _, _) | hir::ExprKind::Unary(hir::UnOp::Deref, ref expr) = exprs.last().unwrap().kind { exprs.push(expr); @@ -392,7 +392,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We also could not use `expr_ty_adjusted` of index_expr because reborrowing // during coercions can also cause type of index_expr to differ from `T`, // which can potentially cause regionck failure (#74933). - Some(self.typeck_results.borrow().node_substs(expr.hir_id).type_at(1)) + Some(self.typeck_results.borrow().node_args(expr.hir_id).type_at(1)) } }; let arg_tys = arg_ty.as_slice(); diff --git a/compiler/rustc_hir_typeck/src/rvalue_scopes.rs b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs index 22c9e7961..04d841023 100644 --- a/compiler/rustc_hir_typeck/src/rvalue_scopes.rs +++ b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs @@ -40,7 +40,7 @@ fn record_rvalue_scope_rec( hir::ExprKind::AddrOf(_, _, subexpr) | hir::ExprKind::Unary(hir::UnOp::Deref, subexpr) | hir::ExprKind::Field(subexpr, _) - | hir::ExprKind::Index(subexpr, _) => { + | hir::ExprKind::Index(subexpr, _, _) => { expr = subexpr; } _ => { @@ -74,9 +74,7 @@ pub fn resolve_rvalue_scopes<'a, 'tcx>( 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)) = hir_map.find(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 208c40a39..1a41786d2 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -33,6 +33,7 @@ use super::FnCtxt; use crate::expr_use_visitor as euv; +use rustc_data_structures::unord::{ExtendUnord, UnordSet}; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; @@ -41,14 +42,14 @@ use rustc_infer::infer::UpvarRegion; use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection, ProjectionKind}; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{ - self, ClosureSizeProfileData, Ty, TyCtxt, TypeckResults, UpvarCapture, UpvarSubsts, + self, ClosureSizeProfileData, Ty, TyCtxt, TypeckResults, UpvarArgs, UpvarCapture, }; use rustc_session::lint; use rustc_span::sym; use rustc_span::{BytePos, Pos, Span, Symbol}; use rustc_trait_selection::infer::InferCtxtExt; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_target::abi::FIRST_VARIANT; use std::iter; @@ -108,11 +109,11 @@ impl MigrationWarningReason { fn migration_message(&self) -> String { let base = "changes to closure capture in Rust 2021 will affect"; if !self.auto_traits.is_empty() && self.drop_order { - format!("{} drop order and which traits the closure implements", base) + format!("{base} drop order and which traits the closure implements") } else if self.drop_order { - format!("{} drop order", base) + format!("{base} drop order") } else { - format!("{} which traits the closure implements", base) + format!("{base} which traits the closure implements") } } } @@ -168,9 +169,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { // Extract the type of the closure. let ty = self.node_ty(closure_hir_id); - let (closure_def_id, substs) = match *ty.kind() { - ty::Closure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs)), - ty::Generator(def_id, substs, _) => (def_id, UpvarSubsts::Generator(substs)), + let (closure_def_id, args) = match *ty.kind() { + ty::Closure(def_id, args) => (def_id, UpvarArgs::Closure(args)), + ty::Generator(def_id, args, _) => (def_id, UpvarArgs::Generator(args)), ty::Error(_) => { // #51714: skip analysis when we have already encountered type errors return; @@ -186,8 +187,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let closure_def_id = closure_def_id.expect_local(); - let infer_kind = if let UpvarSubsts::Closure(closure_substs) = substs { - self.closure_kind(closure_substs).is_none().then_some(closure_substs) + let infer_kind = if let UpvarArgs::Closure(closure_args) = args { + self.closure_kind(closure_args).is_none().then_some(closure_args) } else { None }; @@ -256,19 +257,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let before_feature_tys = self.final_upvar_tys(closure_def_id); - if let Some(closure_substs) = infer_kind { + if let Some(closure_args) = infer_kind { // Unify the (as yet unbound) type variable in the closure - // substs with the kind we inferred. - let closure_kind_ty = closure_substs.as_closure().kind_ty(); + // 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); // If we have an origin, store it. - if let Some(origin) = origin { - let origin = if enable_precise_capture(span) { - (origin.0, origin.1) - } else { - (origin.0, Place { projections: vec![], ..origin.1 }) - }; + if let Some(mut origin) = origin { + if !enable_precise_capture(span) { + // Without precise captures, we just capture the base and ignore + // the projections. + origin.1.projections.clear() + } self.typeck_results .borrow_mut() @@ -293,15 +294,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Equate the type variables for the upvars with the actual types. let final_upvar_tys = self.final_upvar_tys(closure_def_id); - debug!( - "analyze_closure: id={:?} substs={:?} final_upvar_tys={:?}", - closure_hir_id, substs, final_upvar_tys - ); + debug!(?closure_hir_id, ?args, ?final_upvar_tys); // Build a tuple (U0..Un) of the final upvar types U0..Un // and unify the upvar tuple type in the closure with it: let final_tupled_upvars_type = Ty::new_tup(self.tcx, &final_upvar_tys); - self.demand_suptype(span, substs.tupled_upvars_ty(), final_tupled_upvars_type); + self.demand_suptype(span, args.tupled_upvars_ty(), final_tupled_upvars_type); let fake_reads = delegate .fake_reads @@ -337,10 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let upvar_ty = captured_place.place.ty(); let capture = captured_place.info.capture_kind; - debug!( - "final_upvar_tys: place={:?} upvar_ty={:?} capture={:?}, mutability={:?}", - captured_place.place, upvar_ty, capture, captured_place.mutability, - ); + debug!(?captured_place.place, ?upvar_ty, ?capture, ?captured_place.mutability); apply_capture_kind_on_capture_ty(self.tcx, upvar_ty, capture, captured_place.region) }) @@ -644,7 +639,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for capture in captures { match capture.info.capture_kind { ty::UpvarCapture::ByRef(_) => { - let PlaceBase::Upvar(upvar_id) = capture.place.base else { bug!("expected upvar") }; + let PlaceBase::Upvar(upvar_id) = capture.place.base else { + bug!("expected upvar") + }; let origin = UpvarRegion(upvar_id, closure_span); let upvar_region = self.next_region_var(origin); capture.region = Some(upvar_region); @@ -676,6 +673,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 => {} @@ -698,10 +696,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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: ({:?}, {:?})", @@ -821,8 +821,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lint.note("for more information, see "); let diagnostic_msg = format!( - "add a dummy let to cause {} to be fully captured", - migrated_variables_concat + "add a dummy let to cause {migrated_variables_concat} to be fully captured" ); let closure_span = self.tcx.hir().span_with_body(closure_hir_id); @@ -908,19 +907,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Combines all the reasons for 2229 migrations fn compute_2229_migrations_reasons( &self, - auto_trait_reasons: FxHashSet<&'static str>, + auto_trait_reasons: UnordSet<&'static str>, drop_order: bool, ) -> MigrationWarningReason { - let mut reasons = MigrationWarningReason::default(); - - reasons.auto_traits.extend(auto_trait_reasons); - reasons.drop_order = drop_order; - - // `auto_trait_reasons` are in hashset order, so sort them to put the - // diagnostics we emit later in a cross-platform-consistent order. - reasons.auto_traits.sort_unstable(); - - reasons + MigrationWarningReason { + auto_traits: auto_trait_reasons.to_sorted_stable_ord(), + drop_order, + } } /// Figures out the list of root variables (and their types) that aren't completely @@ -934,8 +927,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>, var_hir_id: hir::HirId, closure_clause: hir::CaptureBy, - ) -> Option>> { - let auto_traits_def_id = vec![ + ) -> Option>> { + let auto_traits_def_id = [ self.tcx.lang_items().clone_trait(), self.tcx.lang_items().sync_trait(), self.tcx.get_diagnostic_item(sym::Send), @@ -979,7 +972,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { })); } - let mut problematic_captures = FxHashMap::default(); + let mut problematic_captures = FxIndexMap::default(); // Check whether captured fields also implement the trait for capture in root_var_min_capture_list.iter() { let ty = apply_capture_kind_on_capture_ty( @@ -999,7 +992,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { })); } - let mut capture_problems = FxHashSet::default(); + let mut capture_problems = UnordSet::default(); // Checks if for any of the auto traits, one or more trait is implemented // by the root variable but not by the capture @@ -1045,7 +1038,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>, closure_clause: hir::CaptureBy, var_hir_id: hir::HirId, - ) -> Option> { + ) -> Option> { let ty = self.resolve_vars_if_possible(self.node_ty(var_hir_id)); if !ty.has_significant_drop(self.tcx, self.tcx.param_env(closure_def_id)) { @@ -1064,14 +1057,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // ``` debug!("no path starting from it is used"); - match closure_clause { // Only migrate if closure is a move closure hir::CaptureBy::Value => { - let mut diagnostics_info = FxHashSet::default(); - let upvars = self.tcx.upvars_mentioned(closure_def_id).expect("must be an upvar"); + let mut diagnostics_info = FxIndexSet::default(); + let upvars = + self.tcx.upvars_mentioned(closure_def_id).expect("must be an upvar"); let upvar = upvars[&var_hir_id]; - diagnostics_info.insert(UpvarMigrationInfo::CapturingNothing { use_span: upvar.span }); + diagnostics_info + .insert(UpvarMigrationInfo::CapturingNothing { use_span: upvar.span }); return Some(diagnostics_info); } hir::CaptureBy::Ref => {} @@ -1082,7 +1076,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!(?root_var_min_capture_list); let mut projections_list = Vec::new(); - let mut diagnostics_info = FxHashSet::default(); + let mut diagnostics_info = FxIndexSet::default(); for captured_place in root_var_min_capture_list.iter() { match captured_place.info.capture_kind { @@ -1152,7 +1146,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let mut need_migrations = Vec::new(); - let mut auto_trait_migration_reasons = FxHashSet::default(); + let mut auto_trait_migration_reasons = UnordSet::default(); let mut drop_migration_needed = false; // Perform auto-trait analysis @@ -1164,7 +1158,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { diagnostics_info } else { - FxHashMap::default() + FxIndexMap::default() }; let drop_reorder_diagnostic = if let Some(diagnostics_info) = self @@ -1178,7 +1172,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { drop_migration_needed = true; diagnostics_info } else { - FxHashSet::default() + FxIndexSet::default() }; // Combine all the captures responsible for needing migrations into one HashSet @@ -1195,7 +1189,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(reasons) = auto_trait_diagnostic.get(&captures_info) { reasons.clone() } else { - FxHashSet::default() + UnordSet::default() }; // Check if migration is needed because of drop reorder as a result of that capture @@ -1203,7 +1197,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Combine all the reasons of why the root variable should be captured as a result of // auto trait implementation issues - auto_trait_migration_reasons.extend(capture_trait_reasons.iter().copied()); + auto_trait_migration_reasons.extend_unord(capture_trait_reasons.items().copied()); diagnostics_info.push(MigrationLintNote { captures_info, @@ -1385,7 +1379,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Ref(..) => unreachable!(), ty::RawPtr(..) => unreachable!(), - ty::Adt(def, substs) => { + ty::Adt(def, args) => { // Multi-variant enums are captured in entirety, // which would've been handled in the case of single empty slice in `captured_by_move_projs`. assert_eq!(def.variants().len(), 1); @@ -1412,7 +1406,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) .collect(); - let after_field_ty = field.ty(self.tcx, substs); + let after_field_ty = field.ty(self.tcx, args); self.has_significant_drop_outside_of_captures( closure_def_id, closure_span, @@ -1893,6 +1887,7 @@ fn restrict_capture_precision( return (place, curr_mode); } ProjectionKind::Deref => {} + ProjectionKind::OpaqueCast => {} ProjectionKind::Field(..) => {} // ignore } } @@ -1945,10 +1940,11 @@ fn construct_place_string<'tcx>(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String let mut projections_str = String::new(); for (i, item) in place.projections.iter().enumerate() { let proj = match item.kind { - ProjectionKind::Field(a, b) => format!("({:?}, {:?})", a, b), + ProjectionKind::Field(a, b) => format!("({a:?}, {b:?})"), ProjectionKind::Deref => String::from("Deref"), ProjectionKind::Index => String::from("Index"), ProjectionKind::Subslice => String::from("Subslice"), + ProjectionKind::OpaqueCast => String::from("OpaqueCast"), }; if i != 0 { projections_str.push(','); @@ -1968,7 +1964,7 @@ fn construct_capture_kind_reason_string<'tcx>( let capture_kind_str = match capture_info.capture_kind { ty::UpvarCapture::ByValue => "ByValue".into(), - ty::UpvarCapture::ByRef(kind) => format!("{:?}", kind), + ty::UpvarCapture::ByRef(kind) => format!("{kind:?}"), }; format!("{place_str} captured as {capture_kind_str} here") @@ -1989,7 +1985,7 @@ fn construct_capture_info_string<'tcx>( let capture_kind_str = match capture_info.capture_kind { ty::UpvarCapture::ByValue => "ByValue".into(), - ty::UpvarCapture::ByRef(kind) => format!("{:?}", kind), + ty::UpvarCapture::ByRef(kind) => format!("{kind:?}"), }; format!("{place_str} -> {capture_kind_str}") } @@ -2003,7 +1999,7 @@ fn should_do_rust_2021_incompatible_closure_captures_analysis( tcx: TyCtxt<'_>, closure_id: hir::HirId, ) -> bool { - if tcx.sess.rust_2021() { + if tcx.sess.at_least_rust_2021() { return false; } @@ -2249,5 +2245,5 @@ fn truncate_capture_for_optimization( fn enable_precise_capture(span: Span) -> bool { // We use span here to ensure that if the closure was generated by a macro with a different // edition. - span.rust_2021() + span.at_least_rust_2021() } diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 106457536..603681bbc 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -3,23 +3,19 @@ // substitutions. use crate::FnCtxt; -use hir::def_id::LocalDefId; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::unord::ExtendUnord; 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::hir::place::Place as HirPlace; -use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; -use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt}; -use rustc_middle::ty::{self, ClosureSizeProfileData, Ty, TyCtxt}; +use rustc_middle::ty::visit::TypeVisitableExt; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; use std::mem; -use std::ops::ControlFlow; /////////////////////////////////////////////////////////////////////////// // Entry point @@ -42,9 +38,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This attribute causes us to dump some writeback information // in the form of errors, which is used for unit tests. - let rustc_dump_user_substs = self.tcx.has_attr(item_def_id, sym::rustc_dump_user_substs); + let rustc_dump_user_args = self.tcx.has_attr(item_def_id, sym::rustc_dump_user_args); - let mut wbcx = WritebackCx::new(self, body, rustc_dump_user_substs); + let mut wbcx = WritebackCx::new(self, body, rustc_dump_user_args); for param in body.params { wbcx.visit_node_id(param.pat.span, param.hir_id); } @@ -102,14 +98,14 @@ struct WritebackCx<'cx, 'tcx> { body: &'tcx hir::Body<'tcx>, - rustc_dump_user_substs: bool, + rustc_dump_user_args: bool, } impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fn new( fcx: &'cx FnCtxt<'cx, 'tcx>, body: &'tcx hir::Body<'tcx>, - rustc_dump_user_substs: bool, + rustc_dump_user_args: bool, ) -> WritebackCx<'cx, 'tcx> { let owner = body.id().hir_id.owner; @@ -117,7 +113,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fcx, typeck_results: ty::TypeckResults::new(owner), body, - rustc_dump_user_substs, + rustc_dump_user_args, }; // HACK: We specifically don't want the (opaque) error from tainting our @@ -154,7 +150,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { if inner_ty.is_scalar() { self.typeck_results.type_dependent_defs_mut().remove(e.hir_id); - self.typeck_results.node_substs_mut().remove(e.hir_id); + self.typeck_results.node_args_mut().remove(e.hir_id); } } hir::ExprKind::Binary(ref op, lhs, rhs) | hir::ExprKind::AssignOp(ref op, lhs, rhs) => { @@ -163,7 +159,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { if lhs_ty.is_scalar() && rhs_ty.is_scalar() { self.typeck_results.type_dependent_defs_mut().remove(e.hir_id); - self.typeck_results.node_substs_mut().remove(e.hir_id); + self.typeck_results.node_args_mut().remove(e.hir_id); match e.kind { hir::ExprKind::Binary(..) => { @@ -214,14 +210,14 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // to use builtin indexing because the index type is known to be // usize-ish fn fix_index_builtin_expr(&mut self, e: &hir::Expr<'_>) { - if let hir::ExprKind::Index(ref base, ref index) = e.kind { + if let hir::ExprKind::Index(ref base, ref index, _) = e.kind { // All valid indexing looks like this; might encounter non-valid indexes at this point. let base_ty = self.typeck_results.expr_ty_adjusted_opt(base); if base_ty.is_none() { // 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.delay_span_bug(e.span, format!("bad base: `{base:?}`")); } if let Some(base_ty) = base_ty && let ty::Ref(_, base_ty_inner, _) = *base_ty.kind() @@ -235,13 +231,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { Ty::new_error_with_message( self.fcx.tcx, e.span, - format!("bad index {:?} for base: `{:?}`", index, base), + format!("bad index {index:?} for base: `{base:?}`"), ) }); if self.is_builtin_index(e, base_ty_inner, index_ty) { // Remove the method call record self.typeck_results.type_dependent_defs_mut().remove(e.hir_id); - self.typeck_results.node_substs_mut().remove(e.hir_id); + self.typeck_results.node_args_mut().remove(e.hir_id); if let Some(a) = self.typeck_results.adjustments_mut().get_mut(base.hir_id) { // Discard the need for a mutable borrow @@ -376,66 +372,75 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fn eval_closure_size(&mut self) { - let mut res: FxHashMap> = Default::default(); - for (&closure_def_id, data) in self.fcx.typeck_results.borrow().closure_size_eval.iter() { - let closure_hir_id = self.tcx().hir().local_def_id_to_hir_id(closure_def_id); - - let data = self.resolve(*data, &closure_hir_id); - - res.insert(closure_def_id, data); - } - - self.typeck_results.closure_size_eval = res; + self.tcx().with_stable_hashing_context(|ref hcx| { + let fcx_typeck_results = self.fcx.typeck_results.borrow(); + + self.typeck_results.closure_size_eval = fcx_typeck_results + .closure_size_eval + .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 data = self.resolve(*data, &closure_hir_id); + (closure_def_id, data) + }) + .collect(); + }) } - fn visit_min_capture_map(&mut self) { - let mut min_captures_wb = ty::MinCaptureInformationMap::with_capacity_and_hasher( - self.fcx.typeck_results.borrow().closure_min_captures.len(), - Default::default(), - ); - for (&closure_def_id, root_min_captures) in - self.fcx.typeck_results.borrow().closure_min_captures.iter() - { - let mut root_var_map_wb = ty::RootVariableMinCaptureList::with_capacity_and_hasher( - root_min_captures.len(), - Default::default(), - ); - for (var_hir_id, min_list) in root_min_captures.iter() { - let min_list_wb = min_list - .iter() - .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.resolve(captured_place.clone(), &locatable) - }) - .collect(); - root_var_map_wb.insert(*var_hir_id, min_list_wb); - } - min_captures_wb.insert(closure_def_id, root_var_map_wb); - } - self.typeck_results.closure_min_captures = min_captures_wb; + fn visit_min_capture_map(&mut self) { + self.tcx().with_stable_hashing_context(|ref hcx| { + let fcx_typeck_results = self.fcx.typeck_results.borrow(); + + self.typeck_results.closure_min_captures = fcx_typeck_results + .closure_min_captures + .to_sorted(hcx, false) + .into_iter() + .map(|(&closure_def_id, root_min_captures)| { + let root_var_map_wb = root_min_captures + .iter() + .map(|(var_hir_id, min_list)| { + let min_list_wb = min_list + .iter() + .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.resolve(captured_place.clone(), &locatable) + }) + .collect(); + (*var_hir_id, min_list_wb) + }) + .collect(); + (closure_def_id, root_var_map_wb) + }) + .collect(); + }) } fn visit_fake_reads_map(&mut self) { - let mut resolved_closure_fake_reads: FxHashMap< - LocalDefId, - Vec<(HirPlace<'tcx>, FakeReadCause, hir::HirId)>, - > = Default::default(); - for (&closure_def_id, fake_reads) in - self.fcx.typeck_results.borrow().closure_fake_reads.iter() - { - let mut resolved_fake_reads = Vec::<(HirPlace<'tcx>, FakeReadCause, hir::HirId)>::new(); - for (place, cause, hir_id) in fake_reads.iter() { - let locatable = self.tcx().hir().local_def_id_to_hir_id(closure_def_id); - - let resolved_fake_read = self.resolve(place.clone(), &locatable); - resolved_fake_reads.push((resolved_fake_read, *cause, *hir_id)); - } - resolved_closure_fake_reads.insert(closure_def_id, resolved_fake_reads); - } - self.typeck_results.closure_fake_reads = resolved_closure_fake_reads; + self.tcx().with_stable_hashing_context(move |ref hcx| { + let fcx_typeck_results = self.fcx.typeck_results.borrow(); + + self.typeck_results.closure_fake_reads = fcx_typeck_results + .closure_fake_reads + .to_sorted(hcx, true) + .into_iter() + .map(|(&closure_def_id, fake_reads)| { + 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 resolved_fake_read = self.resolve(place.clone(), &locatable); + (resolved_fake_read, *cause, *hir_id) + }) + .collect(); + + (closure_def_id, resolved_fake_reads) + }) + .collect(); + }); } fn visit_closures(&mut self) { @@ -470,7 +475,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); let common_hir_owner = fcx_typeck_results.hir_owner; - if self.rustc_dump_user_substs { + if self.rustc_dump_user_args { let sorted_user_provided_types = fcx_typeck_results.user_provided_types().items_in_stable_order(); @@ -478,15 +483,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { for (local_id, c_ty) in sorted_user_provided_types { let hir_id = hir::HirId { owner: common_hir_owner, local_id }; - if let ty::UserType::TypeOf(_, user_substs) = c_ty.value { + if let ty::UserType::TypeOf(_, user_args) = c_ty.value { // This is a unit-testing mechanism. let span = self.tcx().hir().span(hir_id); // We need to buffer the errors in order to guarantee a consistent // order when emitting them. - let err = self - .tcx() - .sess - .struct_span_err(span, format!("user substs: {:?}", user_substs)); + let err = + self.tcx().sess.struct_span_err(span, format!("user args: {user_args:?}")); err.buffer(&mut errors_buffer); } } @@ -520,7 +523,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { let fcx_typeck_results = self.fcx.typeck_results.borrow(); assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); - self.typeck_results.user_provided_sigs.extend( + self.typeck_results.user_provided_sigs.extend_unord( fcx_typeck_results.user_provided_sigs.items().map(|(&def_id, c_sig)| { if cfg!(debug_assertions) && c_sig.has_infer() { span_bug!( @@ -540,10 +543,15 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); self.typeck_results.generator_interior_types = fcx_typeck_results.generator_interior_types.clone(); - for (&expr_def_id, predicates) in fcx_typeck_results.generator_interior_predicates.iter() { - let predicates = self.resolve(predicates.clone(), &self.fcx.tcx.def_span(expr_def_id)); - self.typeck_results.generator_interior_predicates.insert(expr_def_id, predicates); - } + self.tcx().with_stable_hashing_context(move |ref hcx| { + for (&expr_def_id, predicates) in + fcx_typeck_results.generator_interior_predicates.to_sorted(hcx, false).into_iter() + { + let predicates = + self.resolve(predicates.clone(), &self.fcx.tcx.def_span(expr_def_id)); + self.typeck_results.generator_interior_predicates.insert(expr_def_id, predicates); + } + }) } #[instrument(skip(self), level = "debug")] @@ -553,23 +561,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { let hidden_type = self.resolve(decl.hidden_type, &decl.hidden_type.span); let opaque_type_key = self.resolve(opaque_type_key, &decl.hidden_type.span); - struct RecursionChecker { - def_id: LocalDefId, - } - impl<'tcx> ty::TypeVisitor> for RecursionChecker { - type BreakTy = (); - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { - if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *t.kind() { - if def_id == self.def_id.to_def_id() { - return ControlFlow::Break(()); - } - } - t.super_visit_with(self) - } - } - if hidden_type - .visit_with(&mut RecursionChecker { def_id: opaque_type_key.def_id }) - .is_break() + if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind() + && alias_ty.def_id == opaque_type_key.def_id.to_def_id() + && alias_ty.args == opaque_type_key.args { continue; } @@ -619,11 +613,11 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { debug!(?n_ty); // Resolve any substitutions - if let Some(substs) = self.fcx.typeck_results.borrow().node_substs_opt(hir_id) { - let substs = self.resolve(substs, &span); - debug!("write_substs_to_tcx({:?}, {:?})", hir_id, substs); - assert!(!substs.has_infer() && !substs.has_placeholders()); - self.typeck_results.node_substs_mut().insert(hir_id, substs); + if let Some(args) = self.fcx.typeck_results.borrow().node_args_opt(hir_id) { + let args = self.resolve(args, &span); + debug!("write_args_to_tcx({:?}, {:?})", hir_id, args); + assert!(!args.has_infer() && !args.has_placeholders()); + self.typeck_results.node_args_mut().insert(hir_id, args); } } -- cgit v1.2.3