diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 5d3997289bb33..6508c0da75f94 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -181,11 +181,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let generic_ty = type_test.generic_kind.to_ty(self.infcx.tcx); let origin = RelateParamBound(type_test_span, generic_ty, None); self.buffer_error(self.infcx.construct_generic_bound_failure( + self.body.source.def_id().expect_local(), type_test_span, Some(origin), type_test.generic_kind, lower_bound_region, - self.body.source.def_id().as_local(), )); } else { // FIXME. We should handle this case better. It diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 4f59215c70b92..d7505717bf3d2 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -63,7 +63,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString, Mul use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; -use rustc_hir::{Item, ItemKind, Node}; +use rustc_hir::Node; use rustc_middle::dep_graph::DepContext; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{ @@ -348,7 +348,11 @@ pub fn same_type_modulo_infer<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { } impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - pub fn report_region_errors(&self, errors: &[RegionResolutionError<'tcx>]) { + pub fn report_region_errors( + &self, + generic_param_scope: LocalDefId, + errors: &[RegionResolutionError<'tcx>], + ) { debug!("report_region_errors(): {} errors to start", errors.len()); // try to pre-process the errors, which will group some of them @@ -379,6 +383,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { RegionResolutionError::GenericBoundFailure(origin, param_ty, sub) => { self.report_generic_bound_failure( + generic_param_scope, origin.span(), Some(origin), param_ty, @@ -2269,56 +2274,30 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn report_generic_bound_failure( &self, + generic_param_scope: LocalDefId, span: Span, origin: Option>, bound_kind: GenericKind<'tcx>, sub: Region<'tcx>, ) { - let owner = - self.in_progress_typeck_results.map(|typeck_results| typeck_results.borrow().hir_owner); - self.construct_generic_bound_failure(span, origin, bound_kind, sub, owner).emit(); + self.construct_generic_bound_failure(generic_param_scope, span, origin, bound_kind, sub) + .emit(); } pub fn construct_generic_bound_failure( &self, + generic_param_scope: LocalDefId, span: Span, origin: Option>, bound_kind: GenericKind<'tcx>, sub: Region<'tcx>, - owner: Option, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - let hir = self.tcx.hir(); // Attempt to obtain the span of the parameter so we can // suggest adding an explicit lifetime bound to it. - let generics = owner.map(|owner| { - let hir_id = hir.local_def_id_to_hir_id(owner); - let parent_id = hir.get_parent_item(hir_id); - ( - // Parent item could be a `mod`, so we check the HIR before calling: - if let Some(Node::Item(Item { - kind: ItemKind::Trait(..) | ItemKind::Impl { .. }, - .. - })) = hir.find_by_def_id(parent_id) - { - Some(self.tcx.generics_of(parent_id)) - } else { - None - }, - self.tcx.generics_of(owner.to_def_id()), - hir.span(hir_id), - ) - }); - - let span = match generics { - // This is to get around the trait identity obligation, that has a `DUMMY_SP` as signal - // for other diagnostics, so we need to recover it here. - Some((_, _, node)) if span.is_dummy() => node, - _ => span, - }; - + let generics = self.tcx.generics_of(generic_param_scope); // type_param_span is (span, has_bounds) - let type_param_span = match (generics, bound_kind) { - (Some((_, ref generics, _)), GenericKind::Param(ref param)) => { + let type_param_span = match bound_kind { + GenericKind::Param(ref param) => { // Account for the case where `param` corresponds to `Self`, // which doesn't have the expected type argument. if !(generics.has_self && param.index == 0) { @@ -2346,30 +2325,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } _ => None, }; - let new_lt = generics - .as_ref() - .and_then(|(parent_g, g, _)| { - let mut possible = (b'a'..=b'z').map(|c| format!("'{}", c as char)); - let mut lts_names = g - .params - .iter() + + let new_lt = { + let mut possible = (b'a'..=b'z').map(|c| format!("'{}", c as char)); + let lts_names = + iter::successors(Some(generics), |g| g.parent.map(|p| self.tcx.generics_of(p))) + .flat_map(|g| &g.params) .filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime)) .map(|p| p.name.as_str()) .collect::>(); - if let Some(g) = parent_g { - lts_names.extend( - g.params - .iter() - .filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime)) - .map(|p| p.name.as_str()), - ); - } - possible.find(|candidate| !lts_names.contains(&&candidate[..])) - }) - .unwrap_or("'lt".to_string()); + possible + .find(|candidate| !lts_names.contains(&&candidate[..])) + .unwrap_or("'lt".to_string()) + }; + let add_lt_sugg = generics - .as_ref() - .and_then(|(_, g, _)| g.params.first()) + .params + .first() .and_then(|param| param.def_id.as_local()) .map(|def_id| (self.tcx.def_span(def_id).shrink_to_lo(), format!("{}, ", new_lt))); @@ -2571,7 +2543,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); if let Some(infer::RelateParamBound(_, t, _)) = origin { let return_impl_trait = - owner.and_then(|owner| self.tcx.return_type_impl_trait(owner)).is_some(); + self.tcx.return_type_impl_trait(generic_param_scope).is_some(); let t = self.resolve_vars_if_possible(t); match t.kind() { // We've got: diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 881682678dbed..c5a342c1ba2ca 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1301,7 +1301,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// result. After this, no more unification operations should be /// done -- or the compiler will panic -- but it is legal to use /// `resolve_vars_if_possible` as well as `fully_resolve`. - pub fn resolve_regions_and_report_errors(&self, outlives_env: &OutlivesEnvironment<'tcx>) { + pub fn resolve_regions_and_report_errors( + &self, + generic_param_scope: LocalDefId, + outlives_env: &OutlivesEnvironment<'tcx>, + ) { let errors = self.resolve_regions(outlives_env); if !self.is_tainted_by_errors() { @@ -1310,7 +1314,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // this infcx was in use. This is totally hokey but // otherwise we have a hard time separating legit region // errors from silly ones. - self.report_region_errors(&errors); + self.report_region_errors(generic_param_scope, &errors); } } diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 59cf39abe6440..a57971bfb697d 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -68,6 +68,7 @@ use crate::infer::{ }; use crate::traits::{ObligationCause, ObligationCauseCode}; use rustc_data_structures::undo_log::UndoLogs; +use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeVisitable}; use smallvec::smallvec; @@ -163,6 +164,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { pub fn check_region_obligations_and_report_errors( &self, + generic_param_scope: LocalDefId, outlives_env: &OutlivesEnvironment<'tcx>, ) { self.process_registered_region_obligations( @@ -170,7 +172,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { outlives_env.param_env, ); - self.resolve_regions_and_report_errors(outlives_env) + self.resolve_regions_and_report_errors(generic_param_scope, outlives_env) } } diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 348397cea67fa..0f7dc6a1257e5 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -1,10 +1,22 @@ -use rustc_middle::ty::TyCtxt; +use std::cell::RefCell; use super::TraitEngine; use super::{ChalkFulfillmentContext, FulfillmentContext}; +use crate::infer::InferCtxtExt; +use rustc_hir::def_id::DefId; +use rustc_infer::infer::{InferCtxt, InferOk}; +use rustc_infer::traits::{ + FulfillmentError, Obligation, ObligationCause, PredicateObligation, TraitEngineExt as _, +}; +use rustc_middle::ty::error::TypeError; +use rustc_middle::ty::ToPredicate; +use rustc_middle::ty::TypeFoldable; +use rustc_middle::ty::{self, Ty, TyCtxt}; pub trait TraitEngineExt<'tcx> { fn new(tcx: TyCtxt<'tcx>) -> Box; + + fn new_ignoring_regions(tcx: TyCtxt<'tcx>) -> Box; } impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> { @@ -15,4 +27,96 @@ impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> { Box::new(FulfillmentContext::new()) } } + + fn new_ignoring_regions(tcx: TyCtxt<'tcx>) -> Box { + if tcx.sess.opts.unstable_opts.chalk { + Box::new(ChalkFulfillmentContext::new()) + } else { + Box::new(FulfillmentContext::new_ignoring_regions()) + } + } +} + +/// Used if you want to have pleasant experience when dealing +/// with obligations outside of hir or mir typeck. +pub struct ObligationCtxt<'a, 'tcx> { + pub infcx: &'a InferCtxt<'a, 'tcx>, + engine: RefCell>>, +} + +impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { + pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self { + Self { infcx, engine: RefCell::new(>::new(infcx.tcx)) } + } + + pub fn register_obligation(&self, obligation: PredicateObligation<'tcx>) { + self.engine.borrow_mut().register_predicate_obligation(self.infcx, obligation); + } + + pub fn register_obligations( + &self, + obligations: impl IntoIterator>, + ) { + // Can't use `register_predicate_obligations` because the iterator + // may also use this `ObligationCtxt`. + for obligation in obligations { + self.engine.borrow_mut().register_predicate_obligation(self.infcx, obligation) + } + } + + pub fn register_infer_ok_obligations(&self, infer_ok: InferOk<'tcx, T>) -> T { + let InferOk { value, obligations } = infer_ok; + self.engine.borrow_mut().register_predicate_obligations(self.infcx, obligations); + value + } + + /// Requires that `ty` must implement the trait with `def_id` in + /// the given environment. This trait must not have any type + /// parameters (except for `Self`). + pub fn register_bound( + &self, + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + def_id: DefId, + ) { + let tcx = self.infcx.tcx; + let trait_ref = ty::TraitRef { def_id, substs: tcx.mk_substs_trait(ty, &[]) }; + self.register_obligation(Obligation { + cause, + recursion_depth: 0, + param_env, + predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx), + }); + } + + pub fn normalize>( + &self, + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + value: T, + ) -> T { + let infer_ok = self.infcx.partially_normalize_associated_types_in(cause, param_env, value); + self.register_infer_ok_obligations(infer_ok) + } + + pub fn equate_types( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + expected: Ty<'tcx>, + actual: Ty<'tcx>, + ) -> Result<(), TypeError<'tcx>> { + match self.infcx.at(cause, param_env).eq(expected, actual) { + Ok(InferOk { obligations, value: () }) => { + self.register_obligations(obligations); + Ok(()) + } + Err(e) => Err(e), + } + } + + pub fn select_all_or_error(&self) -> Vec> { + self.engine.borrow_mut().select_all_or_error(self.infcx) + } } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 0ad1b47a89079..a14bf72242bed 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -47,7 +47,7 @@ pub use self::SelectionError::*; pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls}; pub use self::coherence::{OrphanCheckErr, OverlapResult}; -pub use self::engine::TraitEngineExt; +pub use self::engine::{ObligationCtxt, TraitEngineExt}; pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation}; pub use self::object_safety::astconv_object_safety_violations; pub use self::object_safety::is_vtable_safe_method; @@ -237,29 +237,37 @@ fn do_normalize_predicates<'tcx>( // cares about declarations like `'a: 'b`. let outlives_env = OutlivesEnvironment::new(elaborated_env); - infcx.resolve_regions_and_report_errors(&outlives_env); + // FIXME: It's very weird that we ignore region obligations but apparently + // still need to use `resolve_regions` as we need the resolved regions in + // the normalized predicates. + let errors = infcx.resolve_regions(&outlives_env); + if !errors.is_empty() { + tcx.sess.delay_span_bug( + span, + format!( + "failed region resolution while normalizing {elaborated_env:?}: {errors:?}" + ), + ); + } - let predicates = match infcx.fully_resolve(predicates) { - Ok(predicates) => predicates, + match infcx.fully_resolve(predicates) { + Ok(predicates) => Ok(predicates), Err(fixup_err) => { // If we encounter a fixup error, it means that some type // variable wound up unconstrained. I actually don't know // if this can happen, and I certainly don't expect it to // happen often, but if it did happen it probably // represents a legitimate failure due to some kind of - // unconstrained variable, and it seems better not to ICE, - // all things considered. - let reported = tcx.sess.span_err(span, &fixup_err.to_string()); - return Err(reported); + // unconstrained variable. + // + // @lcnr: Let's still ICE here for now. I want a test case + // for that. + span_bug!( + span, + "inference variables in normalized parameter environment: {}", + fixup_err + ); } - }; - if predicates.needs_infer() { - let reported = tcx - .sess - .delay_span_bug(span, "encountered inference variables after `fully_resolve`"); - Err(reported) - } else { - Ok(predicates) } }) } diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index eccfb3477b9dd..449d7a7b47b1f 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -254,7 +254,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { let result = tcx.normalize_projection_ty(c_data)?; // We don't expect ambiguity. if result.is_ambiguous() { - return Err(NoSolution); + bug!("unexpected ambiguity: {:?} {:?}", c_data, result); } let InferOk { value: result, obligations } = self.infcx.instantiate_query_response_and_region_obligations( @@ -293,7 +293,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { let result = tcx.normalize_projection_ty(c_data)?; // We don't expect ambiguity. if result.is_ambiguous() { - return Err(NoSolution); + bug!("unexpected ambiguity: {:?} {:?}", c_data, result); } let InferOk { value: result, obligations } = self.infcx.instantiate_query_response_and_region_obligations( diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index bd2e89a4dc541..69f3f03cfa97c 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -1,10 +1,9 @@ -use crate::check::wfcheck::for_item; +use crate::check::intrinsicck::InlineAsmCtxt; use super::coercion::CoerceMany; use super::compare_method::check_type_bounds; use super::compare_method::{compare_const_impl, compare_impl_method, compare_ty_impl}; use super::*; - use rustc_attr as attr; use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; @@ -29,8 +28,8 @@ use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVE use rustc_span::symbol::sym; use rustc_span::{self, Span}; use rustc_target::spec::abi::Abi; -use rustc_trait_selection::traits; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; +use rustc_trait_selection::traits::{self, ObligationCtxt}; use rustc_ty_utils::representability::{self, Representability}; use std::iter; @@ -733,14 +732,13 @@ fn check_opaque_meets_bounds<'tcx>( let param_env = tcx.param_env(defining_use_anchor); tcx.infer_ctxt().with_opaque_type_inference(defining_use_anchor).enter(move |infcx| { - let inh = Inherited::new(infcx, def_id); - let infcx = &inh.infcx; + let ocx = ObligationCtxt::new(&infcx); let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs); let misc_cause = traits::ObligationCause::misc(span, hir_id); match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_type) { - Ok(infer_ok) => inh.register_infer_ok_obligations(infer_ok), + Ok(infer_ok) => ocx.register_infer_ok_obligations(infer_ok), Err(ty_err) => { tcx.sess.delay_span_bug( span, @@ -754,11 +752,11 @@ fn check_opaque_meets_bounds<'tcx>( // hidden type is well formed even without those bounds. let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_type.into())).to_predicate(tcx); - inh.register_predicate(Obligation::new(misc_cause, param_env, predicate)); + ocx.register_obligation(Obligation::new(misc_cause, param_env, predicate)); // Check that all obligations are satisfied by the implementation's // version. - let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx); + let errors = ocx.select_all_or_error(); if !errors.is_empty() { infcx.report_fulfillment_errors(&errors, None, false); } @@ -769,7 +767,10 @@ fn check_opaque_meets_bounds<'tcx>( // Can have different predicates to their defining use hir::OpaqueTyOrigin::TyAlias => { let outlives_environment = OutlivesEnvironment::new(param_env); - infcx.check_region_obligations_and_report_errors(&outlives_environment); + infcx.check_region_obligations_and_report_errors( + defining_use_anchor, + &outlives_environment, + ); } } @@ -940,10 +941,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { DefKind::GlobalAsm => { let it = tcx.hir().item(id); let hir::ItemKind::GlobalAsm(asm) = it.kind else { span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it) }; - for_item(tcx, it).with_fcx(|fcx| { - fcx.check_asm(asm, it.hir_id()); - Default::default() - }) + InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, id.hir_id()); } _ => {} } diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 3a31df32298d7..1f921ca835890 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -1,4 +1,6 @@ +use super::potentially_plural_count; use crate::check::regionck::OutlivesEnvironmentExt; +use crate::check::wfcheck; use crate::errors::LifetimesOrBoundsMismatchOnTrait; use rustc_data_structures::stable_set::FxHashSet; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed}; @@ -7,7 +9,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit; use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; -use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; +use rustc_infer::infer::{self, TyCtxtInferExt}; use rustc_infer::traits::util; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::subst::{InternalSubsts, Subst}; @@ -16,11 +18,11 @@ use rustc_middle::ty::{self, DefIdTree}; use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt}; use rustc_span::Span; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; -use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; +use rustc_trait_selection::traits::{ + self, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal, +}; use std::iter; -use super::{potentially_plural_count, FnCtxt, Inherited}; - /// Checks that a method from an impl conforms to the signature of /// the same method as declared in the trait. /// @@ -205,21 +207,19 @@ fn compare_predicate_entailment<'tcx>( ); let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); - tcx.infer_ctxt().enter(|infcx| { - let inh = Inherited::new(infcx, impl_m.def_id.expect_local()); - let infcx = &inh.infcx; + tcx.infer_ctxt().enter(|ref infcx| { + let ocx = ObligationCtxt::new(infcx); debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds()); let mut selcx = traits::SelectionContext::new(&infcx); - let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs); for (predicate, span) in iter::zip(impl_m_own_bounds.predicates, impl_m_own_bounds.spans) { let normalize_cause = traits::ObligationCause::misc(span, impl_m_hir_id); let traits::Normalized { value: predicate, obligations } = traits::normalize(&mut selcx, param_env, normalize_cause, predicate); - inh.register_predicates(obligations); + ocx.register_obligations(obligations); let cause = ObligationCause::new( span, impl_m_hir_id, @@ -228,7 +228,7 @@ fn compare_predicate_entailment<'tcx>( trait_item_def_id: trait_m.def_id, }, ); - inh.register_predicate(traits::Obligation::new(cause, param_env, predicate)); + ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate)); } // We now need to check that the signature of the impl method is @@ -254,32 +254,31 @@ fn compare_predicate_entailment<'tcx>( infer::HigherRankedType, tcx.fn_sig(impl_m.def_id), ); - let impl_sig = - inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, impl_sig); + + let norm_cause = ObligationCause::misc(impl_m_span, impl_m_hir_id); + let impl_sig = ocx.normalize(norm_cause.clone(), param_env, impl_sig); let impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig)); debug!("compare_impl_method: impl_fty={:?}", impl_fty); let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs); let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig); - let trait_sig = - inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, trait_sig); + let trait_sig = ocx.normalize(norm_cause, param_env, trait_sig); // Add the resulting inputs and output as well-formed. wf_tys.extend(trait_sig.inputs_and_output.iter()); let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig)); debug!("compare_impl_method: trait_fty={:?}", trait_fty); - let sub_result = infcx.at(&cause, param_env).sup(trait_fty, impl_fty).map( - |InferOk { obligations, .. }| { - // FIXME: We'd want to keep more accurate spans than "the method signature" when - // processing the comparison between the trait and impl fn, but we sadly lose them - // and point at the whole signature when a trait bound or specific input or output - // type would be more appropriate. In other places we have a `Vec` - // corresponding to their `Vec`, but we don't have that here. - // Fixing this would improve the output of test `issue-83765.rs`. - inh.register_predicates(obligations); - }, - ); + // FIXME: We'd want to keep more accurate spans than "the method signature" when + // processing the comparison between the trait and impl fn, but we sadly lose them + // and point at the whole signature when a trait bound or specific input or output + // type would be more appropriate. In other places we have a `Vec` + // corresponding to their `Vec`, but we don't have that here. + // Fixing this would improve the output of test `issue-83765.rs`. + let sub_result = infcx + .at(&cause, param_env) + .sup(trait_fty, impl_fty) + .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok)); if let Err(terr) = sub_result { debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty); @@ -385,7 +384,7 @@ fn compare_predicate_entailment<'tcx>( // Check that all obligations are satisfied by the implementation's // version. - let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx); + let errors = ocx.select_all_or_error(); if !errors.is_empty() { let reported = infcx.report_fulfillment_errors(&errors, None, false); return Err(reported); @@ -395,7 +394,10 @@ fn compare_predicate_entailment<'tcx>( // lifetime parameters. let mut outlives_environment = OutlivesEnvironment::new(param_env); outlives_environment.add_implied_bounds(infcx, wf_tys, impl_m_hir_id); - infcx.check_region_obligations_and_report_errors(&outlives_environment); + infcx.check_region_obligations_and_report_errors( + impl_m.def_id.expect_local(), + &outlives_environment, + ); Ok(()) }) @@ -1058,8 +1060,7 @@ pub(crate) fn compare_const_impl<'tcx>( tcx.infer_ctxt().enter(|infcx| { let param_env = tcx.param_env(impl_c.def_id); - let inh = Inherited::new(infcx, impl_c.def_id.expect_local()); - let infcx = &inh.infcx; + let ocx = ObligationCtxt::new(&infcx); // The below is for the most part highly similar to the procedure // for methods above. It is simpler in many respects, especially @@ -1082,20 +1083,18 @@ pub(crate) fn compare_const_impl<'tcx>( ); // There is no "body" here, so just pass dummy id. - let impl_ty = - inh.normalize_associated_types_in(impl_c_span, impl_c_hir_id, param_env, impl_ty); + let impl_ty = ocx.normalize(cause.clone(), param_env, impl_ty); debug!("compare_const_impl: impl_ty={:?}", impl_ty); - let trait_ty = - inh.normalize_associated_types_in(impl_c_span, impl_c_hir_id, param_env, trait_ty); + let trait_ty = ocx.normalize(cause.clone(), param_env, trait_ty); debug!("compare_const_impl: trait_ty={:?}", trait_ty); let err = infcx .at(&cause, param_env) .sup(trait_ty, impl_ty) - .map(|ok| inh.register_infer_ok_obligations(ok)); + .map(|ok| ocx.register_infer_ok_obligations(ok)); if let Err(terr) = err { debug!( @@ -1142,14 +1141,15 @@ pub(crate) fn compare_const_impl<'tcx>( // Check that all obligations are satisfied by the implementation's // version. - let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx); + let errors = ocx.select_all_or_error(); if !errors.is_empty() { infcx.report_fulfillment_errors(&errors, None, false); return; } let outlives_environment = OutlivesEnvironment::new(param_env); - infcx.resolve_regions_and_report_errors(&outlives_environment); + infcx + .resolve_regions_and_report_errors(impl_c.def_id.expect_local(), &outlives_environment); }); } @@ -1241,8 +1241,7 @@ fn compare_type_predicate_entailment<'tcx>( ); let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause.clone()); tcx.infer_ctxt().enter(|infcx| { - let inh = Inherited::new(infcx, impl_ty.def_id.expect_local()); - let infcx = &inh.infcx; + let ocx = ObligationCtxt::new(&infcx); debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds()); @@ -1252,13 +1251,13 @@ fn compare_type_predicate_entailment<'tcx>( let traits::Normalized { value: predicate, obligations } = traits::normalize(&mut selcx, param_env, normalize_cause.clone(), predicate); - inh.register_predicates(obligations); - inh.register_predicate(traits::Obligation::new(cause.clone(), param_env, predicate)); + ocx.register_obligations(obligations); + ocx.register_obligation(traits::Obligation::new(cause.clone(), param_env, predicate)); } // Check that all obligations are satisfied by the implementation's // version. - let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx); + let errors = ocx.select_all_or_error(); if !errors.is_empty() { let reported = infcx.report_fulfillment_errors(&errors, None, false); return Err(reported); @@ -1267,7 +1266,10 @@ fn compare_type_predicate_entailment<'tcx>( // Finally, resolve all regions. This catches wily misuses of // lifetime parameters. let outlives_environment = OutlivesEnvironment::new(param_env); - infcx.check_region_obligations_and_report_errors(&outlives_environment); + infcx.check_region_obligations_and_report_errors( + impl_ty.def_id.expect_local(), + &outlives_environment, + ); Ok(()) }) @@ -1431,10 +1433,9 @@ pub fn check_type_bounds<'tcx>( impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs); tcx.infer_ctxt().enter(move |infcx| { - let inh = Inherited::new(infcx, impl_ty.def_id.expect_local()); - let infcx = &inh.infcx; - let mut selcx = traits::SelectionContext::new(&infcx); + let ocx = ObligationCtxt::new(&infcx); + let mut selcx = traits::SelectionContext::new(&infcx); let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local()); let normalize_cause = ObligationCause::new( impl_ty_span, @@ -1477,13 +1478,13 @@ pub fn check_type_bounds<'tcx>( debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate); obligation.predicate = normalized_predicate; - inh.register_predicates(obligations); - inh.register_predicate(obligation); + ocx.register_obligations(obligations); + ocx.register_obligation(obligation); } // Check that all obligations are satisfied by the implementation's // version. - let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx); + let errors = ocx.select_all_or_error(); if !errors.is_empty() { let reported = infcx.report_fulfillment_errors(&errors, None, false); return Err(reported); @@ -1491,16 +1492,18 @@ pub fn check_type_bounds<'tcx>( // Finally, resolve all regions. This catches wily misuses of // lifetime parameters. - // - // FIXME: Remove that `FnCtxt`. - let fcx = FnCtxt::new(&inh, param_env, impl_ty_hir_id); let implied_bounds = match impl_ty.container { ty::TraitContainer(_) => FxHashSet::default(), - ty::ImplContainer(def_id) => fcx.impl_implied_bounds(def_id, impl_ty_span), + ty::ImplContainer(def_id) => { + wfcheck::impl_implied_bounds(tcx, param_env, def_id.expect_local(), impl_ty_span) + } }; let mut outlives_environment = OutlivesEnvironment::new(param_env); - outlives_environment.add_implied_bounds(infcx, implied_bounds, impl_ty_hir_id); - infcx.check_region_obligations_and_report_errors(&outlives_environment); + outlives_environment.add_implied_bounds(&infcx, implied_bounds, impl_ty_hir_id); + infcx.check_region_obligations_and_report_errors( + impl_ty.def_id.expect_local(), + &outlives_environment, + ); Ok(()) }) diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index d15d40bc24756..42a9a23559c9e 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -37,7 +37,6 @@ use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::{ self, ObligationCause, ObligationCauseCode, StatementAsExpression, TraitEngine, TraitEngineExt, - WellFormedLoc, }; use std::collections::hash_map::Entry; @@ -375,29 +374,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (result, spans) } - /// Convenience method which tracks extra diagnostic information for normalization - /// that occurs as a result of WF checking. The `hir_id` is the `HirId` of the hir item - /// whose type is being wf-checked - this is used to construct a more precise span if - /// an error occurs. - /// - /// It is never necessary to call this method - calling `normalize_associated_types_in` will - /// just result in a slightly worse diagnostic span, and will still be sound. - pub(in super::super) fn normalize_associated_types_in_wf( - &self, - span: Span, - value: T, - loc: WellFormedLoc, - ) -> T - where - T: TypeFoldable<'tcx>, - { - self.inh.normalize_associated_types_in_with_cause( - ObligationCause::new(span, self.body_id, ObligationCauseCode::WellFormed(Some(loc))), - self.param_env, - value, - ) - } - pub(in super::super) fn normalize_associated_types_in(&self, span: Span, value: T) -> T where T: TypeFoldable<'tcx>, diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index ec045d3e70c96..89b376442a887 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -4,6 +4,7 @@ use crate::check::fn_ctxt::arg_matrix::{ ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx, }; use crate::check::gather_locals::Declaration; +use crate::check::intrinsicck::InlineAsmCtxt; use crate::check::method::MethodCallee; use crate::check::Expectation::*; use crate::check::TupleArgumentsFlag::*; @@ -59,7 +60,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("FnCtxt::check_asm: {} deferred checks", deferred_asm_checks.len()); for (asm, hir_id) in deferred_asm_checks.drain(..) { let enclosing_id = self.tcx.hir().enclosing_body_owner(hir_id); - self.check_asm(asm, enclosing_id); + InlineAsmCtxt::new_in_fn(self).check_asm(asm, enclosing_id); } } diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs index 2ce258cf69c7a..4afbc00b37c73 100644 --- a/compiler/rustc_typeck/src/check/inherited.rs +++ b/compiler/rustc_typeck/src/check/inherited.rs @@ -103,7 +103,7 @@ impl<'tcx> InheritedBuilder<'tcx> { } impl<'a, 'tcx> Inherited<'a, 'tcx> { - pub(super) fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self { + fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self { let tcx = infcx.tcx; let item_id = tcx.hir().local_def_id_to_hir_id(def_id); let body_id = tcx.hir().maybe_body_owned_by(item_id); @@ -113,7 +113,7 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> { maybe_typeck_results: infcx.in_progress_typeck_results, }, infcx, - fulfillment_cx: RefCell::new(>::new(tcx)), + fulfillment_cx: RefCell::new(>::new_ignoring_regions(tcx)), locals: RefCell::new(Default::default()), deferred_sized_obligations: RefCell::new(Vec::new()), deferred_call_resolutions: RefCell::new(Default::default()), diff --git a/compiler/rustc_typeck/src/check/intrinsicck.rs b/compiler/rustc_typeck/src/check/intrinsicck.rs index a5add1e9a8acb..0adf0d28aae10 100644 --- a/compiler/rustc_typeck/src/check/intrinsicck.rs +++ b/compiler/rustc_typeck/src/check/intrinsicck.rs @@ -111,6 +111,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } false } +} + +pub struct InlineAsmCtxt<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + fcx: Option<&'a FnCtxt<'a, 'tcx>>, +} + +impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { + pub fn new_global_asm(tcx: TyCtxt<'tcx>) -> Self { + InlineAsmCtxt { tcx, fcx: None } + } + + pub fn new_in_fn(fcx: &'a FnCtxt<'a, 'tcx>) -> Self { + InlineAsmCtxt { tcx: fcx.tcx, fcx: Some(fcx) } + } fn check_asm_operand_type( &self, @@ -122,9 +137,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tied_input: Option<(&hir::Expr<'tcx>, Option)>, target_features: &FxHashSet, ) -> Option { + let fcx = self.fcx.unwrap_or_else(|| span_bug!(expr.span, "asm operand for global asm")); // Check the type against the allowed types for inline asm. - let ty = self.typeck_results.borrow().expr_ty_adjusted(expr); - let ty = self.resolve_vars_if_possible(ty); + let ty = fcx.typeck_results.borrow().expr_ty_adjusted(expr); + let ty = fcx.resolve_vars_if_possible(ty); let asm_ty_isize = match self.tcx.sess.target.pointer_width { 16 => InlineAsmType::I16, 32 => InlineAsmType::I32, @@ -134,7 +150,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Expect types to be fully resolved, no const or type variables. if ty.has_infer_types_or_consts() { - assert!(self.is_tainted_by_errors()); + assert!(fcx.is_tainted_by_errors()); return None; } @@ -151,7 +167,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Float(FloatTy::F32) => Some(InlineAsmType::F32), ty::Float(FloatTy::F64) => Some(InlineAsmType::F64), ty::FnPtr(_) => Some(asm_ty_isize), - ty::RawPtr(ty::TypeAndMut { ty, mutbl: _ }) if self.is_thin_ptr_ty(ty) => { + ty::RawPtr(ty::TypeAndMut { ty, mutbl: _ }) if fcx.is_thin_ptr_ty(ty) => { Some(asm_ty_isize) } ty::Adt(adt, substs) if adt.repr().simd() => { @@ -203,7 +219,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Check that the type implements Copy. The only case where this can // possibly fail is for SIMD types which don't #[derive(Copy)]. - if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, DUMMY_SP) { + if !fcx.infcx.type_is_copy_modulo_regions(fcx.param_env, ty, DUMMY_SP) { let msg = "arguments for inline assembly must be copyable"; let mut err = self.tcx.sess.struct_span_err(expr.span, msg); err.note(&format!("`{ty}` does not implement the Copy trait")); @@ -224,8 +240,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let msg = "incompatible types for asm inout argument"; let mut err = self.tcx.sess.struct_span_err(vec![in_expr.span, expr.span], msg); - let in_expr_ty = self.typeck_results.borrow().expr_ty_adjusted(in_expr); - let in_expr_ty = self.resolve_vars_if_possible(in_expr_ty); + let in_expr_ty = fcx.typeck_results.borrow().expr_ty_adjusted(in_expr); + let in_expr_ty = fcx.resolve_vars_if_possible(in_expr_ty); err.span_label(in_expr.span, &format!("type `{in_expr_ty}`")); err.span_label(expr.span, &format!("type `{ty}`")); err.note( diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index e205eba44571f..6df59ea10969c 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -1,7 +1,5 @@ use crate::check::regionck::OutlivesEnvironmentExt; -use crate::check::{FnCtxt, Inherited}; use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter}; - use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; @@ -13,6 +11,7 @@ use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::outlives::obligations::TypeOutlives; use rustc_infer::infer::region_constraints::GenericKind; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; +use rustc_infer::traits::Normalized; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst}; use rustc_middle::ty::trait_def::TraitSpecializationKind; @@ -23,53 +22,95 @@ use rustc_middle::ty::{ use rustc_session::parse::feature_err; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; +use rustc_trait_selection::autoderef::Autoderef; +use rustc_trait_selection::traits::error_reporting::InferCtxtExt; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; -use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, WellFormedLoc}; +use rustc_trait_selection::traits::query::normalize::AtExt; +use rustc_trait_selection::traits::query::NoSolution; +use rustc_trait_selection::traits::{ + self, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc, +}; use std::cell::LazyCell; use std::convert::TryInto; use std::iter; -use std::ops::ControlFlow; +use std::ops::{ControlFlow, Deref}; -/// Helper type of a temporary returned by `.for_item(...)`. -/// This is necessary because we can't write the following bound: -/// -/// ```ignore (illustrative) -/// F: for<'b, 'tcx> where 'tcx FnOnce(FnCtxt<'b, 'tcx>) -/// ``` -pub(super) struct CheckWfFcxBuilder<'tcx> { - inherited: super::InheritedBuilder<'tcx>, - id: hir::HirId, +pub(super) struct WfCheckingCtxt<'a, 'tcx> { + pub(super) ocx: ObligationCtxt<'a, 'tcx>, span: Span, + body_id: hir::HirId, param_env: ty::ParamEnv<'tcx>, } +impl<'a, 'tcx> Deref for WfCheckingCtxt<'a, 'tcx> { + type Target = ObligationCtxt<'a, 'tcx>; + fn deref(&self) -> &Self::Target { + &self.ocx + } +} + +impl<'tcx> WfCheckingCtxt<'_, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.ocx.infcx.tcx + } -impl<'tcx> CheckWfFcxBuilder<'tcx> { - pub(super) fn with_fcx(&mut self, f: F) + fn normalize(&self, span: Span, loc: Option, value: T) -> T where - F: for<'b> FnOnce(&FnCtxt<'b, 'tcx>) -> FxHashSet>, + T: TypeFoldable<'tcx>, { - let id = self.id; - let span = self.span; - let param_env = self.param_env; - self.inherited.enter(|inh| { - let fcx = FnCtxt::new(&inh, param_env, id); - if !inh.tcx.features().trivial_bounds { - // As predicates are cached rather than obligations, this - // needs to be called first so that they are checked with an - // empty `param_env`. - check_false_global_bounds(&fcx, span, id); - } - let wf_tys = f(&fcx); - fcx.select_all_obligations_or_error(); + self.ocx.normalize( + ObligationCause::new(span, self.body_id, ObligationCauseCode::WellFormed(loc)), + self.param_env, + value, + ) + } - let mut outlives_environment = OutlivesEnvironment::new(param_env); - outlives_environment.add_implied_bounds(&fcx.infcx, wf_tys, id); - fcx.infcx.check_region_obligations_and_report_errors(&outlives_environment); - }); + fn register_wf_obligation( + &self, + span: Span, + loc: Option, + arg: ty::GenericArg<'tcx>, + ) { + let cause = + traits::ObligationCause::new(span, self.body_id, ObligationCauseCode::WellFormed(loc)); + self.ocx.register_obligation(traits::Obligation::new( + cause, + self.param_env, + ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(self.tcx()), + )); } } +pub(super) fn enter_wf_checking_ctxt<'tcx, F>( + tcx: TyCtxt<'tcx>, + span: Span, + body_def_id: LocalDefId, + f: F, +) where + F: for<'a> FnOnce(&WfCheckingCtxt<'a, 'tcx>) -> FxHashSet>, +{ + let param_env = tcx.param_env(body_def_id); + let body_id = tcx.hir().local_def_id_to_hir_id(body_def_id); + tcx.infer_ctxt().enter(|ref infcx| { + let ocx = ObligationCtxt::new(infcx); + let mut wfcx = WfCheckingCtxt { ocx, span, body_id, param_env }; + + if !tcx.features().trivial_bounds { + wfcx.check_false_global_bounds() + } + let wf_tys = f(&mut wfcx); + let errors = wfcx.select_all_or_error(); + if !errors.is_empty() { + infcx.report_fulfillment_errors(&errors, None, false); + return; + } + + let mut outlives_environment = OutlivesEnvironment::new(param_env); + outlives_environment.add_implied_bounds(infcx, wf_tys, body_id); + infcx.check_region_obligations_and_report_errors(body_def_id, &outlives_environment); + }) +} + fn check_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { let node = tcx.hir().expect_owner(def_id); match node { @@ -174,17 +215,17 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) { check_item_type(tcx, item.def_id, ty.span, false); } hir::ItemKind::Struct(ref struct_def, ref ast_generics) => { - check_type_defn(tcx, item, false, |fcx| vec![fcx.non_enum_variant(struct_def)]); + check_type_defn(tcx, item, false, |wfcx| vec![wfcx.non_enum_variant(struct_def)]); check_variances_for_type_defn(tcx, item, ast_generics); } hir::ItemKind::Union(ref struct_def, ref ast_generics) => { - check_type_defn(tcx, item, true, |fcx| vec![fcx.non_enum_variant(struct_def)]); + check_type_defn(tcx, item, true, |wfcx| vec![wfcx.non_enum_variant(struct_def)]); check_variances_for_type_defn(tcx, item, ast_generics); } hir::ItemKind::Enum(ref enum_def, ref ast_generics) => { - check_type_defn(tcx, item, true, |fcx| fcx.enum_variants(enum_def)); + check_type_defn(tcx, item, true, |wfcx| wfcx.enum_variants(enum_def)); check_variances_for_type_defn(tcx, item, ast_generics); } @@ -933,45 +974,45 @@ fn check_associated_item( span: Span, sig_if_method: Option<&hir::FnSig<'_>>, ) { - let code = ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(item_id))); - for_id(tcx, item_id, span).with_fcx(|fcx| { - let item = fcx.tcx.associated_item(item_id); + let loc = Some(WellFormedLoc::Ty(item_id)); + enter_wf_checking_ctxt(tcx, span, item_id, |wfcx| { + let item = tcx.associated_item(item_id); let (mut implied_bounds, self_ty) = match item.container { - ty::TraitContainer(_) => (FxHashSet::default(), fcx.tcx.types.self_param), - ty::ImplContainer(def_id) => { - (fcx.impl_implied_bounds(def_id, span), fcx.tcx.type_of(def_id)) - } + ty::TraitContainer(_) => (FxHashSet::default(), tcx.types.self_param), + ty::ImplContainer(def_id) => ( + impl_implied_bounds(tcx, wfcx.param_env, def_id.expect_local(), span), + tcx.type_of(def_id), + ), }; match item.kind { ty::AssocKind::Const => { - let ty = fcx.tcx.type_of(item.def_id); - let ty = fcx.normalize_associated_types_in_wf(span, ty, WellFormedLoc::Ty(item_id)); - fcx.register_wf_obligation(ty.into(), span, code.clone()); + let ty = tcx.type_of(item.def_id); + let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty); + wfcx.register_wf_obligation(span, loc, ty.into()); } ty::AssocKind::Fn => { - let sig = fcx.tcx.fn_sig(item.def_id); + let sig = tcx.fn_sig(item.def_id); let hir_sig = sig_if_method.expect("bad signature for method"); check_fn_or_method( - fcx, - item.ident(fcx.tcx).span, + wfcx, + item.ident(tcx).span, sig, hir_sig.decl, item.def_id.expect_local(), &mut implied_bounds, ); - check_method_receiver(fcx, hir_sig, item, self_ty); + check_method_receiver(wfcx, hir_sig, item, self_ty); } ty::AssocKind::Type => { if let ty::AssocItemContainer::TraitContainer(_) = item.container { - check_associated_type_bounds(fcx, item, span) + check_associated_type_bounds(wfcx, item, span) } if item.defaultness.has_value() { - let ty = fcx.tcx.type_of(item.def_id); - let ty = - fcx.normalize_associated_types_in_wf(span, ty, WellFormedLoc::Ty(item_id)); - fcx.register_wf_obligation(ty.into(), span, code.clone()); + let ty = tcx.type_of(item.def_id); + let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty); + wfcx.register_wf_obligation(span, loc, ty.into()); } } } @@ -980,19 +1021,6 @@ fn check_associated_item( }) } -pub(super) fn for_item<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'_>) -> CheckWfFcxBuilder<'tcx> { - for_id(tcx, item.def_id, item.span) -} - -fn for_id(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> CheckWfFcxBuilder<'_> { - CheckWfFcxBuilder { - inherited: Inherited::build(tcx, def_id), - id: hir::HirId::make_owner(def_id), - span, - param_env: tcx.param_env(def_id), - } -} - fn item_adt_kind(kind: &ItemKind<'_>) -> Option { match kind { ItemKind::Struct(..) => Some(AdtKind::Struct), @@ -1009,19 +1037,19 @@ fn check_type_defn<'tcx, F>( all_sized: bool, mut lookup_fields: F, ) where - F: for<'fcx> FnMut(&FnCtxt<'fcx, 'tcx>) -> Vec>, + F: FnMut(&WfCheckingCtxt<'_, 'tcx>) -> Vec>, { - for_item(tcx, item).with_fcx(|fcx| { - let variants = lookup_fields(fcx); + enter_wf_checking_ctxt(tcx, item.span, item.def_id, |wfcx| { + let variants = lookup_fields(wfcx); let packed = tcx.adt_def(item.def_id).repr().packed(); for variant in &variants { // All field types must be well-formed. for field in &variant.fields { - fcx.register_wf_obligation( - field.ty.into(), + wfcx.register_wf_obligation( field.span, - ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(field.def_id))), + Some(WellFormedLoc::Ty(field.def_id)), + field.ty.into(), ) } @@ -1048,12 +1076,10 @@ fn check_type_defn<'tcx, F>( variant.fields[..variant.fields.len() - unsized_len].iter().enumerate() { let last = idx == variant.fields.len() - 1; - fcx.register_bound( - field.ty, - tcx.require_lang_item(LangItem::Sized, None), + wfcx.register_bound( traits::ObligationCause::new( field.span, - fcx.body_id, + wfcx.body_id, traits::FieldSized { adt_kind: match item_adt_kind(&item.kind) { Some(i) => i, @@ -1063,6 +1089,9 @@ fn check_type_defn<'tcx, F>( last, }, ), + wfcx.param_env, + field.ty, + tcx.require_lang_item(LangItem::Sized, None), ); } @@ -1072,12 +1101,12 @@ fn check_type_defn<'tcx, F>( let cause = traits::ObligationCause::new( tcx.def_span(discr_def_id), - fcx.body_id, + wfcx.body_id, traits::MiscObligation, ); - fcx.register_predicate(traits::Obligation::new( + wfcx.register_obligation(traits::Obligation::new( cause, - fcx.param_env, + wfcx.param_env, ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ty::Unevaluated::new( ty::WithOptConstParam::unknown(discr_def_id.to_def_id()), discr_substs, @@ -1087,7 +1116,7 @@ fn check_type_defn<'tcx, F>( } } - check_where_clauses(fcx, item.span, item.def_id, None); + check_where_clauses(wfcx, item.span, item.def_id); // No implied bounds in a struct definition. FxHashSet::default() @@ -1113,9 +1142,8 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) { } } - // FIXME: this shouldn't use an `FnCtxt` at all. - for_item(tcx, item).with_fcx(|fcx| { - check_where_clauses(fcx, item.span, item.def_id, None); + enter_wf_checking_ctxt(tcx, item.span, item.def_id, |wfcx| { + check_where_clauses(wfcx, item.span, item.def_id); FxHashSet::default() }); @@ -1130,27 +1158,22 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) { /// /// Assuming the defaults are used, check that all predicates (bounds on the /// assoc type and where clauses on the trait) hold. -fn check_associated_type_bounds(fcx: &FnCtxt<'_, '_>, item: &ty::AssocItem, span: Span) { - let tcx = fcx.tcx; - - let bounds = tcx.explicit_item_bounds(item.def_id); +fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: &ty::AssocItem, span: Span) { + let bounds = wfcx.tcx().explicit_item_bounds(item.def_id); debug!("check_associated_type_bounds: bounds={:?}", bounds); let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| { - let normalized_bound = fcx.normalize_associated_types_in(span, bound); + let normalized_bound = wfcx.normalize(span, None, bound); traits::wf::predicate_obligations( - fcx, - fcx.param_env, - fcx.body_id, + wfcx.infcx, + wfcx.param_env, + wfcx.body_id, normalized_bound, bound_span, ) }); - for obligation in wf_obligations { - debug!("next obligation cause: {:?}", obligation.cause); - fcx.register_predicate(obligation); - } + wfcx.register_obligations(wf_obligations); } fn check_item_fn( @@ -1160,10 +1183,10 @@ fn check_item_fn( span: Span, decl: &hir::FnDecl<'_>, ) { - for_id(tcx, def_id, span).with_fcx(|fcx| { + enter_wf_checking_ctxt(tcx, span, def_id, |wfcx| { let sig = tcx.fn_sig(def_id); let mut implied_bounds = FxHashSet::default(); - check_fn_or_method(fcx, ident.span, sig, decl, def_id, &mut implied_bounds); + check_fn_or_method(wfcx, ident.span, sig, decl, def_id, &mut implied_bounds); implied_bounds }) } @@ -1171,28 +1194,25 @@ fn check_item_fn( fn check_item_type(tcx: TyCtxt<'_>, item_id: LocalDefId, ty_span: Span, allow_foreign_ty: bool) { debug!("check_item_type: {:?}", item_id); - for_id(tcx, item_id, ty_span).with_fcx(|fcx| { + enter_wf_checking_ctxt(tcx, ty_span, item_id, |wfcx| { let ty = tcx.type_of(item_id); - let item_ty = fcx.normalize_associated_types_in_wf(ty_span, ty, WellFormedLoc::Ty(item_id)); + let item_ty = wfcx.normalize(ty_span, Some(WellFormedLoc::Ty(item_id)), ty); let mut forbid_unsized = true; if allow_foreign_ty { - let tail = fcx.tcx.struct_tail_erasing_lifetimes(item_ty, fcx.param_env); + let tail = tcx.struct_tail_erasing_lifetimes(item_ty, wfcx.param_env); if let ty::Foreign(_) = tail.kind() { forbid_unsized = false; } } - fcx.register_wf_obligation( - item_ty.into(), - ty_span, - ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(item_id))), - ); + wfcx.register_wf_obligation(ty_span, Some(WellFormedLoc::Ty(item_id)), item_ty.into()); if forbid_unsized { - fcx.register_bound( + wfcx.register_bound( + traits::ObligationCause::new(ty_span, wfcx.body_id, traits::WellFormed(None)), + wfcx.param_env, item_ty, tcx.require_lang_item(LangItem::Sized, None), - traits::ObligationCause::new(ty_span, fcx.body_id, traits::WellFormed(None)), ); } @@ -1203,10 +1223,11 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: LocalDefId, ty_span: Span, allow_fo && !tcx.is_thread_local_static(item_id.to_def_id()); if should_check_for_sync { - fcx.register_bound( + wfcx.register_bound( + traits::ObligationCause::new(ty_span, wfcx.body_id, traits::SharedStatic), + wfcx.param_env, item_ty, tcx.require_lang_item(LangItem::Sync, Some(ty_span)), - traits::ObligationCause::new(ty_span, fcx.body_id, traits::SharedStatic), ); } @@ -1222,56 +1243,47 @@ fn check_impl<'tcx>( ast_self_ty: &hir::Ty<'_>, ast_trait_ref: &Option>, ) { - for_item(tcx, item).with_fcx(|fcx| { + enter_wf_checking_ctxt(tcx, item.span, item.def_id, |wfcx| { match *ast_trait_ref { Some(ref ast_trait_ref) => { // `#[rustc_reservation_impl]` impls are not real impls and // therefore don't need to be WF (the trait's `Self: Trait` predicate // won't hold). let trait_ref = tcx.impl_trait_ref(item.def_id).unwrap(); - let trait_ref = - fcx.normalize_associated_types_in(ast_trait_ref.path.span, trait_ref); + let trait_ref = wfcx.normalize(ast_trait_ref.path.span, None, trait_ref); let obligations = traits::wf::trait_obligations( - fcx, - fcx.param_env, - fcx.body_id, + wfcx.infcx, + wfcx.param_env, + wfcx.body_id, &trait_ref, ast_trait_ref.path.span, item, ); debug!(?obligations); - for obligation in obligations { - fcx.register_predicate(obligation); - } + wfcx.register_obligations(obligations); } None => { let self_ty = tcx.type_of(item.def_id); - let self_ty = fcx.normalize_associated_types_in(item.span, self_ty); - fcx.register_wf_obligation( - self_ty.into(), + let self_ty = wfcx.normalize(item.span, None, self_ty); + wfcx.register_wf_obligation( ast_self_ty.span, - ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty( - item.hir_id().expect_owner(), - ))), + Some(WellFormedLoc::Ty(item.hir_id().expect_owner())), + self_ty.into(), ); } } - check_where_clauses(fcx, item.span, item.def_id, None); + check_where_clauses(wfcx, item.span, item.def_id); - fcx.impl_implied_bounds(item.def_id.to_def_id(), item.span) + impl_implied_bounds(tcx, wfcx.param_env, item.def_id, item.span) }); } /// Checks where-clauses and inline bounds that are declared on `def_id`. -#[instrument(skip(fcx), level = "debug")] -fn check_where_clauses<'tcx, 'fcx>( - fcx: &FnCtxt<'fcx, 'tcx>, - span: Span, - def_id: LocalDefId, - return_ty: Option<(Ty<'tcx>, Span)>, -) { - let tcx = fcx.tcx; +#[instrument(level = "debug", skip(wfcx))] +fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id: LocalDefId) { + let infcx = wfcx.infcx; + let tcx = wfcx.tcx(); let predicates = tcx.predicates_of(def_id); let generics = tcx.generics_of(def_id); @@ -1299,11 +1311,7 @@ fn check_where_clauses<'tcx, 'fcx>( // parameter includes another (e.g., ``). In those cases, we can't // be sure if it will error or not as user might always specify the other. if !ty.needs_subst() { - fcx.register_wf_obligation( - ty.into(), - tcx.def_span(param.def_id), - ObligationCauseCode::MiscObligation, - ); + wfcx.register_wf_obligation(tcx.def_span(param.def_id), None, ty.into()); } } } @@ -1315,10 +1323,10 @@ fn check_where_clauses<'tcx, 'fcx>( // we should eagerly error. let default_ct = tcx.const_param_default(param.def_id); if !default_ct.needs_subst() { - fcx.register_wf_obligation( - default_ct.into(), + wfcx.register_wf_obligation( tcx.def_span(param.def_id), - ObligationCauseCode::WellFormed(None), + None, + default_ct.into(), ); } } @@ -1429,48 +1437,41 @@ fn check_where_clauses<'tcx, 'fcx>( // Note the subtle difference from how we handle `predicates` // below: there, we are not trying to prove those predicates // to be *true* but merely *well-formed*. - let pred = fcx.normalize_associated_types_in(sp, pred); + let pred = wfcx.normalize(sp, None, pred); let cause = traits::ObligationCause::new( sp, - fcx.body_id, + wfcx.body_id, traits::ItemObligation(def_id.to_def_id()), ); - traits::Obligation::new(cause, fcx.param_env, pred) + traits::Obligation::new(cause, wfcx.param_env, pred) }); let predicates = predicates.instantiate_identity(tcx); - if let Some((return_ty, _)) = return_ty { - if return_ty.has_infer_types_or_consts() { - fcx.select_obligations_where_possible(false, |_| {}); - } - } - - let predicates = fcx.normalize_associated_types_in(span, predicates); + let predicates = wfcx.normalize(span, None, predicates); debug!(?predicates.predicates); assert_eq!(predicates.predicates.len(), predicates.spans.len()); let wf_obligations = iter::zip(&predicates.predicates, &predicates.spans).flat_map(|(&p, &sp)| { - traits::wf::predicate_obligations(fcx, fcx.param_env, fcx.body_id, p, sp) + traits::wf::predicate_obligations(infcx, wfcx.param_env, wfcx.body_id, p, sp) }); - for obligation in wf_obligations.chain(default_obligations) { - debug!("next obligation cause: {:?}", obligation.cause); - fcx.register_predicate(obligation); - } + let obligations: Vec<_> = wf_obligations.chain(default_obligations).collect(); + wfcx.register_obligations(obligations); } -#[tracing::instrument(level = "debug", skip(fcx, span, hir_decl))] -fn check_fn_or_method<'fcx, 'tcx>( - fcx: &FnCtxt<'fcx, 'tcx>, +#[tracing::instrument(level = "debug", skip(wfcx, span, hir_decl))] +fn check_fn_or_method<'tcx>( + wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, sig: ty::PolyFnSig<'tcx>, hir_decl: &hir::FnDecl<'_>, def_id: LocalDefId, implied_bounds: &mut FxHashSet>, ) { - let sig = fcx.tcx.liberate_late_bound_regions(def_id.to_def_id(), sig); + let tcx = wfcx.tcx(); + let sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig); // Normalize the input and output types one at a time, using a different // `WellFormedLoc` for each. We cannot call `normalize_associated_types` @@ -1478,70 +1479,61 @@ fn check_fn_or_method<'fcx, 'tcx>( // for each type, preventing the HIR wf check from generating // a nice error message. let ty::FnSig { mut inputs_and_output, c_variadic, unsafety, abi } = sig; - inputs_and_output = - fcx.tcx.mk_type_list(inputs_and_output.iter().enumerate().map(|(i, ty)| { - fcx.normalize_associated_types_in_wf( - span, - ty, - WellFormedLoc::Param { - function: def_id, - // Note that the `param_idx` of the output type is - // one greater than the index of the last input type. - param_idx: i.try_into().unwrap(), - }, - ) - })); + inputs_and_output = tcx.mk_type_list(inputs_and_output.iter().enumerate().map(|(i, ty)| { + wfcx.normalize( + span, + Some(WellFormedLoc::Param { + function: def_id, + // Note that the `param_idx` of the output type is + // one greater than the index of the last input type. + param_idx: i.try_into().unwrap(), + }), + ty, + ) + })); // Manually call `normalize_associated_types_in` on the other types // in `FnSig`. This ensures that if the types of these fields // ever change to include projections, we will start normalizing // them automatically. let sig = ty::FnSig { inputs_and_output, - c_variadic: fcx.normalize_associated_types_in(span, c_variadic), - unsafety: fcx.normalize_associated_types_in(span, unsafety), - abi: fcx.normalize_associated_types_in(span, abi), + c_variadic: wfcx.normalize(span, None, c_variadic), + unsafety: wfcx.normalize(span, None, unsafety), + abi: wfcx.normalize(span, None, abi), }; for (i, (&input_ty, ty)) in iter::zip(sig.inputs(), hir_decl.inputs).enumerate() { - fcx.register_wf_obligation( - input_ty.into(), + wfcx.register_wf_obligation( ty.span, - ObligationCauseCode::WellFormed(Some(WellFormedLoc::Param { - function: def_id, - param_idx: i.try_into().unwrap(), - })), + Some(WellFormedLoc::Param { function: def_id, param_idx: i.try_into().unwrap() }), + input_ty.into(), ); } implied_bounds.extend(sig.inputs()); - fcx.register_wf_obligation( - sig.output().into(), - hir_decl.output.span(), - ObligationCauseCode::ReturnType, - ); + wfcx.register_wf_obligation(hir_decl.output.span(), None, sig.output().into()); // FIXME(#27579) return types should not be implied bounds implied_bounds.insert(sig.output()); debug!(?implied_bounds); - check_where_clauses(fcx, span, def_id, Some((sig.output(), hir_decl.output.span()))); + check_where_clauses(wfcx, span, def_id); } const HELP_FOR_SELF_TYPE: &str = "consider changing to `self`, `&self`, `&mut self`, `self: Box`, \ `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one \ of the previous types except `Self`)"; -#[tracing::instrument(level = "debug", skip(fcx))] -fn check_method_receiver<'fcx, 'tcx>( - fcx: &FnCtxt<'fcx, 'tcx>, +#[tracing::instrument(level = "debug", skip(wfcx))] +fn check_method_receiver<'tcx>( + wfcx: &WfCheckingCtxt<'_, 'tcx>, fn_sig: &hir::FnSig<'_>, method: &ty::AssocItem, self_ty: Ty<'tcx>, ) { - // Check that the method has a valid receiver type, given the type `Self`. - debug!("check_method_receiver({:?}, self_ty={:?})", method, self_ty); + let tcx = wfcx.tcx(); if !method.fn_has_self_parameter { return; @@ -1549,28 +1541,28 @@ fn check_method_receiver<'fcx, 'tcx>( let span = fn_sig.decl.inputs[0].span; - let sig = fcx.tcx.fn_sig(method.def_id); - let sig = fcx.tcx.liberate_late_bound_regions(method.def_id, sig); - let sig = fcx.normalize_associated_types_in(span, sig); + let sig = tcx.fn_sig(method.def_id); + let sig = tcx.liberate_late_bound_regions(method.def_id, sig); + let sig = wfcx.normalize(span, None, sig); debug!("check_method_receiver: sig={:?}", sig); - let self_ty = fcx.normalize_associated_types_in(span, self_ty); + let self_ty = wfcx.normalize(span, None, self_ty); let receiver_ty = sig.inputs()[0]; - let receiver_ty = fcx.normalize_associated_types_in(span, receiver_ty); + let receiver_ty = wfcx.normalize(span, None, receiver_ty); - if fcx.tcx.features().arbitrary_self_types { - if !receiver_is_valid(fcx, span, receiver_ty, self_ty, true) { + if tcx.features().arbitrary_self_types { + if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) { // Report error; `arbitrary_self_types` was enabled. - e0307(fcx, span, receiver_ty); + e0307(tcx, span, receiver_ty); } } else { - if !receiver_is_valid(fcx, span, receiver_ty, self_ty, false) { - if receiver_is_valid(fcx, span, receiver_ty, self_ty, true) { + if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, false) { + if receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) { // Report error; would have worked with `arbitrary_self_types`. feature_err( - &fcx.tcx.sess.parse_sess, + &tcx.sess.parse_sess, sym::arbitrary_self_types, span, &format!( @@ -1582,15 +1574,15 @@ fn check_method_receiver<'fcx, 'tcx>( .emit(); } else { // Report error; would not have worked with `arbitrary_self_types`. - e0307(fcx, span, receiver_ty); + e0307(tcx, span, receiver_ty); } } } } -fn e0307<'tcx>(fcx: &FnCtxt<'_, 'tcx>, span: Span, receiver_ty: Ty<'_>) { +fn e0307<'tcx>(tcx: TyCtxt<'tcx>, span: Span, receiver_ty: Ty<'_>) { struct_span_err!( - fcx.tcx.sess.diagnostic(), + tcx.sess.diagnostic(), span, E0307, "invalid `self` parameter type: {receiver_ty}" @@ -1609,26 +1601,30 @@ fn e0307<'tcx>(fcx: &FnCtxt<'_, 'tcx>, span: Span, receiver_ty: Ty<'_>) { /// N.B., there are cases this function returns `true` but causes an error to be emitted, /// particularly when `receiver_ty` derefs to a type that is the same as `self_ty` but has the /// wrong lifetime. Be careful of this if you are calling this function speculatively. -fn receiver_is_valid<'fcx, 'tcx>( - fcx: &FnCtxt<'fcx, 'tcx>, +fn receiver_is_valid<'tcx>( + wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, receiver_ty: Ty<'tcx>, self_ty: Ty<'tcx>, arbitrary_self_types_enabled: bool, ) -> bool { - let cause = fcx.cause(span, traits::ObligationCauseCode::MethodReceiver); + let infcx = wfcx.infcx; + let tcx = wfcx.tcx(); + let cause = + ObligationCause::new(span, wfcx.body_id, traits::ObligationCauseCode::MethodReceiver); - let can_eq_self = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok(); + let can_eq_self = |ty| infcx.can_eq(wfcx.param_env, self_ty, ty).is_ok(); // `self: Self` is always valid. if can_eq_self(receiver_ty) { - if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, self_ty, receiver_ty) { - err.emit(); + if let Err(err) = wfcx.equate_types(&cause, wfcx.param_env, self_ty, receiver_ty) { + infcx.report_mismatched_types(&cause, self_ty, receiver_ty, err).emit(); } return true; } - let mut autoderef = fcx.autoderef(span, receiver_ty); + let mut autoderef = + Autoderef::new(infcx, wfcx.param_env, wfcx.body_id, span, receiver_ty, span); // The `arbitrary_self_types` feature allows raw pointer receivers like `self: *const Self`. if arbitrary_self_types_enabled { @@ -1638,7 +1634,7 @@ fn receiver_is_valid<'fcx, 'tcx>( // The first type is `receiver_ty`, which we know its not equal to `self_ty`; skip it. autoderef.next(); - let receiver_trait_def_id = fcx.tcx.require_lang_item(LangItem::Receiver, None); + let receiver_trait_def_id = tcx.require_lang_item(LangItem::Receiver, None); // Keep dereferencing `receiver_ty` until we get to `self_ty`. loop { @@ -1649,12 +1645,12 @@ fn receiver_is_valid<'fcx, 'tcx>( ); if can_eq_self(potential_self_ty) { - fcx.register_predicates(autoderef.into_obligations()); + wfcx.register_obligations(autoderef.into_obligations()); - if let Some(mut err) = - fcx.demand_eqtype_with_origin(&cause, self_ty, potential_self_ty) + if let Err(err) = + wfcx.equate_types(&cause, wfcx.param_env, self_ty, potential_self_ty) { - err.emit(); + infcx.report_mismatched_types(&cause, self_ty, potential_self_ty, err).emit(); } break; @@ -1663,7 +1659,7 @@ fn receiver_is_valid<'fcx, 'tcx>( // deref chain implement `receiver` if !arbitrary_self_types_enabled && !receiver_is_implemented( - fcx, + wfcx, receiver_trait_def_id, cause.clone(), potential_self_ty, @@ -1682,7 +1678,7 @@ fn receiver_is_valid<'fcx, 'tcx>( // Without `feature(arbitrary_self_types)`, we require that `receiver_ty` implements `Receiver`. if !arbitrary_self_types_enabled - && !receiver_is_implemented(fcx, receiver_trait_def_id, cause.clone(), receiver_ty) + && !receiver_is_implemented(wfcx, receiver_trait_def_id, cause.clone(), receiver_ty) { return false; } @@ -1691,23 +1687,21 @@ fn receiver_is_valid<'fcx, 'tcx>( } fn receiver_is_implemented<'tcx>( - fcx: &FnCtxt<'_, 'tcx>, + wfcx: &WfCheckingCtxt<'_, 'tcx>, receiver_trait_def_id: DefId, cause: ObligationCause<'tcx>, receiver_ty: Ty<'tcx>, ) -> bool { + let tcx = wfcx.tcx(); let trait_ref = ty::Binder::dummy(ty::TraitRef { def_id: receiver_trait_def_id, - substs: fcx.tcx.mk_substs_trait(receiver_ty, &[]), + substs: tcx.mk_substs_trait(receiver_ty, &[]), }); - let obligation = traits::Obligation::new( - cause, - fcx.param_env, - trait_ref.without_const().to_predicate(fcx.tcx), - ); + let obligation = + traits::Obligation::new(cause, wfcx.param_env, trait_ref.without_const().to_predicate(tcx)); - if fcx.predicate_must_hold_modulo_regions(&obligation) { + if wfcx.infcx.predicate_must_hold_modulo_regions(&obligation) { true } else { debug!( @@ -1809,55 +1803,56 @@ fn report_bivariance( err.emit() } -/// Feature gates RFC 2056 -- trivial bounds, checking for global bounds that -/// aren't true. -fn check_false_global_bounds(fcx: &FnCtxt<'_, '_>, mut span: Span, id: hir::HirId) { - let empty_env = ty::ParamEnv::empty(); - - let def_id = fcx.tcx.hir().local_def_id(id); - let predicates_with_span = - fcx.tcx.predicates_of(def_id).predicates.iter().map(|(p, span)| (*p, *span)); - // Check elaborated bounds. - let implied_obligations = traits::elaborate_predicates_with_span(fcx.tcx, predicates_with_span); - - for obligation in implied_obligations { - // We lower empty bounds like `Vec:` as - // `WellFormed(Vec)`, which will later get checked by - // regular WF checking - if let ty::PredicateKind::WellFormed(..) = obligation.predicate.kind().skip_binder() { - continue; - } - let pred = obligation.predicate; - // Match the existing behavior. - if pred.is_global() && !pred.has_late_bound_regions() { - let pred = fcx.normalize_associated_types_in(span, pred); - let hir_node = fcx.tcx.hir().find(id); +impl<'tcx> WfCheckingCtxt<'_, 'tcx> { + /// Feature gates RFC 2056 -- trivial bounds, checking for global bounds that + /// aren't true. + fn check_false_global_bounds(&mut self) { + let tcx = self.ocx.infcx.tcx; + let mut span = self.span; + let empty_env = ty::ParamEnv::empty(); + + let def_id = tcx.hir().local_def_id(self.body_id); + let predicates_with_span = tcx.predicates_of(def_id).predicates.iter().copied(); + // Check elaborated bounds. + let implied_obligations = traits::elaborate_predicates_with_span(tcx, predicates_with_span); + + for obligation in implied_obligations { + // We lower empty bounds like `Vec:` as + // `WellFormed(Vec)`, which will later get checked by + // regular WF checking + if let ty::PredicateKind::WellFormed(..) = obligation.predicate.kind().skip_binder() { + continue; + } + let pred = obligation.predicate; + // Match the existing behavior. + if pred.is_global() && !pred.has_late_bound_regions() { + let pred = self.normalize(span, None, pred); + let hir_node = tcx.hir().find(self.body_id); - // only use the span of the predicate clause (#90869) + // only use the span of the predicate clause (#90869) - if let Some(hir::Generics { predicates, .. }) = - hir_node.and_then(|node| node.generics()) - { - let obligation_span = obligation.cause.span(); - - span = predicates - .iter() - // There seems to be no better way to find out which predicate we are in - .find(|pred| pred.span().contains(obligation_span)) - .map(|pred| pred.span()) - .unwrap_or(obligation_span); - } + if let Some(hir::Generics { predicates, .. }) = + hir_node.and_then(|node| node.generics()) + { + let obligation_span = obligation.cause.span(); + + span = predicates + .iter() + // There seems to be no better way to find out which predicate we are in + .find(|pred| pred.span().contains(obligation_span)) + .map(|pred| pred.span()) + .unwrap_or(obligation_span); + } - let obligation = traits::Obligation::new( - traits::ObligationCause::new(span, id, traits::TrivialBound), - empty_env, - pred, - ); - fcx.register_predicate(obligation); + let obligation = traits::Obligation::new( + traits::ObligationCause::new(span, self.body_id, traits::TrivialBound), + empty_env, + pred, + ); + self.ocx.register_obligation(obligation); + } } } - - fcx.select_all_obligations_or_error(); } fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalDefId) { @@ -1887,17 +1882,16 @@ struct AdtField<'tcx> { span: Span, } -impl<'a, 'tcx> FnCtxt<'a, 'tcx> { +impl<'a, 'tcx> WfCheckingCtxt<'a, 'tcx> { // FIXME(eddyb) replace this with getting fields through `ty::AdtDef`. fn non_enum_variant(&self, struct_def: &hir::VariantData<'_>) -> AdtVariant<'tcx> { let fields = struct_def .fields() .iter() .map(|field| { - let def_id = self.tcx.hir().local_def_id(field.hir_id); - let field_ty = self.tcx.type_of(def_id); - let field_ty = self.normalize_associated_types_in(field.ty.span, field_ty); - let field_ty = self.resolve_vars_if_possible(field_ty); + let def_id = self.tcx().hir().local_def_id(field.hir_id); + let field_ty = self.tcx().type_of(def_id); + let field_ty = self.normalize(field.ty.span, None, field_ty); debug!("non_enum_variant: type of field {:?} is {:?}", field, field_ty); AdtField { ty: field_ty, span: field.ty.span, def_id } }) @@ -1913,32 +1907,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fields: self.non_enum_variant(&variant.data).fields, explicit_discr: variant .disr_expr - .map(|explicit_discr| self.tcx.hir().local_def_id(explicit_discr.hir_id)), + .map(|explicit_discr| self.tcx().hir().local_def_id(explicit_discr.hir_id)), }) .collect() } +} - pub(super) fn impl_implied_bounds( - &self, - impl_def_id: DefId, - span: Span, - ) -> FxHashSet> { - match self.tcx.impl_trait_ref(impl_def_id) { +pub(super) fn impl_implied_bounds<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + impl_def_id: LocalDefId, + span: Span, +) -> FxHashSet> { + // We completely ignore any obligations caused by normalizing the types + // we assume to be well formed. Considering that the user of the implied + // bounds will also normalize them, we leave it to them to emit errors + // which should result in better causes and spans. + tcx.infer_ctxt().enter(|infcx| { + let cause = ObligationCause::misc(span, tcx.hir().local_def_id_to_hir_id(impl_def_id)); + match tcx.impl_trait_ref(impl_def_id) { Some(trait_ref) => { // Trait impl: take implied bounds from all types that // appear in the trait reference. - let trait_ref = self.normalize_associated_types_in(span, trait_ref); - trait_ref.substs.types().collect() + match infcx.at(&cause, param_env).normalize(trait_ref) { + Ok(Normalized { value, obligations: _ }) => value.substs.types().collect(), + Err(NoSolution) => FxHashSet::default(), + } } None => { // Inherent impl: take implied bounds from the `self` type. - let self_ty = self.tcx.type_of(impl_def_id); - let self_ty = self.normalize_associated_types_in(span, self_ty); - FxHashSet::from_iter([self_ty]) + let self_ty = tcx.type_of(impl_def_id); + match infcx.at(&cause, param_env).normalize(self_ty) { + Ok(Normalized { value, obligations: _ }) => FxHashSet::from_iter([value]), + Err(NoSolution) => FxHashSet::default(), + } } } - } + }) } fn error_392( diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs index d532050d05035..a92c37ff143b4 100644 --- a/compiler/rustc_typeck/src/coherence/builtin.rs +++ b/compiler/rustc_typeck/src/coherence/builtin.rs @@ -349,7 +349,7 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did: // Finally, resolve all regions. let outlives_env = OutlivesEnvironment::new(param_env); - infcx.resolve_regions_and_report_errors(&outlives_env); + infcx.resolve_regions_and_report_errors(impl_did, &outlives_env); } } _ => { @@ -606,7 +606,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn // Finally, resolve all regions. let outlives_env = OutlivesEnvironment::new(param_env); - infcx.resolve_regions_and_report_errors(&outlives_env); + infcx.resolve_regions_and_report_errors(impl_did, &outlives_env); CoerceUnsizedInfo { custom_kind: kind } }) diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs index c46b825f4578d..6ece955de643c 100644 --- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs @@ -150,7 +150,7 @@ fn get_impl_substs<'tcx>( // Conservatively use an empty `ParamEnv`. let outlives_env = OutlivesEnvironment::new(ty::ParamEnv::empty()); - infcx.resolve_regions_and_report_errors(&outlives_env); + infcx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env); let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else { let span = tcx.def_span(impl1_def_id); tcx.sess.emit_err(SubstsOnOverriddenImpl { span }); diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.stderr b/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.stderr index 26eecf6a21d3d..95cf4fb168f1e 100644 --- a/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.stderr +++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.stderr @@ -2,10 +2,12 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/implied-bounds-unnorm-associated-type-3.rs:19:5 | LL | fn zero_copy_from<'b>(cart: &'b [T]) -> &'b [T] { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `[T]` will meet its required lifetime bounds | - = help: consider adding an explicit lifetime bound `T: 'static`... - = note: ...so that the type `[T]` will meet its required lifetime bounds +help: consider adding an explicit lifetime bound... + | +LL | impl ZeroCopyFrom<[T]> for &'static [T] { + | +++++++++ error: aborting due to previous error diff --git a/src/test/ui/regions/regions-normalize-in-where-clause-list.rs b/src/test/ui/regions/regions-normalize-in-where-clause-list.rs index 9912e88c2ec57..389f82e794be7 100644 --- a/src/test/ui/regions/regions-normalize-in-where-clause-list.rs +++ b/src/test/ui/regions/regions-normalize-in-where-clause-list.rs @@ -23,7 +23,6 @@ where // Here we get an error: we need `'a: 'b`. fn bar<'a, 'b>() //~^ ERROR cannot infer -//~| ERROR cannot infer where <() as Project<'a, 'b>>::Item: Eq, { diff --git a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr index 2bb58b5ec2df5..5672837290cb1 100644 --- a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr +++ b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr @@ -1,35 +1,3 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements - --> $DIR/regions-normalize-in-where-clause-list.rs:24:1 - | -LL | / fn bar<'a, 'b>() -LL | | -LL | | -LL | | where -LL | | <() as Project<'a, 'b>>::Item: Eq, - | |______________________________________^ - | -note: first, the lifetime cannot outlive the lifetime `'a` as defined here... - --> $DIR/regions-normalize-in-where-clause-list.rs:24:8 - | -LL | fn bar<'a, 'b>() - | ^^ -note: ...but the lifetime must also be valid for the lifetime `'b` as defined here... - --> $DIR/regions-normalize-in-where-clause-list.rs:24:12 - | -LL | fn bar<'a, 'b>() - | ^^ -note: ...so that the types are compatible - --> $DIR/regions-normalize-in-where-clause-list.rs:24:1 - | -LL | / fn bar<'a, 'b>() -LL | | -LL | | -LL | | where -LL | | <() as Project<'a, 'b>>::Item: Eq, - | |______________________________________^ - = note: expected `Project<'a, 'b>` - found `Project<'_, '_>` - error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements --> $DIR/regions-normalize-in-where-clause-list.rs:24:4 | @@ -54,6 +22,6 @@ LL | fn bar<'a, 'b>() = note: expected `Project<'a, 'b>` found `Project<'_, '_>` -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/specialization/min_specialization/issue-79224.stderr b/src/test/ui/specialization/min_specialization/issue-79224.stderr index 44c6ec1426b90..cfb9007c7a28c 100644 --- a/src/test/ui/specialization/min_specialization/issue-79224.stderr +++ b/src/test/ui/specialization/min_specialization/issue-79224.stderr @@ -11,12 +11,10 @@ LL | impl Display for Cow<'_, B> { | +++++++++++++++++++ error[E0277]: the trait bound `B: Clone` is not satisfied - --> $DIR/issue-79224.rs:19:5 + --> $DIR/issue-79224.rs:19:12 | -LL | / fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -LL | | write!(f, "foo") -LL | | } - | |_____^ the trait `Clone` is not implemented for `B` +LL | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + | ^^^^^ the trait `Clone` is not implemented for `B` | = note: required because of the requirements on the impl of `ToOwned` for `B` help: consider further restricting this bound