diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs index 64726eacca74a..b9fa46ea883ff 100644 --- a/compiler/rustc_borrowck/src/consumers.rs +++ b/compiler/rustc_borrowck/src/consumers.rs @@ -2,7 +2,6 @@ use rustc_hir::def_id::LocalDefId; use rustc_index::{IndexSlice, IndexVec}; -use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::{Body, Promoted}; use rustc_middle::ty::TyCtxt; use std::rc::Rc; @@ -105,8 +104,7 @@ pub fn get_body_with_borrowck_facts( options: ConsumerOptions, ) -> BodyWithBorrowckFacts<'_> { let (input_body, promoted) = tcx.mir_promoted(def); - let infcx = tcx.infer_ctxt().with_opaque_type_inference(def).build(); let input_body: &Body<'_> = &input_body.borrow(); let promoted: &IndexSlice<_, _> = &promoted.borrow(); - *super::do_mir_borrowck(&infcx, input_body, promoted, Some(options)).1.unwrap() + *super::do_mir_borrowck(tcx, input_body, promoted, Some(options)).1.unwrap() } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 47c83e0bb2bb6..abe57e26af461 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -23,9 +23,8 @@ use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::{BitSet, ChunkedBitSet}; use rustc_index::{IndexSlice, IndexVec}; -use rustc_infer::infer::{ - InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt, -}; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin}; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::*; use rustc_middle::query::Providers; @@ -123,9 +122,8 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> &BorrowCheckResult<'_> { return tcx.arena.alloc(result); } - let infcx = tcx.infer_ctxt().with_opaque_type_inference(def).build(); let promoted: &IndexSlice<_, _> = &promoted.borrow(); - let opt_closure_req = do_mir_borrowck(&infcx, input_body, promoted, None).0; + let opt_closure_req = do_mir_borrowck(tcx, input_body, promoted, None).0; debug!("mir_borrowck done"); tcx.arena.alloc(opt_closure_req) @@ -136,18 +134,15 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> &BorrowCheckResult<'_> { /// Use `consumer_options: None` for the default behavior of returning /// [`BorrowCheckResult`] only. Otherwise, return [`BodyWithBorrowckFacts`] according /// to the given [`ConsumerOptions`]. -#[instrument(skip(infcx, input_body, input_promoted), fields(id=?input_body.source.def_id()), level = "debug")] +#[instrument(skip(tcx, input_body, input_promoted), fields(id=?input_body.source.def_id()), level = "debug")] fn do_mir_borrowck<'tcx>( - infcx: &InferCtxt<'tcx>, + tcx: TyCtxt<'tcx>, input_body: &Body<'tcx>, input_promoted: &IndexSlice>, consumer_options: Option, ) -> (BorrowCheckResult<'tcx>, Option>>) { let def = input_body.source.def_id().expect_local(); - debug!(?def); - - let tcx = infcx.tcx; - let infcx = BorrowckInferCtxt::new(infcx); + let infcx = BorrowckInferCtxt::new(tcx, def); let param_env = tcx.param_env(def); let mut local_names = IndexVec::from_elem(None, &input_body.local_decls); @@ -187,6 +182,12 @@ fn do_mir_borrowck<'tcx>( nll::replace_regions_in_mir(&infcx, param_env, &mut body_owned, &mut promoted); let body = &body_owned; // no further changes + // FIXME(-Znext-solver): A bit dubious that we're only registering + // predefined opaques in the typeck root. + if infcx.next_trait_solver() && !infcx.tcx.is_typeck_child(body.source.def_id()) { + infcx.register_predefined_opaques_for_next_solver(def); + } + let location_table = LocationTable::new(body); let move_data = MoveData::gather_moves(body, tcx, param_env, |_| true); @@ -440,13 +441,14 @@ fn do_mir_borrowck<'tcx>( (result, body_with_facts) } -pub struct BorrowckInferCtxt<'cx, 'tcx> { - pub(crate) infcx: &'cx InferCtxt<'tcx>, +pub struct BorrowckInferCtxt<'tcx> { + pub(crate) infcx: InferCtxt<'tcx>, pub(crate) reg_var_to_origin: RefCell>, } -impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> { - pub(crate) fn new(infcx: &'cx InferCtxt<'tcx>) -> Self { +impl<'tcx> BorrowckInferCtxt<'tcx> { + pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { + let infcx = tcx.infer_ctxt().with_opaque_type_inference(def_id).build(); BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()) } } @@ -492,18 +494,40 @@ impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> { next_region } + + /// With the new solver we prepopulate the opaque type storage during + /// MIR borrowck with the hidden types from HIR typeck. This is necessary + /// to avoid ambiguities as earlier goals can rely on the hidden type + /// of an opaque which is only constrained by a later goal. + fn register_predefined_opaques_for_next_solver(&self, def_id: LocalDefId) { + let tcx = self.tcx; + // OK to use the identity arguments for each opaque type key, since + // we remap opaques from HIR typeck back to their definition params. + for data in tcx.typeck(def_id).concrete_opaque_types.iter().map(|(k, v)| (*k, *v)) { + // HIR typeck did not infer the regions of the opaque, so we instantiate + // them with fresh inference variables. + let (key, hidden_ty) = tcx.fold_regions(data, |_, _| { + self.next_nll_region_var_in_universe( + NllRegionVariableOrigin::Existential { from_forall: false }, + ty::UniverseIndex::ROOT, + ) + }); + + self.inject_new_hidden_type_unchecked(key, hidden_ty); + } + } } -impl<'cx, 'tcx> Deref for BorrowckInferCtxt<'cx, 'tcx> { +impl<'tcx> Deref for BorrowckInferCtxt<'tcx> { type Target = InferCtxt<'tcx>; - fn deref(&self) -> &'cx Self::Target { - self.infcx + fn deref(&self) -> &Self::Target { + &self.infcx } } struct MirBorrowckCtxt<'cx, 'tcx> { - infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>, + infcx: &'cx BorrowckInferCtxt<'tcx>, param_env: ParamEnv<'tcx>, body: &'cx Body<'tcx>, move_data: &'cx MoveData<'tcx>, diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 4aa32a61f7c36..49f50babdcb96 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -51,7 +51,7 @@ pub(crate) struct NllOutput<'tcx> { /// `compute_regions`. #[instrument(skip(infcx, param_env, body, promoted), level = "debug")] pub(crate) fn replace_regions_in_mir<'tcx>( - infcx: &BorrowckInferCtxt<'_, 'tcx>, + infcx: &BorrowckInferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body: &mut Body<'tcx>, promoted: &mut IndexSlice>, @@ -75,7 +75,7 @@ pub(crate) fn replace_regions_in_mir<'tcx>( /// /// This may result in errors being reported. pub(crate) fn compute_regions<'cx, 'tcx>( - infcx: &BorrowckInferCtxt<'_, 'tcx>, + infcx: &BorrowckInferCtxt<'tcx>, universal_regions: UniversalRegions<'tcx>, body: &Body<'tcx>, promoted: &IndexSlice>, @@ -202,7 +202,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>( } pub(super) fn dump_mir_results<'tcx>( - infcx: &BorrowckInferCtxt<'_, 'tcx>, + infcx: &BorrowckInferCtxt<'tcx>, body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option>, @@ -254,7 +254,7 @@ pub(super) fn dump_mir_results<'tcx>( #[allow(rustc::diagnostic_outside_of_impl)] #[allow(rustc::untranslatable_diagnostic)] pub(super) fn dump_annotation<'tcx>( - infcx: &BorrowckInferCtxt<'_, 'tcx>, + infcx: &BorrowckInferCtxt<'tcx>, body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option>, diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 78465ad7975d9..54574446b559a 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -250,10 +250,7 @@ pub enum ExtraConstraintInfo { } #[instrument(skip(infcx, sccs), level = "debug")] -fn sccs_info<'cx, 'tcx>( - infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>, - sccs: Rc>, -) { +fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: Rc>) { use crate::renumber::RegionCtxt; let var_to_origin = infcx.reg_var_to_origin.borrow(); @@ -322,8 +319,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// /// The `outlives_constraints` and `type_tests` are an initial set /// of constraints produced by the MIR type check. - pub(crate) fn new<'cx>( - _infcx: &BorrowckInferCtxt<'cx, 'tcx>, + pub(crate) fn new( + _infcx: &BorrowckInferCtxt<'tcx>, var_infos: VarInfos, universal_regions: Rc>, placeholder_indices: Rc, diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index dca8df3280028..f5757bcaa1d11 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -11,7 +11,7 @@ use rustc_span::Symbol; /// inference variables, returning the number of variables created. #[instrument(skip(infcx, body, promoted), level = "debug")] pub fn renumber_mir<'tcx>( - infcx: &BorrowckInferCtxt<'_, 'tcx>, + infcx: &BorrowckInferCtxt<'tcx>, body: &mut Body<'tcx>, promoted: &mut IndexSlice>, ) { @@ -57,7 +57,7 @@ impl RegionCtxt { } struct RegionRenumberer<'a, 'tcx> { - infcx: &'a BorrowckInferCtxt<'a, 'tcx>, + infcx: &'a BorrowckInferCtxt<'tcx>, } impl<'a, 'tcx> RegionRenumberer<'a, 'tcx> { diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index b67c5d8581839..13acc672defb8 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -24,7 +24,6 @@ use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::traits::query::NoSolution; -use rustc_middle::traits::ObligationCause; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::visit::TypeVisitableExt; @@ -122,7 +121,7 @@ mod relate_tys; /// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis /// - `elements` -- MIR region map pub(crate) fn type_check<'mir, 'tcx>( - infcx: &BorrowckInferCtxt<'_, 'tcx>, + infcx: &BorrowckInferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, promoted: &IndexSlice>, @@ -865,7 +864,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { /// way, it accrues region constraints -- these can later be used by /// NLL region checking. struct TypeChecker<'a, 'tcx> { - infcx: &'a BorrowckInferCtxt<'a, 'tcx>, + infcx: &'a BorrowckInferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, last_span: Span, body: &'a Body<'tcx>, @@ -1020,7 +1019,7 @@ impl Locations { impl<'a, 'tcx> TypeChecker<'a, 'tcx> { fn new( - infcx: &'a BorrowckInferCtxt<'a, 'tcx>, + infcx: &'a BorrowckInferCtxt<'tcx>, body: &'a Body<'tcx>, param_env: ty::ParamEnv<'tcx>, region_bound_pairs: &'a RegionBoundPairs<'tcx>, @@ -1028,7 +1027,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { implicit_region_bound: ty::Region<'tcx>, borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, ) -> Self { - let mut checker = Self { + Self { infcx, last_span: body.span, body, @@ -1039,74 +1038,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { implicit_region_bound, borrowck_context, reported_errors: Default::default(), - }; - - // FIXME(-Znext-solver): A bit dubious that we're only registering - // predefined opaques in the typeck root. - if infcx.next_trait_solver() && !infcx.tcx.is_typeck_child(body.source.def_id()) { - checker.register_predefined_opaques_for_next_solver(); - } - - checker - } - - pub(super) fn register_predefined_opaques_for_next_solver(&mut self) { - // OK to use the identity arguments for each opaque type key, since - // we remap opaques from HIR typeck back to their definition params. - let opaques: Vec<_> = self - .infcx - .tcx - .typeck(self.body.source.def_id().expect_local()) - .concrete_opaque_types - .iter() - .map(|(k, v)| (*k, *v)) - .collect(); - - let renumbered_opaques = self.infcx.tcx.fold_regions(opaques, |_, _| { - self.infcx.next_nll_region_var_in_universe( - NllRegionVariableOrigin::Existential { from_forall: false }, - ty::UniverseIndex::ROOT, - ) - }); - - let param_env = self.param_env; - let result = self.fully_perform_op( - Locations::All(self.body.span), - ConstraintCategory::OpaqueType, - CustomTypeOp::new( - |ocx| { - let mut obligations = Vec::new(); - for (opaque_type_key, hidden_ty) in renumbered_opaques { - let cause = ObligationCause::dummy(); - ocx.infcx.insert_hidden_type( - opaque_type_key, - &cause, - param_env, - hidden_ty.ty, - &mut obligations, - )?; - - ocx.infcx.add_item_bounds_for_hidden_type( - opaque_type_key.def_id.to_def_id(), - opaque_type_key.args, - cause, - param_env, - hidden_ty.ty, - &mut obligations, - ); - } - - ocx.register_obligations(obligations); - Ok(()) - }, - "register pre-defined opaques", - ), - ); - - if result.is_err() { - self.infcx - .dcx() - .span_bug(self.body.span, "failed re-defining predefined opaques in mir typeck"); } } diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 070238fc37882..f8123535e2d0a 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -240,7 +240,7 @@ impl<'tcx> UniversalRegions<'tcx> { /// signature. This will also compute the relationships that are /// known between those regions. pub fn new( - infcx: &BorrowckInferCtxt<'_, 'tcx>, + infcx: &BorrowckInferCtxt<'tcx>, mir_def: LocalDefId, param_env: ty::ParamEnv<'tcx>, ) -> Self { @@ -411,7 +411,7 @@ impl<'tcx> UniversalRegions<'tcx> { } struct UniversalRegionsBuilder<'cx, 'tcx> { - infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>, + infcx: &'cx BorrowckInferCtxt<'tcx>, mir_def: LocalDefId, param_env: ty::ParamEnv<'tcx>, } @@ -796,7 +796,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { } #[extension(trait InferCtxtExt<'tcx>)] -impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> { +impl<'tcx> BorrowckInferCtxt<'tcx> { #[instrument(skip(self), level = "debug")] fn replace_free_regions_with_nll_infer_vars( &self, diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index 94a546f87eee9..b7ee860cf07da 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -485,6 +485,19 @@ impl<'tcx> InferCtxt<'tcx> { Ok(InferOk { value: (), obligations }) } + /// Insert a hidden type into the opaque type storage, making sure + /// it hasn't previously been defined. This does not emit any + /// constraints and it's the responsibility of the caller to make + /// sure that the item bounds of the opaque are checked. + pub fn inject_new_hidden_type_unchecked( + &self, + opaque_type_key: OpaqueTypeKey<'tcx>, + hidden_ty: OpaqueHiddenType<'tcx>, + ) { + let prev = self.inner.borrow_mut().opaque_types().register(opaque_type_key, hidden_ty); + assert_eq!(prev, None); + } + /// Insert a hidden type into the opaque type storage, equating it /// with any previous entries if necessary. /// diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs index cddf9d5f874a3..2ddcb8aab2530 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect.rs @@ -123,6 +123,8 @@ pub enum ProbeStep<'tcx> { /// used whenever there are multiple candidates to prove the /// current goalby . NestedProbe(Probe<'tcx>), + /// A trait goal was satisfied by an impl candidate. + RecordImplArgs { impl_args: CanonicalState<'tcx, ty::GenericArgsRef<'tcx>> }, /// A call to `EvalCtxt::evaluate_added_goals_make_canonical_response` with /// `Certainty` was made. This is the certainty passed in, so it's not unified /// with the certainty of the `try_evaluate_added_goals` that is done within; diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs index 11aa0e10931cb..e652f0586c4ea 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs @@ -136,6 +136,9 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> { ProbeStep::MakeCanonicalResponse { shallow_certainty } => { writeln!(this.f, "EVALUATE GOALS AND MAKE RESPONSE: {shallow_certainty:?}")? } + ProbeStep::RecordImplArgs { impl_args } => { + writeln!(this.f, "RECORDED IMPL ARGS: {impl_args:?}")? + } } } Ok(()) diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index d6bf2b596ef1e..5f73432750d10 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -236,7 +236,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { normalization_nested_goals, } = external_constraints.deref(); self.register_region_constraints(region_constraints); - self.register_new_opaque_types(param_env, opaque_types); + self.register_new_opaque_types(opaque_types); (normalization_nested_goals.clone(), certainty) } @@ -368,13 +368,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { assert!(region_constraints.member_constraints.is_empty()); } - fn register_new_opaque_types( - &mut self, - param_env: ty::ParamEnv<'tcx>, - opaque_types: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)], - ) { + fn register_new_opaque_types(&mut self, opaque_types: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)]) { for &(key, ty) in opaque_types { - self.insert_hidden_type(key, param_env, ty).unwrap(); + let hidden_ty = ty::OpaqueHiddenType { ty, span: DUMMY_SP }; + self.infcx.inject_new_hidden_type_unchecked(key, hidden_ty); } } } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index 773babde0d7b3..55ade5e3e2f9f 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -248,8 +248,8 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { }; for &(key, ty) in &input.predefined_opaques_in_body.opaque_types { - ecx.insert_hidden_type(key, input.goal.param_env, ty) - .expect("failed to prepopulate opaque types"); + let hidden_ty = ty::OpaqueHiddenType { ty, span: DUMMY_SP }; + ecx.infcx.inject_new_hidden_type_unchecked(key, hidden_ty); } if !ecx.nested_goals.is_empty() { @@ -587,6 +587,11 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { Ok(unchanged_certainty) } + + /// Record impl args in the proof tree for later access by `InspectCandidate`. + pub(crate) fn record_impl_args(&mut self, impl_args: ty::GenericArgsRef<'tcx>) { + self.inspect.record_impl_args(self.infcx, self.max_input_universe, impl_args) + } } impl<'tcx> EvalCtxt<'_, 'tcx> { diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs index 16fe045b82de7..f586a74258d7e 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs @@ -1,12 +1,11 @@ use std::ops::ControlFlow; -use rustc_hir::def_id::DefId; -use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; +use rustc_infer::infer::InferCtxt; use rustc_infer::traits::solve::inspect::ProbeKind; use rustc_infer::traits::solve::{CandidateSource, Certainty, Goal}; use rustc_infer::traits::{ BuiltinImplSource, ImplSource, ImplSourceUserDefinedData, Obligation, ObligationCause, - PolyTraitObligation, PredicateObligation, Selection, SelectionError, SelectionResult, + PolyTraitObligation, Selection, SelectionError, SelectionResult, }; use rustc_macros::extension; use rustc_span::Span; @@ -133,32 +132,32 @@ fn to_selection<'tcx>( return None; } - let make_nested = || { - cand.instantiate_nested_goals(span) - .into_iter() - .map(|nested| { - Obligation::new( - nested.infcx().tcx, - ObligationCause::dummy_with_span(span), - nested.goal().param_env, - nested.goal().predicate, - ) - }) - .collect() - }; + let (nested, impl_args) = cand.instantiate_nested_goals_and_opt_impl_args(span); + let nested = nested + .into_iter() + .map(|nested| { + Obligation::new( + nested.infcx().tcx, + ObligationCause::dummy_with_span(span), + nested.goal().param_env, + nested.goal().predicate, + ) + }) + .collect(); Some(match cand.kind() { ProbeKind::TraitCandidate { source, result: _ } => match source { CandidateSource::Impl(impl_def_id) => { // FIXME: Remove this in favor of storing this in the tree // For impl candidates, we do the rematch manually to compute the args. - ImplSource::UserDefined(rematch_impl(cand.goal(), impl_def_id, span)) - } - CandidateSource::BuiltinImpl(builtin) => ImplSource::Builtin(builtin, make_nested()), - CandidateSource::ParamEnv(_) => ImplSource::Param(make_nested()), - CandidateSource::AliasBound => { - ImplSource::Builtin(BuiltinImplSource::Misc, make_nested()) + ImplSource::UserDefined(ImplSourceUserDefinedData { + impl_def_id, + args: impl_args.expect("expected recorded impl args for impl candidate"), + nested, + }) } + CandidateSource::BuiltinImpl(builtin) => ImplSource::Builtin(builtin, nested), + CandidateSource::ParamEnv(_) | CandidateSource::AliasBound => ImplSource::Param(nested), CandidateSource::CoherenceUnknowable => { span_bug!(span, "didn't expect to select an unknowable candidate") } @@ -173,40 +172,3 @@ fn to_selection<'tcx>( } }) } - -fn rematch_impl<'tcx>( - goal: &inspect::InspectGoal<'_, 'tcx>, - impl_def_id: DefId, - span: Span, -) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> { - let infcx = goal.infcx(); - let goal_trait_ref = infcx - .enter_forall_and_leak_universe(goal.goal().predicate.to_opt_poly_trait_pred().unwrap()) - .trait_ref; - - let args = infcx.fresh_args_for_item(span, impl_def_id); - let impl_trait_ref = - infcx.tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(infcx.tcx, args); - - let InferOk { value: (), obligations: mut nested } = infcx - .at(&ObligationCause::dummy_with_span(span), goal.goal().param_env) - .eq(DefineOpaqueTypes::Yes, goal_trait_ref, impl_trait_ref) - .expect("rematching impl failed"); - - // FIXME(-Znext-solver=coinductive): We need to add supertraits here eventually. - - nested.extend( - infcx.tcx.predicates_of(impl_def_id).instantiate(infcx.tcx, args).into_iter().map( - |(clause, _)| { - Obligation::new( - infcx.tcx, - ObligationCause::dummy_with_span(span), - goal.goal().param_env, - clause, - ) - }, - ), - ); - - ImplSourceUserDefinedData { impl_def_id, nested, args } -} diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 4f79f1b2aafe0..fa4323a3a944d 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -93,6 +93,7 @@ pub struct InspectCandidate<'a, 'tcx> { kind: inspect::ProbeKind<'tcx>, nested_goals: Vec<(GoalSource, inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>)>, final_state: inspect::CanonicalState<'tcx, ()>, + impl_args: Option>>, result: QueryResult<'tcx>, shallow_certainty: Certainty, } @@ -135,7 +136,20 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { /// Instantiate the nested goals for the candidate without rolling back their /// inference constraints. This function modifies the state of the `infcx`. + /// + /// See [`Self::instantiate_nested_goals_and_opt_impl_args`] if you need the impl args too. pub fn instantiate_nested_goals(&self, span: Span) -> Vec> { + self.instantiate_nested_goals_and_opt_impl_args(span).0 + } + + /// Instantiate the nested goals for the candidate without rolling back their + /// inference constraints, and optionally the args of an impl if this candidate + /// came from a `CandidateSource::Impl`. This function modifies the state of the + /// `infcx`. + pub fn instantiate_nested_goals_and_opt_impl_args( + &self, + span: Span, + ) -> (Vec>, Option>) { let infcx = self.goal.infcx; let param_env = self.goal.goal.param_env; let mut orig_values = self.goal.orig_values.to_vec(); @@ -164,6 +178,17 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { self.final_state, ); + let impl_args = self.impl_args.map(|impl_args| { + canonical::instantiate_canonical_state( + infcx, + span, + param_env, + &mut orig_values, + impl_args, + ) + .fold_with(&mut EagerResolver::new(infcx)) + }); + if let Some(term_hack) = self.goal.normalizes_to_term_hack { // FIXME: We ignore the expected term of `NormalizesTo` goals // when computing the result of its candidates. This is @@ -171,7 +196,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { let _ = term_hack.constrain(infcx, span, param_env); } - instantiated_goals + let goals = instantiated_goals .into_iter() .map(|(source, goal)| match goal.predicate.kind().no_bound_vars() { Some(ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })) => { @@ -208,7 +233,9 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { source, ), }) - .collect() + .collect(); + + (goals, impl_args) } /// Visit all nested goals of this candidate, rolling back @@ -245,9 +272,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { probe: &inspect::Probe<'tcx>, ) { let mut shallow_certainty = None; + let mut impl_args = None; for step in &probe.steps { - match step { - &inspect::ProbeStep::AddGoal(source, goal) => nested_goals.push((source, goal)), + match *step { + inspect::ProbeStep::AddGoal(source, goal) => nested_goals.push((source, goal)), inspect::ProbeStep::NestedProbe(ref probe) => { // Nested probes have to prove goals added in their parent // but do not leak them, so we truncate the added goals @@ -257,7 +285,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { nested_goals.truncate(num_goals); } inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => { - assert_eq!(shallow_certainty.replace(*c), None); + assert_eq!(shallow_certainty.replace(c), None); + } + inspect::ProbeStep::RecordImplArgs { impl_args: i } => { + assert_eq!(impl_args.replace(i), None); } inspect::ProbeStep::EvaluateGoals(_) => (), } @@ -284,6 +315,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { final_state: probe.final_state, result, shallow_certainty, + impl_args, }); } } diff --git a/compiler/rustc_trait_selection/src/solve/inspect/build.rs b/compiler/rustc_trait_selection/src/solve/inspect/build.rs index 466d0d8006018..79d8901a260b4 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/build.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/build.rs @@ -242,6 +242,7 @@ enum WipProbeStep<'tcx> { EvaluateGoals(WipAddedGoalsEvaluation<'tcx>), NestedProbe(WipProbe<'tcx>), MakeCanonicalResponse { shallow_certainty: Certainty }, + RecordImplArgs { impl_args: inspect::CanonicalState<'tcx, ty::GenericArgsRef<'tcx>> }, } impl<'tcx> WipProbeStep<'tcx> { @@ -250,6 +251,9 @@ impl<'tcx> WipProbeStep<'tcx> { WipProbeStep::AddGoal(source, goal) => inspect::ProbeStep::AddGoal(source, goal), WipProbeStep::EvaluateGoals(eval) => inspect::ProbeStep::EvaluateGoals(eval.finalize()), WipProbeStep::NestedProbe(probe) => inspect::ProbeStep::NestedProbe(probe.finalize()), + WipProbeStep::RecordImplArgs { impl_args } => { + inspect::ProbeStep::RecordImplArgs { impl_args } + } WipProbeStep::MakeCanonicalResponse { shallow_certainty } => { inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty } } @@ -534,6 +538,30 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } } + pub(crate) fn record_impl_args( + &mut self, + infcx: &InferCtxt<'tcx>, + max_input_universe: ty::UniverseIndex, + impl_args: ty::GenericArgsRef<'tcx>, + ) { + match self.as_mut() { + Some(DebugSolver::GoalEvaluationStep(state)) => { + let impl_args = canonical::make_canonical_state( + infcx, + &state.var_values, + max_input_universe, + impl_args, + ); + state + .current_evaluation_scope() + .steps + .push(WipProbeStep::RecordImplArgs { impl_args }); + } + None => {} + _ => bug!(), + } + } + pub fn make_canonical_response(&mut self, shallow_certainty: Certainty) { match self.as_mut() { Some(DebugSolver::GoalEvaluationStep(state)) => { @@ -543,7 +571,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { .push(WipProbeStep::MakeCanonicalResponse { shallow_certainty }); } None => {} - _ => {} + _ => bug!(), } } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index d2b893d6383bd..0fde9dd4cd680 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -75,6 +75,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| { let impl_args = ecx.fresh_args_for_item(impl_def_id); + ecx.record_impl_args(impl_args); let impl_trait_ref = impl_trait_header.trait_ref.instantiate(tcx, impl_args); ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?; diff --git a/src/doc/book b/src/doc/book index d207d894cc5e1..bebcf527e6775 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit d207d894cc5e1d496ab99beeacd1a420e5d4d238 +Subproject commit bebcf527e67755a989a1739b7cfaa8f0e6b30040 diff --git a/src/doc/embedded-book b/src/doc/embedded-book index aa7d4b0b4653d..17842ebb050f6 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit aa7d4b0b4653ddb47cb1de2036d090ec2ba9dab1 +Subproject commit 17842ebb050f62e40a4618edeb8e8ee86e758707 diff --git a/src/doc/reference b/src/doc/reference index 5854fcc286557..51817951d0d21 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 5854fcc286557ad3ab34d325073d11d8118096b6 +Subproject commit 51817951d0d213a0011f82b62aae02c3b3f2472e diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 60d34b5fd33db..229ad13b64d91 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 60d34b5fd33db1346f9aabfc0c9d0bda6c8e42be +Subproject commit 229ad13b64d919b12e548d560f06d88963b25cd3 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index 07425fed36b00..2d1947ff34d50 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit 07425fed36b00e60341c5e29e28d37d40cbd4451 +Subproject commit 2d1947ff34d50ca46dfe242ad75531a4c429bb52 diff --git a/src/doc/rustc/src/check-cfg.md b/src/doc/rustc/src/check-cfg.md index 56198437ee97d..8e39adaa43858 100644 --- a/src/doc/rustc/src/check-cfg.md +++ b/src/doc/rustc/src/check-cfg.md @@ -1,18 +1,29 @@ # Checking conditional configurations -`rustc` accepts the `--check-cfg` option, which specifies whether to check conditions and how to -check them. The `--check-cfg` option takes a value, called the _check cfg specification_. -This specification has one form: +`rustc` supports checking that every _reachable_[^reachable] `#[cfg]` matches a list of the +expected config names and values. -1. `--check-cfg cfg(...)` mark a configuration and it's expected values as expected. +This can help with verifying that the crate is correctly handling conditional compilation for +different target platforms or features. It ensures that the cfg settings are consistent between +what is intended and what is used, helping to catch potential bugs or errors early in the +development process. -*No implicit expectation is added when using `--cfg`. Users are expected to -pass all expected names and values using the _check cfg specification_.* +In order to accomplish that goal, `rustc` accepts the `--check-cfg` flag, which specifies +whether to check conditions and how to check them. -## The `cfg(...)` form +> **Note:** No implicit expectation is added when using `--cfg`. Users are expected to +pass all expected names and values using the _check cfg specification_. -The `cfg(...)` form enables checking the values within list-valued conditions. It has this -basic form: +[^reachable]: `rustc` promises to at least check reachable `#[cfg]`, and while non-reachable +`#[cfg]` are not currently checked, they may well be checked in the future without it being a +breaking change. + +## Specifying expected names and values + +To specify expected names and values, the _check cfg specification_ provides the `cfg(...)` +option which enables specifying for an expected config name and it's expected values. + +It has this basic form: ```bash rustc --check-cfg 'cfg(name, values("value1", "value2", ... "valueN"))' @@ -20,15 +31,20 @@ rustc --check-cfg 'cfg(name, values("value1", "value2", ... "valueN"))' where `name` is a bare identifier (has no quotes) and each `"value"` term is a quoted literal string. `name` specifies the name of the condition, such as `feature` or `my_cfg`. +`"value"` specify one of the value of that condition name. + +When the `cfg(...)` option is specified, `rustc` will check every[^reachable]: + - `#[cfg(name = "value")]` attribute + - `#[cfg_attr(name = "value")]` attribute + - `#[link(name = "a", cfg(name = "value"))]` attribute + - `cfg!(name = "value")` macro call -When the `cfg(...)` option is specified, `rustc` will check every `#[cfg(name = "value")]` -attribute, `#[cfg_attr(name = "value")]` attribute, `#[link(name = "a", cfg(name = "value"))]` -attribute and `cfg!(name = "value")` macro call. It will check that the `"value"` specified is -present in the list of expected values. If `"value"` is not in it, then `rustc` will report an -`unexpected_cfgs` lint diagnostic. The default diagnostic level for this lint is `Warn`. +> *The command line `--cfg` arguments are currently NOT checked but may very well be checked +in the future.* -*The command line `--cfg` arguments are currently *NOT* checked but may very well be checked in -the future.* +`rustc` will check that the `"value"` specified is present in the list of expected values. +If `"value"` is not in it, then `rustc` will report an `unexpected_cfgs` lint diagnostic. +The default diagnostic level for this lint is `Warn`. To check for the _none_ value (ie `#[cfg(foo)]`) one can use the `none()` predicate inside `values()`: `values(none())`. It can be followed or preceded by any number of `"value"`. @@ -43,12 +59,12 @@ rustc --check-cfg 'cfg(name, values(none()))' To enable checking of name but not values, use one of these forms: - - No expected values (_will lint on every value_): + - No expected values (_will lint on every value of `name`_): ```bash rustc --check-cfg 'cfg(name, values())' ``` - - Unknown expected values (_will never lint_): + - Unknown expected values (_will never lint on value of `name`_): ```bash rustc --check-cfg 'cfg(name, values(any()))' ``` @@ -59,17 +75,26 @@ To avoid repeating the same set of values, use this form: rustc --check-cfg 'cfg(name1, ..., nameN, values("value1", "value2", ... "valueN"))' ``` +To enable checking without specifying any names or values, use this form: + +```bash +rustc --check-cfg 'cfg()' +``` + The `--check-cfg cfg(...)` option can be repeated, both for the same condition name and for different names. If it is repeated for the same condition name, then the sets of values for that condition are merged together (precedence is given to `values(any())`). +> To help out an equivalence table between `--cfg` arguments and `--check-cfg` is available +[down below](#equivalence-table-with---cfg). + ## Well known names and values -`rustc` has a internal list of well known names and their corresponding values. -Those well known names and values follows the same stability as what they refer to. +`rustc` maintains a list of well-known names and their corresponding values in order to avoid +the need to specify them manually. -Well known names and values checking is always enabled as long as at least one -`--check-cfg` argument is present. +Well known names and values are implicitly added as long as at least one `--check-cfg` argument +is present. As of `2024-05-06T`, the list of known names is as follows: @@ -109,11 +134,9 @@ As of `2024-05-06T`, the list of known names is as follows: Like with `values(any())`, well known names checking can be disabled by passing `cfg(any())` as argument to `--check-cfg`. -## Examples - -### Equivalence table +## Equivalence table with `--cfg` -This table describe the equivalence of a `--cfg` argument to a `--check-cfg` argument. +This table describe the equivalence between a `--cfg` argument to a `--check-cfg` argument. | `--cfg` | `--check-cfg` | |-------------------------------|------------------------------------------------------------| @@ -125,40 +148,42 @@ This table describe the equivalence of a `--cfg` argument to a `--check-cfg` arg | `--cfg foo="1" --cfg bar="2"` | `--check-cfg=cfg(foo, values("1")) --check-cfg=cfg(bar, values("2"))` | | `--cfg foo --cfg foo="bar"` | `--check-cfg=cfg(foo, values(none(), "bar"))` | +## Examples + ### Example: Cargo-like `feature` example Consider this command line: ```bash rustc --check-cfg 'cfg(feature, values("lion", "zebra"))' \ - --cfg 'feature="lion"' -Z unstable-options example.rs + --cfg 'feature="lion"' example.rs ``` -This command line indicates that this crate has two features: `lion` and `zebra`. The `lion` +> This command line indicates that this crate has two features: `lion` and `zebra`. The `lion` feature is enabled, while the `zebra` feature is disabled. -Given the `--check-cfg` arguments, exhaustive checking of names and -values are enabled. -`example.rs`: ```rust -#[cfg(feature = "lion")] // This condition is expected, as "lion" is an expected value of `feature` +#[cfg(feature = "lion")] // This condition is expected, as "lion" is an + // expected value of `feature` fn tame_lion(lion: Lion) {} -#[cfg(feature = "zebra")] // This condition is expected, as "zebra" is an expected value of `feature` - // but the condition will still evaluate to false - // since only --cfg feature="lion" was passed +#[cfg(feature = "zebra")] // This condition is expected, as "zebra" is an expected + // value of `feature` but the condition will evaluate + // to false since only --cfg feature="lion" was passed fn ride_zebra(z: Zebra) {} -#[cfg(feature = "platypus")] // This condition is UNEXPECTED, as "platypus" is NOT an expected value of - // `feature` and will cause a compiler warning (by default). +#[cfg(feature = "platypus")] // This condition is UNEXPECTED, as "platypus" is NOT + // an expected value of `feature` and will cause a + // the compiler to emit the `unexpected_cfgs` lint fn poke_platypus() {} -#[cfg(feechure = "lion")] // This condition is UNEXPECTED, as 'feechure' is NOT a expected condition - // name, no `cfg(feechure, ...)` was passed in `--check-cfg` +#[cfg(feechure = "lion")] // This condition is UNEXPECTED, as 'feechure' is NOT + // a expected condition name, no `cfg(feechure, ...)` + // was passed in `--check-cfg` fn tame_lion() {} -#[cfg(windows = "unix")] // This condition is UNEXPECTED, as while 'windows' is a well known - // condition name, it doesn't expect any values +#[cfg(windows = "unix")] // This condition is UNEXPECTED, as the well known + // 'windows' cfg doesn't expect any values fn tame_windows() {} ``` @@ -167,25 +192,28 @@ fn tame_windows() {} ```bash rustc --check-cfg 'cfg(is_embedded, has_feathers)' \ --check-cfg 'cfg(feature, values("zapping", "lasers"))' \ - --cfg has_feathers --cfg 'feature="zapping"' -Z unstable-options + --cfg has_feathers --cfg 'feature="zapping"' ``` ```rust -#[cfg(is_embedded)] // This condition is expected, as 'is_embedded' was provided in --check-cfg -fn do_embedded() {} // and doesn't take any value +#[cfg(is_embedded)] // This condition is expected, as 'is_embedded' was + // provided in --check-cfg and doesn't take any value +fn do_embedded() {} -#[cfg(has_feathers)] // This condition is expected, as 'has_feathers' was provided in --check-cfg -fn do_features() {} // and doesn't take any value +#[cfg(has_feathers)] // This condition is expected, as 'has_feathers' was + // provided in --check-cfg and doesn't take any value +fn do_features() {} -#[cfg(has_mumble_frotz)] // This condition is UNEXPECTED, as 'has_mumble_frotz' was NEVER provided - // in any --check-cfg arguments +#[cfg(has_mumble_frotz)] // This condition is UNEXPECTED, as 'has_mumble_frotz' + // was NEVER provided in any --check-cfg arguments fn do_mumble_frotz() {} -#[cfg(feature = "lasers")] // This condition is expected, as "lasers" is an expected value of `feature` +#[cfg(feature = "lasers")] // This condition is expected, as "lasers" is an + // expected value of `feature` fn shoot_lasers() {} -#[cfg(feature = "monkeys")] // This condition is UNEXPECTED, as "monkeys" is NOT an expected value of - // `feature` +#[cfg(feature = "monkeys")] // This condition is UNEXPECTED, as "monkeys" is NOT + // an expected value of `feature` fn write_shakespeare() {} ``` @@ -193,24 +221,25 @@ fn write_shakespeare() {} ```bash rustc --check-cfg 'cfg(is_embedded, has_feathers, values(any()))' \ - --cfg has_feathers -Z unstable-options + --cfg has_feathers ``` ```rust -#[cfg(is_embedded)] // This condition is expected, as 'is_embedded' was provided in --check-cfg - // as condition name +#[cfg(is_embedded)] // This condition is expected, as 'is_embedded' was + // provided in --check-cfg as condition name fn do_embedded() {} -#[cfg(has_feathers)] // This condition is expected, as "has_feathers" was provided in --check-cfg - // as condition name +#[cfg(has_feathers)] // This condition is expected, as "has_feathers" was + // provided in --check-cfg as condition name fn do_features() {} -#[cfg(has_feathers = "zapping")] // This condition is expected, as "has_feathers" was provided in - // and because *any* values is expected for 'has_feathers' no +#[cfg(has_feathers = "zapping")] // This condition is expected, as "has_feathers" + // was provided and because *any* values is + // expected for 'has_feathers' no // warning is emitted for the value "zapping" fn do_zapping() {} -#[cfg(has_mumble_frotz)] // This condition is UNEXPECTED, as 'has_mumble_frotz' was not provided - // in any --check-cfg arguments +#[cfg(has_mumble_frotz)] // This condition is UNEXPECTED, as 'has_mumble_frotz' + // was not provided in any --check-cfg arguments fn do_mumble_frotz() {} ``` diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index 7c605333c25d4..3e1ac2fa8ad7b 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -19,9 +19,15 @@ For examples, `--cfg 'verbose'` or `--cfg 'feature="serde"'`. These correspond to `#[cfg(verbose)]` and `#[cfg(feature = "serde")]` respectively. -## `--check-cfg`: enables checking conditional configurations +## `--check-cfg`: configure compile-time checking of conditional compilation + +This flag enables checking conditional configurations of the crate at compile-time, +specifically it helps configure the set of expected cfg names and values, in order +to check that every _reachable_ `#[cfg]` matches the expected config names and values. + +This is different from the `--cfg` flag above which activates some config but do +not expect them. This is useful to prevent stalled conditions, typos, ... -This flag will enable checking conditional configurations. Refer to the [Checking conditional configurations](check-cfg.md) of this book for further details and explanation. diff --git a/tests/ui/impl-trait/dyn-trait-elided-two-inputs-ref-assoc.rs b/tests/ui/impl-trait/dyn-trait-elided-two-inputs-ref-assoc.rs index 2dc19b9ad6884..e9706b656f228 100644 --- a/tests/ui/impl-trait/dyn-trait-elided-two-inputs-ref-assoc.rs +++ b/tests/ui/impl-trait/dyn-trait-elided-two-inputs-ref-assoc.rs @@ -2,6 +2,9 @@ // when there are multiple inputs. The `dyn Bar` should default to `+ // 'static`. This used to erroneously generate an error (cc #62517). // +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) //@ check-pass trait Foo { diff --git a/tests/ui/impl-trait/in-trait/placeholder-implied-bounds.rs b/tests/ui/impl-trait/in-trait/placeholder-implied-bounds.rs index f7546a05bfdb6..df03150e29acb 100644 --- a/tests/ui/impl-trait/in-trait/placeholder-implied-bounds.rs +++ b/tests/ui/impl-trait/in-trait/placeholder-implied-bounds.rs @@ -1,3 +1,6 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) //@ check-pass pub fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-105826.rs b/tests/ui/impl-trait/issues/issue-105826.rs index e3488140dcc7a..33c5ed5fdebe5 100644 --- a/tests/ui/impl-trait/issues/issue-105826.rs +++ b/tests/ui/impl-trait/issues/issue-105826.rs @@ -1,3 +1,6 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) //@ check-pass use std::io::Write; diff --git a/tests/ui/traits/next-solver/select-alias-bound-as-param.rs b/tests/ui/traits/next-solver/select-alias-bound-as-param.rs new file mode 100644 index 0000000000000..fd40ef1f872f3 --- /dev/null +++ b/tests/ui/traits/next-solver/select-alias-bound-as-param.rs @@ -0,0 +1,13 @@ +//@ check-pass +//@ compile-flags: -Znext-solver + +pub(crate) fn y() -> impl FnMut() { + || {} +} + +pub(crate) fn x(a: (), b: ()) { + let x = (); + y()() +} + +fn main() {} diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.next.stderr b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.next.stderr deleted file mode 100644 index 3c2bc0b919065..0000000000000 --- a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.next.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: internal compiler error: error performing operation: query type op - --> $DIR/illegal-upcast-from-impl-opaque.rs:25:1 - | -LL | fn illegal(x: &dyn Sub) -> &dyn Super { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: - --> $DIR/illegal-upcast-from-impl-opaque.rs:25:1 - | -LL | fn illegal(x: &dyn Sub) -> &dyn Super { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -query stack during panic: -end of query stack diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.rs b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.rs deleted file mode 100644 index f344474054a22..0000000000000 --- a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.rs +++ /dev/null @@ -1,29 +0,0 @@ -//@ revisions: current next -//@[next] compile-flags: -Znext-solver -//@[next] failure-status: 101 -//@[next] known-bug: unknown -//@[next] normalize-stderr-test "note: .*\n\n" -> "" -//@[next] normalize-stderr-test "thread 'rustc' panicked.*\n.*\n" -> "" -//@[next] normalize-stderr-test "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: " -//@[next] normalize-stderr-test "delayed at .*" -> "" -//@[next] rustc-env:RUST_BACKTRACE=0 - -#![feature(trait_upcasting, type_alias_impl_trait)] - -trait Super { - type Assoc; -} - -trait Sub: Super {} - -impl Super for T { - type Assoc = i32; -} - -type Foo = impl Sized; - -fn illegal(x: &dyn Sub) -> &dyn Super { - x //[current]~ mismatched types -} - -fn main() {} diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.current.stderr b/tests/ui/traits/trait-upcasting/upcast-defining-opaque.current.stderr similarity index 62% rename from tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.current.stderr rename to tests/ui/traits/trait-upcasting/upcast-defining-opaque.current.stderr index c54a1c42baddf..a259abb28ae3e 100644 --- a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.current.stderr +++ b/tests/ui/traits/trait-upcasting/upcast-defining-opaque.current.stderr @@ -1,11 +1,11 @@ error[E0308]: mismatched types - --> $DIR/illegal-upcast-from-impl-opaque.rs:26:5 + --> $DIR/upcast-defining-opaque.rs:21:5 | LL | type Foo = impl Sized; | ---------- the found opaque type LL | -LL | fn illegal(x: &dyn Sub) -> &dyn Super { - | ----------------------- expected `&dyn Super` because of return type +LL | fn upcast(x: &dyn Sub) -> &dyn Super { + | ----------------------- expected `&dyn Super` because of return type LL | x | ^ expected trait `Super`, found trait `Sub` | diff --git a/tests/ui/traits/trait-upcasting/upcast-defining-opaque.rs b/tests/ui/traits/trait-upcasting/upcast-defining-opaque.rs new file mode 100644 index 0000000000000..cb1501a94a2ae --- /dev/null +++ b/tests/ui/traits/trait-upcasting/upcast-defining-opaque.rs @@ -0,0 +1,24 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] check-pass + +#![feature(trait_upcasting, type_alias_impl_trait)] + +trait Super { + type Assoc; +} + +trait Sub: Super {} + +impl Super for T { + type Assoc = i32; +} + +type Foo = impl Sized; + +fn upcast(x: &dyn Sub) -> &dyn Super { + x //[current]~ mismatched types +} + +fn main() {}