diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index d1d864246b9ff..0f0940712a77a 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -322,6 +322,10 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { self.resolve_vars_if_possible(value) } + fn commit_if_ok(&self, f: impl FnOnce() -> Result) -> Result { + self.commit_if_ok(|_| f()) + } + fn probe(&self, probe: impl FnOnce() -> T) -> T { self.probe(|_| probe()) } diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index f325862102318..3a2643a65b48c 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -13,6 +13,7 @@ use std::iter; use canonicalizer::Canonicalizer; use rustc_index::IndexVec; +use rustc_type_ir::error::TypeError; use rustc_type_ir::inherent::*; use rustc_type_ir::relate::{ self, Relate, RelateResult, TypeRelation, VarianceDiagInfo, relate_args_invariantly, @@ -27,7 +28,7 @@ use crate::delegate::SolverDelegate; use crate::resolve::eager_resolve_vars; use crate::solve::{ CanonicalInput, CanonicalResponse, Certainty, ExternalConstraintsData, - ExternalRegionConstraints, Goal, NestedNormalizationGoals, QueryInput, Response, + ExternalRegionConstraints, Goal, NestedNormalizationGoals, NoSolution, QueryInput, Response, VisibleForLeakCheck, inspect, }; @@ -103,7 +104,7 @@ pub(super) fn instantiate_and_apply_query_response( original_values: &[I::GenericArg], response: CanonicalResponse, span: I::Span, -) -> (NestedNormalizationGoals, Certainty) +) -> Result<(NestedNormalizationGoals, Certainty), NoSolution> where D: SolverDelegate, I: Interner, @@ -114,7 +115,7 @@ where let Response { var_values, external_constraints, certainty } = delegate.instantiate_canonical(response, instantiation); - unify_query_var_values(delegate, param_env, &original_values, var_values, span); + unify_query_var_values(delegate, param_env, &original_values, var_values, span)?; let ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals } = &*external_constraints; @@ -139,7 +140,7 @@ where }; register_new_opaque_types(delegate, opaque_types, span); - (normalization_nested_goals.clone(), certainty) + Ok((normalization_nested_goals.clone(), certainty)) } /// This returns the canonical variable values to instantiate the bound variables of @@ -320,10 +321,24 @@ where } (ty::Infer(ty::TyVar(a_vid)), _) => { + if !infcx + .universe_of_ty(a_vid) + .unwrap() + .can_name(ty::max_universe_of_non_region_placeholders(infcx, b)) + { + return Err(TypeError::Mismatch); + } infcx.instantiate_ty_var_raw(a_vid, b); } (_, ty::Infer(ty::TyVar(b_vid))) => { + if !infcx + .universe_of_ty(b_vid) + .unwrap() + .can_name(ty::max_universe_of_non_region_placeholders(infcx, a)) + { + return Err(TypeError::Mismatch); + } infcx.instantiate_ty_var_raw(b_vid, a); } @@ -407,10 +422,24 @@ where } (ty::ConstKind::Infer(ty::InferConst::Var(a_vid)), _) => { + if !infcx + .universe_of_ct(a_vid) + .unwrap() + .can_name(ty::max_universe_of_non_region_placeholders(infcx, b)) + { + return Err(TypeError::Mismatch); + } infcx.instantiate_const_var_raw(a_vid, b); } (_, ty::ConstKind::Infer(ty::InferConst::Var(b_vid))) => { + if !infcx + .universe_of_ct(b_vid) + .unwrap() + .can_name(ty::max_universe_of_non_region_placeholders(infcx, a)) + { + return Err(TypeError::Mismatch); + } infcx.instantiate_const_var_raw(b_vid, a); } @@ -443,10 +472,10 @@ where /// Unify the `original_values` with the `var_values` returned by the canonical query.. /// -/// This assumes that this unification will always succeed. This is the case when -/// applying a query response right away. However, calling a canonical query, doing any -/// other kind of trait solving, and only then instantiating the result of the query -/// can cause the instantiation to fail. This is not supported and we ICE in this case. +/// This unification can fail if an input inference variable cannot name a placeholder +/// in the response. Input canonicalization maps all universes to the root universe, so +/// the query itself cannot detect that mismatch. Treating the response as `NoSolution` +/// here prevents a higher-ranked placeholder from leaking into the caller. /// /// We always structurally instantiate aliases. Relating aliases needs to be different /// depending on whether the alias is *rigid* or not. We're only really able to tell @@ -460,16 +489,21 @@ fn unify_query_var_values( original_values: &[I::GenericArg], var_values: CanonicalVarValues, span: I::Span, -) where +) -> Result<(), NoSolution> +where D: SolverDelegate, I: Interner, { assert_eq!(original_values.len(), var_values.len()); - for (&orig, response) in iter::zip(original_values, var_values.var_values.iter()) { - let mut must_eq = ResponseRelating::new(&**delegate, span); - must_eq.relate(orig, response).unwrap(); - } + delegate.commit_if_ok(|| { + for (&orig, response) in iter::zip(original_values, var_values.var_values.iter()) { + let mut must_eq = ResponseRelating::new(&**delegate, span); + must_eq.relate(orig, response).map_err(|_| NoSolution)?; + } + + Ok(()) + }) } fn register_region_constraints( @@ -546,7 +580,7 @@ pub fn instantiate_canonical_state( param_env: I::ParamEnv, orig_values: &mut Vec, state: inspect::CanonicalState, -) -> T +) -> Result where D: SolverDelegate, I: Interner, @@ -565,8 +599,8 @@ where let inspect::State { var_values, data } = delegate.instantiate_canonical(state, instantiation); - unify_query_var_values(delegate, param_env, orig_values, var_values, span); - data + unify_query_var_values(delegate, param_env, orig_values, var_values, span)?; + Ok(data) } pub fn response_no_constraints_raw( diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index c3ccb46069063..37d70df8a21c9 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -684,7 +684,7 @@ where &orig_values, response, self.origin_span, - ); + )?; // FIXME: We previously had an assert here that checked that recomputing // a goal after applying its constraints did not change its response. @@ -1734,7 +1734,7 @@ pub(super) fn evaluate_root_goal_for_proof_tree, let (canonical_result, final_revision) = delegate.cx().evaluate_root_goal_for_proof_tree_raw(canonical_goal); - let proof_tree = inspect::GoalEvaluation { + let mut proof_tree = inspect::GoalEvaluation { uncanonicalized_goal: goal, orig_values, final_revision, @@ -1746,13 +1746,34 @@ pub(super) fn evaluate_root_goal_for_proof_tree, Ok(response) => response, }; - let (normalization_nested_goals, _certainty) = instantiate_and_apply_query_response( + let Ok((normalization_nested_goals, _certainty)) = instantiate_and_apply_query_response( delegate, goal.param_env, &proof_tree.orig_values, response, origin_span, - ); + ) else { + proof_tree.result = Err(NoSolution); + // The recorded states may contain the same constraints which made the response + // inapplicable in the caller, so they cannot be safely replayed by diagnostics. + let var_kinds = canonical_goal.canonical.var_kinds; + proof_tree.final_revision = delegate.cx().mk_probe(inspect::Probe { + steps: vec![], + kind: inspect::ProbeKind::Root { result: Err(NoSolution) }, + // This failed proof has no state to replay. Keep an identity state in the + // solver query's canonical variables instead of response-canonicalizing + // caller-side values, which may contain parameters. + final_state: ty::Canonical { + value: inspect::State { + var_values: CanonicalVarValues::make_identity(delegate.cx(), var_kinds), + data: (), + }, + max_universe: canonical_goal.canonical.max_universe, + var_kinds, + }, + }); + return (Err(NoSolution), proof_tree); + }; (Ok(normalization_nested_goals), proof_tree) } diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index 0c365e9dea707..da3b073abde67 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -229,14 +229,16 @@ impl<'tcx> BestObligation<'tcx> { if candidates.len() > 1 { candidates.retain(|candidate| { goal.infcx().probe(|_| { - candidate.instantiate_nested_goals(self.span()).iter().any( - |nested_goal| { - matches!( - nested_goal.source(), - GoalSource::ImplWhereBound - | GoalSource::AliasBoundConstCondition - | GoalSource::AliasWellFormed - ) && nested_goal.result().is_err() + candidate.instantiate_nested_goals(self.span()).is_ok_and( + |nested_goals| { + nested_goals.iter().any(|nested_goal| { + matches!( + nested_goal.source(), + GoalSource::ImplWhereBound + | GoalSource::AliasBoundConstCondition + | GoalSource::AliasWellFormed + ) && nested_goal.result().is_err() + }) }, ) }) @@ -470,7 +472,9 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { _ => ChildMode::PassThrough, }; - let nested_goals = candidate.instantiate_nested_goals(self.span()); + let Ok(nested_goals) = candidate.instantiate_nested_goals(self.span()) else { + return self.detect_error_from_empty_candidates(goal); + }; // If the candidate requires some `T: FnPtr` bound which does not hold should not be treated as // an actual candidate, instead we should treat them as if the impl was never considered to diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 7bf41d343ecf4..a08392fce6419 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -76,7 +76,11 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { /// back their inference constraints. This function modifies /// the state of the `infcx`. pub fn visit_nested_no_probe>(&self, visitor: &mut V) -> V::Result { - for goal in self.instantiate_nested_goals(visitor.span()) { + let Ok(nested_goals) = self.instantiate_nested_goals(visitor.span()) else { + return V::Result::output(); + }; + + for goal in nested_goals { try_visit!(goal.visit_with(visitor)); } @@ -92,31 +96,52 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { skip_all, fields(goal = ?self.goal.goal, steps = ?self.steps) )] - pub fn instantiate_nested_goals(&self, span: Span) -> Vec> { + pub fn instantiate_nested_goals( + &self, + span: Span, + ) -> Result>, NoSolution> { let infcx = self.goal.infcx; let param_env = self.goal.goal.param_env; - let mut orig_values = self.goal.orig_values.clone(); - - let mut instantiated_goals = vec![]; - for step in &self.steps { - match **step { - inspect::ProbeStep::AddGoal(source, goal) => instantiated_goals.push(( - source, - instantiate_canonical_state(infcx, span, param_env, &mut orig_values, goal), - )), - inspect::ProbeStep::RecordImplArgs { .. } => {} - inspect::ProbeStep::MakeCanonicalResponse { .. } - | inspect::ProbeStep::NestedProbe(_) => unreachable!(), - } - } + let instantiate = + || -> Result>)>, NoSolution> { + let mut orig_values = self.goal.orig_values.clone(); + let mut instantiated_goals = vec![]; + + for step in &self.steps { + match **step { + inspect::ProbeStep::AddGoal(source, goal) => { + let goal = instantiate_canonical_state( + infcx, + span, + param_env, + &mut orig_values, + goal, + )?; + instantiated_goals.push((source, goal)); + } + inspect::ProbeStep::RecordImplArgs { .. } => {} + inspect::ProbeStep::MakeCanonicalResponse { .. } + | inspect::ProbeStep::NestedProbe(_) => unreachable!(), + } + } + + let () = instantiate_canonical_state( + infcx, + span, + param_env, + &mut orig_values, + self.final_state, + )?; + + Ok(instantiated_goals) + }; - let () = - instantiate_canonical_state(infcx, span, param_env, &mut orig_values, self.final_state); + let instantiated_goals = infcx.commit_if_ok(|_| instantiate())?; - instantiated_goals + Ok(instantiated_goals .into_iter() .map(|(source, goal)| self.instantiate_proof_tree_for_nested_goal(source, goal, span)) - .collect() + .collect()) } /// Instantiate the args of an impl if this candidate came from a @@ -127,39 +152,47 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { skip_all, fields(goal = ?self.goal.goal, steps = ?self.steps) )] - pub fn instantiate_impl_args(&self, span: Span) -> ty::GenericArgsRef<'tcx> { + pub fn instantiate_impl_args( + &self, + span: Span, + ) -> Result, NoSolution> { let infcx = self.goal.infcx; let param_env = self.goal.goal.param_env; - let mut orig_values = self.goal.orig_values.clone(); - - for step in &self.steps { - match **step { - inspect::ProbeStep::RecordImplArgs { impl_args } => { - let impl_args = instantiate_canonical_state( - infcx, - span, - param_env, - &mut orig_values, - impl_args, - ); - - let () = instantiate_canonical_state( - infcx, - span, - param_env, - &mut orig_values, - self.final_state, - ); - - return eager_resolve_vars(&**infcx, impl_args); + let instantiate = || -> Result, NoSolution> { + let mut orig_values = self.goal.orig_values.clone(); + + for step in &self.steps { + match **step { + inspect::ProbeStep::RecordImplArgs { impl_args } => { + let impl_args = instantiate_canonical_state( + infcx, + span, + param_env, + &mut orig_values, + impl_args, + )?; + + let () = instantiate_canonical_state( + infcx, + span, + param_env, + &mut orig_values, + self.final_state, + )?; + + return Ok(impl_args); + } + inspect::ProbeStep::AddGoal(..) => {} + inspect::ProbeStep::MakeCanonicalResponse { .. } + | inspect::ProbeStep::NestedProbe(_) => unreachable!(), } - inspect::ProbeStep::AddGoal(..) => {} - inspect::ProbeStep::MakeCanonicalResponse { .. } - | inspect::ProbeStep::NestedProbe(_) => unreachable!(), } - } - bug!("expected impl args probe step for `instantiate_impl_args`"); + bug!("expected impl args probe step for `instantiate_impl_args`"); + }; + + let impl_args = infcx.commit_if_ok(|_| instantiate())?; + Ok(eager_resolve_vars(&**infcx, impl_args)) } pub fn instantiate_proof_tree_for_nested_goal( diff --git a/compiler/rustc_trait_selection/src/solve/select.rs b/compiler/rustc_trait_selection/src/solve/select.rs index b413b8b5ed9c7..fa4d990e86fe2 100644 --- a/compiler/rustc_trait_selection/src/solve/select.rs +++ b/compiler/rustc_trait_selection/src/solve/select.rs @@ -153,6 +153,7 @@ fn to_selection<'tcx>( Certainty::Yes => thin_vec![], Certainty::Maybe(_) => cand .instantiate_nested_goals(span) + .ok()? .into_iter() .map(|nested| { Obligation::new( @@ -172,7 +173,7 @@ fn to_selection<'tcx>( // For impl candidates, we do the rematch manually to compute the args. ImplSource::UserDefined(ImplSourceUserDefinedData { impl_def_id, - args: cand.instantiate_impl_args(span), + args: cand.instantiate_impl_args(span).ok()?, nested, }) } diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 75f906e498eda..9ca6a024f0b5d 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -463,6 +463,8 @@ pub trait InferCtxtLike: Sized { where T: TypeFoldable; + fn commit_if_ok(&self, f: impl FnOnce() -> Result) -> Result; + fn probe(&self, probe: impl FnOnce() -> T) -> T; fn sub_regions( diff --git a/compiler/rustc_type_ir/src/universe.rs b/compiler/rustc_type_ir/src/universe.rs index a5a4b2c02be89..8bb7bcb33a13e 100644 --- a/compiler/rustc_type_ir/src/universe.rs +++ b/compiler/rustc_type_ir/src/universe.rs @@ -13,7 +13,7 @@ pub fn max_universe, I: Interner, T: TypeFold infcx: &Infcx, t: T, ) -> UniverseIndex { - max_universe_inner::<_, _, _, true, true>(infcx, t) + max_universe_inner::<_, _, _, true, true, true>(infcx, t) } /// The largest universe a variable was from in `t` @@ -25,7 +25,7 @@ pub fn max_universe_of_infer_vars< infcx: &Infcx, t: T, ) -> UniverseIndex { - max_universe_inner::<_, _, _, false, true>(infcx, t) + max_universe_inner::<_, _, _, false, false, true>(infcx, t) } /// The largest universe a placeholder was from in `t` @@ -37,24 +37,50 @@ pub fn max_universe_of_placeholders< infcx: &Infcx, t: T, ) -> UniverseIndex { - max_universe_inner::<_, _, _, true, false>(infcx, t) + max_universe_inner::<_, _, _, true, true, false>(infcx, t) +} + +/// The largest universe a type or const placeholder was from in `t` +pub fn max_universe_of_non_region_placeholders< + Infcx: InferCtxtLike, + I: Interner, + T: TypeFoldable, +>( + infcx: &Infcx, + t: T, +) -> UniverseIndex { + max_universe_inner::<_, _, _, true, false, false>(infcx, t) } fn max_universe_inner< Infcx: InferCtxtLike, I: Interner, T: TypeFoldable, - const VISIT_PLACEHOLDER: bool, + const VISIT_NON_REGION_PLACEHOLDER: bool, + const VISIT_REGION_PLACEHOLDER: bool, const VISIT_INFER: bool, >( infcx: &Infcx, t: T, ) -> UniverseIndex { - if !MaxUniverse::::needs_visit(&t) { + if !MaxUniverse::< + Infcx, + I, + VISIT_NON_REGION_PLACEHOLDER, + VISIT_REGION_PLACEHOLDER, + VISIT_INFER, + >::needs_visit(&t) + { return UniverseIndex::ROOT; } - let mut visitor = MaxUniverse::<_, _, VISIT_PLACEHOLDER, VISIT_INFER>::new(infcx); + let mut visitor = MaxUniverse::< + _, + _, + VISIT_NON_REGION_PLACEHOLDER, + VISIT_REGION_PLACEHOLDER, + VISIT_INFER, + >::new(infcx); // FIXME: make this a debug_assert and let callers resolve vars. Then the input only needs to // be `TypeVisitable`. let t = infcx.resolve_vars_if_possible(t); @@ -66,7 +92,8 @@ struct MaxUniverse< 'a, Infcx: InferCtxtLike, I: Interner, - const VISIT_PLACEHOLDER: bool, + const VISIT_NON_REGION_PLACEHOLDER: bool, + const VISIT_REGION_PLACEHOLDER: bool, const VISIT_INFER: bool, > { max_universe: UniverseIndex, @@ -78,9 +105,10 @@ impl< 'a, Infcx: InferCtxtLike, I: Interner, - const VISIT_PLACEHOLDER: bool, + const VISIT_NON_REGION_PLACEHOLDER: bool, + const VISIT_REGION_PLACEHOLDER: bool, const VISIT_INFER: bool, -> MaxUniverse<'a, Infcx, I, VISIT_PLACEHOLDER, VISIT_INFER> +> MaxUniverse<'a, Infcx, I, VISIT_NON_REGION_PLACEHOLDER, VISIT_REGION_PLACEHOLDER, VISIT_INFER> { fn new(infcx: &'a Infcx) -> Self { MaxUniverse { infcx, max_universe: UniverseIndex::ROOT, cache: Default::default() } @@ -92,7 +120,8 @@ impl< #[instrument(ret, level = "debug")] fn needs_visit>(t: &T) -> bool { - (VISIT_PLACEHOLDER && t.has_placeholders()) || (VISIT_INFER && t.has_infer()) + ((VISIT_NON_REGION_PLACEHOLDER || VISIT_REGION_PLACEHOLDER) && t.has_placeholders()) + || (VISIT_INFER && t.has_infer()) } } @@ -100,9 +129,18 @@ impl< 'a, Infcx: InferCtxtLike, I: Interner, - const VISIT_PLACEHOLDER: bool, + const VISIT_NON_REGION_PLACEHOLDER: bool, + const VISIT_REGION_PLACEHOLDER: bool, const VISIT_INFER: bool, -> TypeVisitor for MaxUniverse<'a, Infcx, I, VISIT_PLACEHOLDER, VISIT_INFER> +> TypeVisitor + for MaxUniverse< + 'a, + Infcx, + I, + VISIT_NON_REGION_PLACEHOLDER, + VISIT_REGION_PLACEHOLDER, + VISIT_INFER, + > { type Result = (); @@ -116,7 +154,7 @@ impl< } match t.kind() { - TyKind::Placeholder(p) if VISIT_PLACEHOLDER => { + TyKind::Placeholder(p) if VISIT_NON_REGION_PLACEHOLDER => { self.max_universe = self.max_universe.max(p.universe) } TyKind::Infer(InferTy::TyVar(inf)) if VISIT_INFER => { @@ -136,7 +174,7 @@ impl< } match c.kind() { - ConstKind::Placeholder(p) if VISIT_PLACEHOLDER => { + ConstKind::Placeholder(p) if VISIT_NON_REGION_PLACEHOLDER => { self.max_universe = self.max_universe.max(p.universe) } ConstKind::Infer(rustc_type_ir::InferConst::Var(inf)) if VISIT_INFER => { @@ -150,12 +188,12 @@ impl< fn visit_region(&mut self, r: Region) { match r.kind() { - RegionKind::RePlaceholder(p) if VISIT_PLACEHOLDER => { + RegionKind::RePlaceholder(p) if VISIT_REGION_PLACEHOLDER => { self.max_universe = self.max_universe.max(p.universe) } RegionKind::ReVar(var) if VISIT_INFER => { match self.infcx.opportunistic_resolve_lt_var(var).kind() { - RegionKind::RePlaceholder(p) if VISIT_PLACEHOLDER => { + RegionKind::RePlaceholder(p) if VISIT_REGION_PLACEHOLDER => { self.max_universe = self.max_universe.max(p.universe) } RegionKind::ReVar(var) if VISIT_INFER => { diff --git a/tests/ui/traits/next-solver/canonical/response-universe-lowering-hrtb.rs b/tests/ui/traits/next-solver/canonical/response-universe-lowering-hrtb.rs new file mode 100644 index 0000000000000..2e9b0073cc3d1 --- /dev/null +++ b/tests/ui/traits/next-solver/canonical/response-universe-lowering-hrtb.rs @@ -0,0 +1,51 @@ +//@ check-pass +//@ compile-flags: -Znext-solver=globally + +use std::marker::PhantomData; + +trait Lift { + type Lifted; +} + +trait Print

