From 9835e2ae736235810b4ea1c162ca5e65c547e770 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 18 May 2024 04:49:50 +0200 Subject: Merging upstream version 1.71.1+dfsg1. Signed-off-by: Daniel Baumann --- compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs | 105 ++++++++++++++++----- .../src/fn_ctxt/adjust_fulfillment_errors.rs | 43 +++++---- .../rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs | 2 +- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 86 +++++++++-------- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 29 ++---- .../rustc_hir_typeck/src/fn_ctxt/suggestions.rs | 74 +++++++-------- 6 files changed, 195 insertions(+), 144 deletions(-) (limited to 'compiler/rustc_hir_typeck/src/fn_ctxt') diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index f736f7a96..557950338 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1,10 +1,11 @@ use crate::callee::{self, DeferredCallResolution}; +use crate::errors::CtorIsPrivate; use crate::method::{self, MethodCallee, SelfSource}; use crate::rvalue_scopes; use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, RawTy}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan}; +use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan, StashKey}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; @@ -35,7 +36,9 @@ use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; use rustc_target::abi::FieldIdx; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; -use rustc_trait_selection::traits::{self, NormalizeExt, ObligationCauseCode, ObligationCtxt}; +use rustc_trait_selection::traits::{ + self, NormalizeExt, ObligationCauseCode, ObligationCtxt, StructurallyNormalizeExt, +}; use std::collections::hash_map::Entry; use std::slice; @@ -63,9 +66,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lint::builtin::UNREACHABLE_CODE, id, span, - &msg, + msg.clone(), |lint| { - lint.span_label(span, &msg).span_label( + lint.span_label(span, msg).span_label( orig_span, custom_note .unwrap_or("any code following this expression is unreachable"), @@ -275,7 +278,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => { self.tcx.sess.delay_span_bug( expr.span, - &format!( + format!( "while adjusting {:?}, can't compose {:?} and {:?}", expr, entry.get(), @@ -420,9 +423,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ast_c: &hir::AnonConst, param_def_id: DefId, ) -> ty::Const<'tcx> { - let const_def = - ty::WithOptConstParam { did: ast_c.def_id, const_param_did: Some(param_def_id) }; - let c = ty::Const::from_opt_const_arg_anon_const(self.tcx, const_def); + let did = ast_c.def_id; + self.tcx.feed_anon_const_type(did, self.tcx.type_of(param_def_id)); + let c = ty::Const::from_anon_const(self.tcx, did); self.register_wf_obligation( c.into(), self.tcx.hir().span(ast_c.hir_id), @@ -827,7 +830,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } QPath::TypeRelative(ref qself, ref segment) => { // Don't use `self.to_ty`, since this will register a WF obligation. - // If we're trying to call a non-existent method on a trait + // If we're trying to call a nonexistent method on a trait // (e.g. `MyTrait::missing_method`), then resolution will // give us a `QPath::TypeRelative` with a trait object as // `qself`. In that case, we want to avoid registering a WF obligation @@ -853,23 +856,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let item_name = item_segment.ident; let result = self .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) { + diag.emit(); + } + Ok(r) + }) .or_else(|error| { + let guar = self + .tcx + .sess + .delay_span_bug(span, "method resolution should've emitted an error"); let result = match error { method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)), - _ => Err(ErrorGuaranteed::unchecked_claim_error_was_emitted()), + _ => Err(guar), }; + let trait_missing_method = + matches!(error, method::MethodError::NoMatch(_)) && ty.normalized.is_trait(); // If we have a path like `MyTrait::missing_method`, then don't register // a WF obligation for `dyn MyTrait` when method lookup fails. Otherwise, // register a WF obligation so that we can detect any additional // errors in the self type. - if !(matches!(error, method::MethodError::NoMatch(_)) && ty.normalized.is_trait()) { + if !trait_missing_method { self.register_wf_obligation( ty.raw.into(), qself.span, traits::WellFormed(None), ); } + + // 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 trait_missing_method { + // cancel the diag for bare traits when meeting `MyTrait::missing_method` + diag.cancel(); + } else { + diag.emit(); + } + } + if item_name.name != kw::Empty { if let Some(mut e) = self.report_method_error( span, @@ -879,10 +906,12 @@ 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 ) { e.emit(); } } + result }); @@ -989,8 +1018,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .typeck_results .borrow() .expr_ty_adjusted_opt(rcvr) - .and_then(|ty| expected.map(|expected_ty| expected_ty.peel_refs() == ty.peel_refs())) - .unwrap_or(false); + .zip(expected) + .is_some_and(|(ty, expected_ty)| expected_ty.peel_refs() == ty.peel_refs()); let prev_call_mutates_and_returns_unit = || { self.typeck_results @@ -998,14 +1027,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .type_dependent_def_id(expr.hir_id) .map(|def_id| self.tcx.fn_sig(def_id).skip_binder().skip_binder()) .and_then(|sig| sig.inputs_and_output.split_last()) - .map(|(output, inputs)| { + .is_some_and(|(output, inputs)| { output.is_unit() && inputs .get(0) .and_then(|self_ty| self_ty.ref_mutability()) - .map_or(false, rustc_ast::Mutability::is_mut) + .is_some_and(rustc_ast::Mutability::is_mut) }) - .unwrap_or(false) }; if !(rcvr_has_the_expected_type || prev_call_mutates_and_returns_unit()) { @@ -1034,15 +1062,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rcvr.span, "you probably want to use this value after calling the method...", ); - err.span_note(sp, &modifies_rcvr_note); - err.note(&format!("...instead of the `()` output of method `{}`", path_segment.ident)); + err.span_note(sp, modifies_rcvr_note); + err.note(format!("...instead of the `()` output of method `{}`", path_segment.ident)); } 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.", ); } else { - err.span_note(sp, &modifies_rcvr_note); + err.span_note(sp, modifies_rcvr_note); } } @@ -1172,16 +1200,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - let has_self = path_segs - .last() - .map(|PathSeg(def_id, _)| tcx.generics_of(*def_id).has_self) - .unwrap_or(false); + 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()); 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(); + // Check the visibility of the ctor. + let vis = tcx.visibility(ctor_def_id); + if !vis.is_accessible_from(tcx.parent_module(hir_id).to_def_id(), tcx) { + tcx.sess + .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; @@ -1374,7 +1406,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Err(_) => { self.tcx.sess.delay_span_bug( span, - &format!( + format!( "instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?", self_ty, impl_ty, @@ -1434,10 +1466,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Resolves `typ` by a single level if `typ` is a type variable. + /// + /// When the new solver is enabled, this will also attempt to normalize + /// the type if it's a projection (note that it will not deeply normalize + /// projections within the type, just the outermost layer of the type). + /// /// If no resolution is possible, then an error is reported. /// Numeric inference variables may be left unresolved. pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - let ty = self.resolve_vars_with_obligations(ty); + let mut ty = self.resolve_vars_with_obligations(ty); + + if self.tcx.trait_solver_next() + && let ty::Alias(ty::Projection, _) = ty.kind() + { + match self + .at(&self.misc(sp), self.param_env) + .structurally_normalize(ty, &mut **self.fulfillment_cx.borrow_mut()) + { + Ok(normalized_ty) => { + ty = normalized_ty; + }, + Err(errors) => { + let guar = self.err_ctxt().report_fulfillment_errors(&errors); + return self.tcx.ty_error(guar); + } + } + } + if !ty.is_ty_var() { ty } else { 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 f879ccbb3..3efdab534 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 @@ -164,24 +164,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] + .into_iter() + .flatten() { - if let Some(param) = param { - let refined_expr = self.point_at_field_if_possible( - def_id, - param, - variant_def_id, - fields, - ); - - match refined_expr { - None => {} - Some((refined_expr, _)) => { - error.obligation.cause.span = refined_expr - .span - .find_ancestor_in_same_ctxt(error.obligation.cause.span) - .unwrap_or(refined_expr.span); - return true; - } + let refined_expr = + self.point_at_field_if_possible(def_id, param, variant_def_id, fields); + + match refined_expr { + None => {} + Some((refined_expr, _)) => { + error.obligation.cause.span = refined_expr + .span + .find_ancestor_in_same_ctxt(error.obligation.cause.span) + .unwrap_or(refined_expr.span); + return true; } } } @@ -282,9 +278,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, ) -> bool { if let traits::FulfillmentErrorCode::CodeSelectionError( - traits::SelectionError::OutputTypeParameterMismatch(_, expected, _), + traits::SelectionError::OutputTypeParameterMismatch(box traits::SelectionOutputTypeParameterMismatch{ + expected_trait_ref, .. + }), ) = error.code - && let ty::Closure(def_id, _) | ty::Generator(def_id, ..) = expected.skip_binder().self_ty().kind() + && let ty::Closure(def_id, _) | ty::Generator(def_id, ..) = expected_trait_ref.skip_binder().self_ty().kind() && span.overlaps(self.tcx.def_span(*def_id)) { true @@ -334,7 +332,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// expression mentioned. /// /// `blame_specific_arg_if_possible` will find the most-specific expression anywhere inside - /// the provided function call expression, and mark it as responsible for the fullfillment + /// the provided function call expression, and mark it as responsible for the fulfillment /// error. fn blame_specific_arg_if_possible( &self, @@ -485,7 +483,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // For the purposes of this function, we hope that it is a `struct` type, and that our current `expr` is a literal of // that struct type. let impl_trait_self_ref = if self.tcx.is_trait_alias(obligation.impl_or_alias_def_id) { - self.tcx.mk_trait_ref( + ty::TraitRef::new( + self.tcx, obligation.impl_or_alias_def_id, ty::InternalSubsts::identity_for_item(self.tcx, obligation.impl_or_alias_def_id), ) @@ -846,7 +845,7 @@ fn find_param_in_ty<'tcx>( return true; } if let ty::GenericArgKind::Type(ty) = arg.unpack() - && let ty::Alias(ty::Projection, ..) = ty.kind() + && let ty::Alias(ty::Projection | ty::Inherent, ..) = ty.kind() { // This logic may seem a bit strange, but typically when // we have a projection type in a function signature, the diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs index 6f26afcaf..d45e3d395 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs @@ -1,6 +1,6 @@ use std::cmp; -use rustc_index::vec::IndexVec; +use rustc_index::IndexVec; use rustc_middle::ty::error::TypeError; rustc_index::newtype_index! { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index ea1b52daa..eba5c829e 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -2,8 +2,8 @@ use crate::coercion::CoerceMany; use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx}; use crate::gather_locals::Declaration; use crate::method::MethodCallee; -use crate::Expectation::*; use crate::TupleArgumentsFlag::*; +use crate::{errors, Expectation::*}; use crate::{ struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, Needs, RawTy, TupleArgumentsFlag, @@ -21,7 +21,7 @@ use rustc_hir_analysis::astconv::AstConv; use rustc_hir_analysis::check::intrinsicck::InlineAsmCtxt; use rustc_hir_analysis::check::potentially_plural_count; use rustc_hir_analysis::structured_errors::StructuredDiagnostic; -use rustc_index::vec::IndexVec; +use rustc_index::IndexVec; use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::TypeTrace; @@ -283,19 +283,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if idx == 1 && !self.tcx.is_const_fn_raw(*def_id) { self.tcx .sess - .struct_span_err(provided_arg.span, "this argument must be a `const fn`") - .help("consult the documentation on `const_eval_select` for more information") - .emit(); + .emit_err(errors::ConstSelectMustBeConst { span: provided_arg.span }); } } else { - self.tcx - .sess - .struct_span_err(provided_arg.span, "this argument must be a function item") - .note(format!("expected a function item, found {checked_ty}")) - .help( - "consult the documentation on `const_eval_select` for more information", - ) - .emit(); + self.tcx.sess.emit_err(errors::ConstSelectMustBeFn { + span: provided_arg.span, + ty: checked_ty, + }); } } @@ -368,7 +362,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { continue; } - let is_closure = matches!(arg.kind, ExprKind::Closure { .. }); + // For this check, we do *not* want to treat async generator closures (async blocks) + // as proper closures. Doing so would regress type inference when feeding + // the return value of an argument-position async block to an argument-position + // closure wrapped in a block. + // See . + let is_closure = if let ExprKind::Closure(closure) = arg.kind { + !tcx.generator_is_async(closure.def_id.to_def_id()) + } else { + false + }; if is_closure != check_closures { continue; } @@ -691,7 +694,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { err = tcx.sess.struct_span_err_with_code( full_call_span, - &format!( + format!( "{call_name} takes {}{} but {} {} supplied", if c_variadic { "at least " } else { "" }, potentially_plural_count( @@ -744,17 +747,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if cfg!(debug_assertions) { span_bug!(error_span, "expected errors from argument matrix"); } else { - tcx.sess - .struct_span_err( - error_span, - "argument type mismatch was detected, \ - but rustc had trouble determining where", - ) - .note( - "we would appreciate a bug report: \ - https://github.com/rust-lang/rust/issues/new", - ) - .emit(); + tcx.sess.emit_err(errors::ArgMismatchIndeterminate { span: error_span }); } return; } @@ -844,7 +837,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { tcx.sess.struct_span_err_with_code( full_call_span, - &format!( + format!( "this {} takes {}{} but {} {} supplied", call_name, if c_variadic { "at least " } else { "" }, @@ -892,7 +885,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut errors = errors.into_iter().peekable(); let mut only_extras_so_far = errors .peek() - .map_or(false, |first| matches!(first, Error::Extra(arg_idx) if arg_idx.index() == 0)); + .is_some_and(|first| matches!(first, Error::Extra(arg_idx) if arg_idx.index() == 0)); let mut suggestions = vec![]; while let Some(error) = errors.next() { only_extras_so_far &= matches!(error, Error::Extra(_)); @@ -1219,7 +1212,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } SuggestionText::Remove(plural) => { err.multipart_suggestion( - &format!("remove the extra argument{}", if plural { "s" } else { "" }), + format!("remove the extra argument{}", if plural { "s" } else { "" }), suggestions, Applicability::HasPlaceholders, ); @@ -1269,7 +1262,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { suggestion += ")"; err.span_suggestion_verbose( suggestion_span, - &suggestion_text, + suggestion_text, suggestion, Applicability::HasPlaceholders, ); @@ -1316,6 +1309,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { opt_ty.unwrap_or_else(|| self.next_float_var()) } ast::LitKind::Bool(_) => tcx.types.bool, + ast::LitKind::CStr(_, _) => tcx.mk_imm_ref( + tcx.lifetimes.re_static, + tcx.type_of(tcx.require_lang_item(hir::LangItem::CStr, Some(lit.span))) + .skip_binder(), + ), ast::LitKind::Err => tcx.ty_error_misc(), } } @@ -1530,7 +1528,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // case we can ignore the tail expression (e.g., `'a: { // break 'a 22; }` would not force the type of the block // to be `()`). - let tail_expr = blk.expr.as_ref(); let coerce_to_ty = expected.coercion_target_type(self, blk.span); let coerce = if blk.targeted_by_break { CoerceMany::new(coerce_to_ty) @@ -1548,13 +1545,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // check the tail expression **without** holding the // `enclosing_breakables` lock below. - let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected)); + let tail_expr_ty = + blk.expr.map(|expr| (expr, self.check_expr_with_expectation(expr, expected))); let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); let ctxt = enclosing_breakables.find_breakable(blk.hir_id); let coerce = ctxt.coerce.as_mut().unwrap(); - if let Some(tail_expr_ty) = tail_expr_ty { - let tail_expr = tail_expr.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 ty_for_diagnostic = coerce.merged_ty(); @@ -1607,6 +1604,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self.misc(sp), &mut |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( + err, + blk.span, + blk.hir_id, + expected_ty, + self.tcx.mk_unit(), + ); + } if !self.consider_removing_semicolon(blk, expected_ty, err) { self.err_ctxt().consider_returning_binding( blk, @@ -1619,7 +1625,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // silence this redundant error, as we already emit E0070. // Our block must be a `assign desugar local; assignment` - if let Some(hir::Node::Block(hir::Block { + if let hir::Block { stmts: [ hir::Stmt { @@ -1641,7 +1647,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, ], .. - })) = self.tcx.hir().find(blk.hir_id) + } = blk { self.comes_from_while_condition(blk.hir_id, |_| { err.downgrade_to_delayed_bug(); @@ -1911,7 +1917,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => { // Look for a user-provided impl of a `Fn` trait, and point to it. let new_def_id = self.probe(|_| { - let trait_ref = self.tcx.mk_trait_ref( + let trait_ref = ty::TraitRef::new(self.tcx, call_kind.to_def_id(self.tcx), [ callee_ty, @@ -1963,7 +1969,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { spans.push_span_label(param.span, ""); } - err.span_note(spans, &format!("{} defined here", self.tcx.def_descr(def_id))); + err.span_note(spans, format!("{} defined here", self.tcx.def_descr(def_id))); } else if let Some(hir::Node::Expr(e)) = self.tcx.hir().get_if_local(def_id) && let hir::ExprKind::Closure(hir::Closure { body, .. }) = &e.kind { @@ -1974,11 +1980,11 @@ 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!("{} defined here", kind)); } else { err.span_note( self.tcx.def_span(def_id), - &format!("{} defined here", self.tcx.def_descr(def_id)), + format!("{} defined here", self.tcx.def_descr(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 c6fd0b610..67f45f9aa 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -17,7 +17,6 @@ use rustc_infer::infer; use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt}; use rustc_session::Session; use rustc_span::symbol::Ident; @@ -169,7 +168,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ocx.normalize(&ObligationCause::dummy(), self.param_env, fn_sig); if ocx.select_all_or_error().is_empty() { let normalized_fn_sig = self.resolve_vars_if_possible(normalized_fn_sig); - if !normalized_fn_sig.needs_infer() { + if !normalized_fn_sig.has_infer() { return normalized_fn_sig; } } @@ -250,16 +249,12 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { } fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { - if let Some(param) = param { - if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() { - return ty; - } - unreachable!() - } else { - self.next_ty_var(TypeVariableOrigin { + match param { + Some(param) => self.var_for_def(span, param).as_type().unwrap(), + None => self.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span, - }) + }), } } @@ -269,16 +264,12 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { param: Option<&ty::GenericParamDef>, span: Span, ) -> Const<'tcx> { - if let Some(param) = param { - if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() { - return ct; - } - unreachable!() - } else { - self.next_const_var( + match param { + Some(param) => self.var_for_def(span, param).as_const().unwrap(), + None => self.next_const_var( ty, ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span }, - ) + ), } } @@ -309,7 +300,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { match ty.kind() { ty::Adt(adt_def, _) => Some(*adt_def), // FIXME(#104767): Should we handle bound regions here? - ty::Alias(ty::Projection, _) if !ty.has_escaping_bound_vars() => { + ty::Alias(ty::Projection | ty::Inherent, _) 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 5fda4e191..c4add4dbd 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1,6 +1,6 @@ use super::FnCtxt; -use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel}; +use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel, SuggestBoxing}; use crate::fluent_generated as fluent; use crate::method::probe::{IsSuggestion, Mode, ProbeScope}; use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX}; @@ -9,7 +9,8 @@ use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; use rustc_hir::lang_items::LangItem; use rustc_hir::{ - Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate, + AsyncGeneratorKind, Expr, ExprKind, GeneratorKind, GenericBound, HirId, Node, Path, QPath, + Stmt, StmtKind, TyKind, WherePredicate, }; use rustc_hir_analysis::astconv::AstConv; use rustc_infer::traits::{self, StatementAsExpression}; @@ -274,13 +275,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, ) -> bool { let expr = expr.peel_blocks(); - if let Some((sp, msg, suggestion, applicability, verbose, annotation)) = - self.check_ref(expr, found, expected) + if let Some((suggestion, msg, applicability, verbose, annotation)) = + self.suggest_deref_or_ref(expr, found, expected) { if verbose { - err.span_suggestion_verbose(sp, &msg, suggestion, applicability); + err.multipart_suggestion_verbose(msg, suggestion, applicability); } else { - err.span_suggestion(sp, &msg, suggestion, applicability); + err.multipart_suggestion(msg, suggestion, applicability); } if annotation { let suggest_annotation = match expr.peel_drop_temps().kind { @@ -342,7 +343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(sp, format!("{descr} `{name}` defined here")); } return true; - } else if self.check_for_cast(err, expr, found, expected, expected_ty_expr) { + } else if self.suggest_cast(err, expr, found, expected, expected_ty_expr) { return true; } else { let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id); @@ -438,33 +439,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn suggest_boxing_when_appropriate( &self, err: &mut Diagnostic, - expr: &hir::Expr<'_>, + span: Span, + hir_id: HirId, expected: Ty<'tcx>, found: Ty<'tcx>, ) -> bool { - if self.tcx.hir().is_inside_const_context(expr.hir_id) { - // Do not suggest `Box::new` in const context. - return false; - } - if !expected.is_box() || found.is_box() { + // Do not suggest `Box::new` in const context. + if self.tcx.hir().is_inside_const_context(hir_id) || !expected.is_box() || found.is_box() { return false; } - let boxed_found = self.tcx.mk_box(found); - if self.can_coerce(boxed_found, expected) { - err.multipart_suggestion( - "store this in the heap by calling `Box::new`", - vec![ - (expr.span.shrink_to_lo(), "Box::new(".to_string()), - (expr.span.shrink_to_hi(), ")".to_string()), - ], - Applicability::MachineApplicable, - ); - err.note( - "for more on the distinction between the stack and the heap, read \ - https://doc.rust-lang.org/book/ch15-01-box.html, \ - https://doc.rust-lang.org/rust-by-example/std/box.html, and \ - https://doc.rust-lang.org/std/boxed/index.html", - ); + if self.can_coerce(self.tcx.mk_box(found), expected) { + let suggest_boxing = match found.kind() { + ty::Tuple(tuple) if tuple.is_empty() => { + SuggestBoxing::Unit { start: span.shrink_to_lo(), end: span } + } + ty::Generator(def_id, ..) + if matches!( + self.tcx.generator_kind(def_id), + Some(GeneratorKind::Async(AsyncGeneratorKind::Closure)) + ) => + { + SuggestBoxing::AsyncBody + } + _ => SuggestBoxing::Other { start: span.shrink_to_lo(), end: span.shrink_to_hi() }, + }; + err.subdiagnostic(suggest_boxing); + true } else { false @@ -794,7 +794,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; }; - // get all where BoundPredicates here, because they are used in to cases below + // get all where BoundPredicates here, because they are used in two cases below let where_predicates = predicates .iter() .filter_map(|p| match p { @@ -1096,10 +1096,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx, self.misc(expr.span), self.param_env, - ty::Binder::dummy(self.tcx.mk_trait_ref( + ty::TraitRef::new(self.tcx, into_def_id, [expr_ty, expected_ty] - )), + ), )) { let sugg = if expr.precedence().order() >= PREC_POSTFIX { @@ -1252,7 +1252,7 @@ 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; } @@ -1311,7 +1311,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We have satisfied all requirements to provide a suggestion. Emit it. err.span_suggestion( - span, + *span, format!("if you meant to create a null pointer, use `{null_path_str}()`"), null_path_str + "()", Applicability::MachineApplicable, @@ -1384,7 +1384,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let item_ty = self.tcx.type_of(item.def_id).subst_identity(); // FIXME(compiler-errors): This check is *so* rudimentary - if item_ty.needs_subst() { + if item_ty.has_param() { return false; } if self.can_coerce(item_ty, expected_ty) { @@ -1438,7 +1438,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && !results.expr_adjustments(callee_expr).iter().any(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(..))) // Check that we're in fact trying to clone into the expected type && self.can_coerce(*pointee_ty, expected_ty) - && let trait_ref = ty::Binder::dummy(self.tcx.mk_trait_ref(clone_trait_did, [expected_ty])) + && let trait_ref = ty::TraitRef::new(self.tcx, clone_trait_did, [expected_ty]) // And the expected type doesn't implement `Clone` && !self.predicate_must_hold_considering_regions(&traits::Obligation::new( self.tcx, @@ -1449,7 +1449,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { diag.span_note( callee_expr.span, - &format!( + format!( "`{expected_ty}` does not implement `Clone`, so `{found_ty}` was cloned instead" ), ); -- cgit v1.2.3