{} + +#[derive(Copy, Clone)] +struct Tcx<'tcx>(PhantomData<&'tcx ()>); + +#[derive(Copy, Clone)] +struct Region(I); + +struct Printer<'a, 'tcx>(PhantomData<(&'a (), &'tcx ())>); + +// Mirrors the higher-ranked blanket bound used by rustc's `IrPrint` implementation. +trait IrPrint { + fn print(value: &T); +} + +impl IrPrint for Tcx<'_> +where + T: Copy + for<'a, 'tcx> Lift, Lifted: Print>>, +{ + fn print(_: &T) {} +} + +impl<'from, 'tcx> Lift> for Region> { + type Lifted = Region>; +} + +impl<'a, 'tcx> Print> for Region> {} + +trait Interner: Copy + IrPrint> {} + +impl Interner for Tcx<'_> {} + +impl std::fmt::Display for Region { + fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + >>::print(self); + Ok(()) + } +} + +fn main() { + println!("{}", Region(Tcx(PhantomData))); +} diff --git a/tests/ui/traits/next-solver/canonical/response-universe-lowering.rs b/tests/ui/traits/next-solver/canonical/response-universe-lowering.rs new file mode 100644 index 0000000000000..3038032e83e3c --- /dev/null +++ b/tests/ui/traits/next-solver/canonical/response-universe-lowering.rs @@ -0,0 +1,58 @@ +//@ check-pass +//@ compile-flags: -Znext-solver + +fn unconstrained() -> T { + todo!() +} + +trait Relate {} + +struct Type(T); + +impl Relate> for T {} + +fn relate_types, U>(_: &T, _: &U) {} + +fn type_inference_var() { + let low_universe = unconstrained(); + + let bump: for<'a, 'b> fn(&'a (), &'b ()) = |_, _| (); + let _: for<'a> fn(&'a (), &'a ()) = bump; + + let high_universe = unconstrained(); + relate_types(&high_universe, &low_universe); + + let _: () = high_universe; + let _: Type<()> = low_universe; +} + +#[derive(Copy, Clone)] +struct Const; + +trait RelateConst {} + +impl RelateConst<{ N }> for Const {} + +fn relate_consts(_: Const, _: Const) +where + Const: RelateConst, +{ +} + +fn const_inference_var() { + let low_universe = Const::<_>; + + let bump: for<'a, 'b> fn(&'a (), &'b ()) = |_, _| (); + let _: for<'a> fn(&'a (), &'a ()) = bump; + + let high_universe = Const::<_>; + relate_consts(high_universe, low_universe); + + let _: Const<0> = high_universe; + let _: Const<0> = low_universe; +} + +fn main() { + type_inference_var(); + const_inference_var(); +} diff --git a/tests/ui/traits/non_lifetime_binders/canonical-response-placeholder-leak-issue-159704.rs b/tests/ui/traits/non_lifetime_binders/canonical-response-placeholder-leak-issue-159704.rs new file mode 100644 index 0000000000000..cf096b06398e1 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/canonical-response-placeholder-leak-issue-159704.rs @@ -0,0 +1,24 @@ +//@ compile-flags: -Znext-solver=globally + +#![feature(non_lifetime_binders)] +#![allow(incomplete_features, bare_trait_objects)] + +fn trivial() +where + for Fn(A, B): Fn(A, A) + 'static, + //~^ ERROR the size for values of type `A` cannot be known at compilation time + //~| ERROR the size for values of type `A` cannot be known at compilation time +{ +} + +fn caller() { + trivial(); + //~^ ERROR expected an `Fn(_, _)` closure + //~| ERROR type mismatch resolving `>::Output == ()` +} + +fn main() { + trivial(); + //~^ ERROR expected an `Fn(_, _)` closure + //~| ERROR type mismatch resolving `>::Output == ()` +} diff --git a/tests/ui/traits/non_lifetime_binders/canonical-response-placeholder-leak-issue-159704.stderr b/tests/ui/traits/non_lifetime_binders/canonical-response-placeholder-leak-issue-159704.stderr new file mode 100644 index 0000000000000..55971c6f9fbcf --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/canonical-response-placeholder-leak-issue-159704.stderr @@ -0,0 +1,100 @@ +error[E0277]: the size for values of type `A` cannot be known at compilation time + --> $DIR/canonical-response-placeholder-leak-issue-159704.rs:8:22 + | +LL | fn trivial() + | - this type parameter needs to be `Sized` +LL | where +LL | for Fn(A, B): Fn(A, A) + 'static, + | ^^^^^^^^ doesn't have a size known at compile-time + | + = note: required because it appears within the type `(A, A)` +note: required by an implicit `Sized` bound in `Fn` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - fn trivial() +LL + fn trivial() + | + +error[E0277]: the size for values of type `A` cannot be known at compilation time + --> $DIR/canonical-response-placeholder-leak-issue-159704.rs:8:33 + | +LL | fn trivial() + | - this type parameter needs to be `Sized` +LL | where +LL | for Fn(A, B): Fn(A, A) + 'static, + | ^^^^^^^ doesn't have a size known at compile-time + | + = note: only the last element of a tuple may have a dynamically sized type +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - fn trivial() +LL + fn trivial() + | + +error[E0277]: expected an `Fn(_, _)` closure, found `(dyn Fn(_, B) + 'static)` + --> $DIR/canonical-response-placeholder-leak-issue-159704.rs:15:5 + | +LL | trivial(); + | ^^^^^^^^^ expected an `Fn(_, _)` closure, found `(dyn Fn(_, B) + 'static)` + | + = help: the trait `Fn(_, _)` is not implemented for `(dyn Fn(_, B) + 'static)` +note: required by a bound in `trivial` + --> $DIR/canonical-response-placeholder-leak-issue-159704.rs:8:22 + | +LL | fn trivial() + | ------- required by a bound in this function +LL | where +LL | for Fn(A, B): Fn(A, A) + 'static, + | ^^^^^^^^ required by this bound in `trivial` + +error[E0271]: type mismatch resolving `>::Output == ()` + --> $DIR/canonical-response-placeholder-leak-issue-159704.rs:15:5 + | +LL | trivial(); + | ^^^^^^^^^ types differ + | +note: required by a bound in `trivial` + --> $DIR/canonical-response-placeholder-leak-issue-159704.rs:8:22 + | +LL | fn trivial() + | ------- required by a bound in this function +LL | where +LL | for Fn(A, B): Fn(A, A) + 'static, + | ^^^^^^^^ required by this bound in `trivial` + +error[E0277]: expected an `Fn(_, _)` closure, found `(dyn Fn(_, B) + 'static)` + --> $DIR/canonical-response-placeholder-leak-issue-159704.rs:21:5 + | +LL | trivial(); + | ^^^^^^^^^ expected an `Fn(_, _)` closure, found `(dyn Fn(_, B) + 'static)` + | + = help: the trait `Fn(_, _)` is not implemented for `(dyn Fn(_, B) + 'static)` +note: required by a bound in `trivial` + --> $DIR/canonical-response-placeholder-leak-issue-159704.rs:8:22 + | +LL | fn trivial() + | ------- required by a bound in this function +LL | where +LL | for Fn(A, B): Fn(A, A) + 'static, + | ^^^^^^^^ required by this bound in `trivial` + +error[E0271]: type mismatch resolving `>::Output == ()` + --> $DIR/canonical-response-placeholder-leak-issue-159704.rs:21:5 + | +LL | trivial(); + | ^^^^^^^^^ types differ + | +note: required by a bound in `trivial` + --> $DIR/canonical-response-placeholder-leak-issue-159704.rs:8:22 + | +LL | fn trivial() + | ------- required by a bound in this function +LL | where +LL | for Fn(A, B): Fn(A, A) + 'static, + | ^^^^^^^^ required by this bound in `trivial` + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0271, E0277. +For more information about an error, try `rustc --explain E0271`.