From eabd1a65bec975c272819fbc1bd1ba9ef536561e Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 19 Dec 2023 08:20:24 +0100 Subject: [PATCH] new solver: make apply query response infallible For this we have to provide the necessary information when canonicalizing the input, guaranteeing that if the canonical query successfully instantiates some inference variable, it will also succeed in the caller. This means we have to not merge universes in the canonical input. --- compiler/rustc_infer/src/infer/mod.rs | 2 +- .../rustc_infer/src/infer/relate/combine.rs | 12 +- .../src/infer/relate/generalize.rs | 6 + .../src/infer/relate/instantiate_unchecked.rs | 266 ++++++++++++++++++ compiler/rustc_infer/src/infer/relate/mod.rs | 1 + .../rustc_middle/src/traits/solve/inspect.rs | 2 - .../src/traits/solve/inspect/format.rs | 15 +- .../src/canonicalizer.rs | 28 +- .../src/solve/eval_ctxt/canonical.rs | 60 ++-- .../src/solve/eval_ctxt/mod.rs | 55 ++-- .../src/solve/eval_ctxt/select.rs | 50 ++-- .../src/solve/fulfill.rs | 25 +- .../src/solve/inspect/analyse.rs | 14 +- .../src/solve/inspect/build.rs | 14 - .../generalize-proj-new-universe-index-2.rs | 4 +- ...eneralize-proj-new-universe-index-2.stderr | 19 -- ...tantiate-canonical-occurs-check-failure.rs | 29 ++ .../occurs-check-nested-alias.next.stderr | 2 +- .../generalize/occurs-check-nested-alias.rs | 6 +- .../issue-118950-root-region.stderr | 2 + 20 files changed, 405 insertions(+), 207 deletions(-) create mode 100644 compiler/rustc_infer/src/infer/relate/instantiate_unchecked.rs delete mode 100644 tests/ui/traits/next-solver/generalize/generalize-proj-new-universe-index-2.stderr create mode 100644 tests/ui/traits/next-solver/generalize/instantiate-canonical-occurs-check-failure.rs diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 1eab8575fc0c4..4816f8f8796c6 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -67,7 +67,7 @@ pub mod opaque_types; pub mod outlives; mod projection; pub mod region_constraints; -mod relate; +pub mod relate; pub mod resolve; pub mod type_variable; mod undo_log; diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs index 1c120646f1f90..126985d8bd5d3 100644 --- a/compiler/rustc_infer/src/infer/relate/combine.rs +++ b/compiler/rustc_infer/src/infer/relate/combine.rs @@ -335,7 +335,7 @@ impl<'tcx> InferCtxt<'tcx> { Ok(value) } - fn unify_integral_variable( + pub(super) fn unify_integral_variable( &self, vid_is_expected: bool, vid: ty::IntVid, @@ -352,7 +352,7 @@ impl<'tcx> InferCtxt<'tcx> { } } - fn unify_float_variable( + pub(super) fn unify_float_variable( &self, vid_is_expected: bool, vid: ty::FloatVid, @@ -366,7 +366,7 @@ impl<'tcx> InferCtxt<'tcx> { Ok(Ty::new_float(self.tcx, val)) } - fn unify_effect_variable( + pub(super) fn unify_effect_variable( &self, vid_is_expected: bool, vid: ty::EffectVid, @@ -564,7 +564,7 @@ pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> { fn alias_relate_direction(&self) -> ty::AliasRelationDirection; } -fn int_unification_error<'tcx>( +pub(super) fn int_unification_error<'tcx>( a_is_expected: bool, v: (ty::IntVarValue, ty::IntVarValue), ) -> TypeError<'tcx> { @@ -572,7 +572,7 @@ fn int_unification_error<'tcx>( TypeError::IntMismatch(ExpectedFound::new(a_is_expected, a, b)) } -fn float_unification_error<'tcx>( +pub(super) fn float_unification_error<'tcx>( a_is_expected: bool, v: (ty::FloatVarValue, ty::FloatVarValue), ) -> TypeError<'tcx> { @@ -580,7 +580,7 @@ fn float_unification_error<'tcx>( TypeError::FloatMismatch(ExpectedFound::new(a_is_expected, a, b)) } -fn effect_unification_error<'tcx>( +pub(super) fn effect_unification_error<'tcx>( _tcx: TyCtxt<'tcx>, _a_is_expected: bool, (_a, _b): (EffectVarValue<'tcx>, EffectVarValue<'tcx>), diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 417c8695e248b..6e981493ce303 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -269,6 +269,8 @@ where ty::Invariant => { if self.for_universe.can_name(universe) { return Ok(t); + } else if self.infcx.next_trait_solver() && self.in_alias { + return Err(TypeError::Mismatch); } } @@ -400,6 +402,8 @@ where let r_universe = self.infcx.universe_of_region(r); if self.for_universe.can_name(r_universe) { return Ok(r); + } else if self.infcx.next_trait_solver() && self.in_alias { + return Err(TypeError::Mismatch); } } @@ -439,6 +443,8 @@ where ConstVariableValue::Unknown { origin, universe } => { if self.for_universe.can_name(universe) { Ok(c) + } else if self.infcx.next_trait_solver() && self.in_alias { + return Err(TypeError::Mismatch); } else { let new_var_id = variable_table .new_key(ConstVariableValue::Unknown { diff --git a/compiler/rustc_infer/src/infer/relate/instantiate_unchecked.rs b/compiler/rustc_infer/src/infer/relate/instantiate_unchecked.rs new file mode 100644 index 0000000000000..c9c66fdcacc11 --- /dev/null +++ b/compiler/rustc_infer/src/infer/relate/instantiate_unchecked.rs @@ -0,0 +1,266 @@ +use super::combine::{float_unification_error, int_unification_error}; +use crate::infer::{InferCtxt, SubregionOrigin, TypeTrace, ValuePairs}; + +use rustc_middle::infer::unify_key::{ConstVariableValue, EffectVarValue}; +use rustc_middle::traits::ObligationCause; +use rustc_middle::ty::error::ExpectedFound; +use rustc_middle::ty::relate::{self, structurally_relate_tys, Relate, RelateResult, TypeRelation}; +use rustc_middle::ty::visit::MaxUniverse; +use rustc_middle::ty::IntVarValue::{IntType, UintType}; +use rustc_middle::ty::TypeVisitable; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{GenericArgsRef, InferConst}; +use rustc_middle::ty::{InferCtxtLike, TyVar}; + +use rustc_hir::def_id::DefId; + +/// A visitor to instantiate inference variables assuming that the +/// instantiation will definitely succeed. +/// +/// Using this in places where that may not be the case can easily +/// result in bugs or unsoudness. Used when instantiating a canonical +/// response in the new solver. +/// +/// Unlike `Equate` this always structurally relates aliases, meaning +/// it always succeeds without emitting any nested obligations. +pub struct InstantiateUnchecked<'a, 'tcx> { + infcx: &'a InferCtxt<'tcx>, + cause: &'a ObligationCause<'tcx>, +} + +impl<'a, 'tcx> InstantiateUnchecked<'a, 'tcx> { + pub fn new( + infcx: &'a InferCtxt<'tcx>, + cause: &'a ObligationCause<'tcx>, + ) -> InstantiateUnchecked<'a, 'tcx> { + InstantiateUnchecked { infcx, cause } + } + + /// Used by debug assertions to detect some unsound uses of this + /// visitor. + fn infer_var_can_name>>( + &self, + universe_of_infer: ty::UniverseIndex, + value: T, + ) -> bool { + let mut visitor = MaxUniverse::new(); + value.visit_with(&mut visitor); + universe_of_infer.can_name(visitor.max_universe()) + } +} + +impl<'tcx> TypeRelation<'tcx> for InstantiateUnchecked<'_, 'tcx> { + fn tag(&self) -> &'static str { + "InstantiateUnchecked" + } + + fn tcx(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn a_is_expected(&self) -> bool { + true + } + + fn relate_item_args( + &mut self, + _item_def_id: DefId, + a_arg: GenericArgsRef<'tcx>, + b_arg: GenericArgsRef<'tcx>, + ) -> RelateResult<'tcx, GenericArgsRef<'tcx>> { + relate::relate_args_invariantly(self, a_arg, b_arg) + } + + fn relate_with_variance>( + &mut self, + _: ty::Variance, + _info: ty::VarianceDiagInfo<'tcx>, + a: T, + b: T, + ) -> RelateResult<'tcx, T> { + self.relate(a, b) + } + + #[instrument(skip(self), level = "debug")] + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + if a == b { + return Ok(a); + } + + let infcx = self.infcx; + let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a); + let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b); + + // This is pretty much a copy of `Equate::tys` and `fn super_combine_consts`. + // We cannot use these directly as they emit `AliasRelate` goals when + // relate aliases. + match (a.kind(), b.kind()) { + (&ty::Infer(TyVar(a_vid)), &ty::Infer(TyVar(b_vid))) => { + infcx.inner.borrow_mut().type_variables().equate(a_vid, b_vid); + Ok(a) + } + + (&ty::Infer(TyVar(a_vid)), _) => { + debug_assert!(self.infer_var_can_name(infcx.universe_of_ty(a_vid).unwrap(), b)); + infcx.inner.borrow_mut().type_variables().instantiate(a_vid, b); + Ok(b) + } + + (_, &ty::Infer(TyVar(b_vid))) => { + debug_assert!(self.infer_var_can_name(infcx.universe_of_ty(b_vid).unwrap(), a)); + infcx.inner.borrow_mut().type_variables().instantiate(b_vid, a); + Ok(a) + } + + (&ty::Infer(ty::IntVar(a_vid)), &ty::Infer(ty::IntVar(b_vid))) => { + infcx + .inner + .borrow_mut() + .int_unification_table() + .unify_var_var(a_vid, b_vid) + .map_err(|e| int_unification_error(true, e))?; + Ok(a) + } + (&ty::Infer(ty::IntVar(v_id)), &ty::Int(v)) => { + infcx.unify_integral_variable(true, v_id, IntType(v)) + } + (&ty::Int(v), &ty::Infer(ty::IntVar(v_id))) => { + infcx.unify_integral_variable(false, v_id, IntType(v)) + } + (&ty::Infer(ty::IntVar(v_id)), &ty::Uint(v)) => { + infcx.unify_integral_variable(true, v_id, UintType(v)) + } + (&ty::Uint(v), &ty::Infer(ty::IntVar(v_id))) => { + infcx.unify_integral_variable(false, v_id, UintType(v)) + } + + // Relate floating-point variables to other types + (&ty::Infer(ty::FloatVar(a_vid)), &ty::Infer(ty::FloatVar(b_vid))) => { + infcx + .inner + .borrow_mut() + .float_unification_table() + .unify_var_var(a_vid, b_vid) + .map_err(|e| float_unification_error(true, e))?; + Ok(a) + } + (&ty::Infer(ty::FloatVar(v_id)), &ty::Float(v)) => { + infcx.unify_float_variable(true, v_id, v) + } + (&ty::Float(v), &ty::Infer(ty::FloatVar(v_id))) => { + infcx.unify_float_variable(false, v_id, v) + } + + _ => structurally_relate_tys(self, a, b), + } + } + + fn regions( + &mut self, + a: ty::Region<'tcx>, + b: ty::Region<'tcx>, + ) -> RelateResult<'tcx, ty::Region<'tcx>> { + debug!("{}.regions({:?}, {:?})", self.tag(), a, b); + let origin = SubregionOrigin::Subtype(Box::new(TypeTrace { + cause: self.cause.clone(), + values: ValuePairs::Regions(ExpectedFound::new(true, a, b)), + })); + self.infcx.inner.borrow_mut().unwrap_region_constraints().make_eqregion(origin, a, b); + Ok(a) + } + + fn consts( + &mut self, + a: ty::Const<'tcx>, + b: ty::Const<'tcx>, + ) -> RelateResult<'tcx, ty::Const<'tcx>> { + let infcx = self.infcx; + let a = infcx.shallow_resolve(a); + let b = infcx.shallow_resolve(b); + match (a.kind(), b.kind()) { + ( + ty::ConstKind::Infer(InferConst::Var(a_vid)), + ty::ConstKind::Infer(InferConst::Var(b_vid)), + ) => { + infcx.inner.borrow_mut().const_unification_table().union(a_vid, b_vid); + Ok(a) + } + + ( + ty::ConstKind::Infer(InferConst::EffectVar(a_vid)), + ty::ConstKind::Infer(InferConst::EffectVar(b_vid)), + ) => { + infcx + .inner + .borrow_mut() + .effect_unification_table() + .unify_var_var(a_vid, b_vid) + .map_err(|_| bug!("unexpected error"))?; + Ok(a) + } + + // All other cases of inference with other variables are errors. + ( + ty::ConstKind::Infer(InferConst::Var(_) | InferConst::EffectVar(_)), + ty::ConstKind::Infer(_), + ) + | ( + ty::ConstKind::Infer(_), + ty::ConstKind::Infer(InferConst::Var(_) | InferConst::EffectVar(_)), + ) => { + bug!( + "tried to combine ConstKind::Infer/ConstKind::Infer(InferConst::Var): {a:?} and {b:?}" + ) + } + + (ty::ConstKind::Infer(InferConst::Var(a_vid)), _) => { + debug_assert!(self.infer_var_can_name(infcx.universe_of_ct(a_vid).unwrap(), b)); + infcx + .inner + .borrow_mut() + .const_unification_table() + .union_value(a_vid, ConstVariableValue::Known { value: b }); + Ok(b) + } + + (_, ty::ConstKind::Infer(InferConst::Var(b_vid))) => { + debug_assert!(self.infer_var_can_name(infcx.universe_of_ct(b_vid).unwrap(), a)); + infcx + .inner + .borrow_mut() + .const_unification_table() + .union_value(b_vid, ConstVariableValue::Known { value: a }); + Ok(a) + } + + (ty::ConstKind::Infer(InferConst::EffectVar(vid)), _) => { + infcx.unify_effect_variable(true, vid, EffectVarValue::Const(b)) + } + + (_, ty::ConstKind::Infer(InferConst::EffectVar(vid))) => { + infcx.unify_effect_variable(false, vid, EffectVarValue::Const(a)) + } + + _ => ty::relate::structurally_relate_consts(self, a, b), + } + } + + fn binders( + &mut self, + a: ty::Binder<'tcx, T>, + b: ty::Binder<'tcx, T>, + ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> + where + T: Relate<'tcx>, + { + // A binder is equal to itself if it's structurally equal to itself + if a != b { + assert_eq!(a.bound_vars(), b.bound_vars()); + let (a, b) = self + .infcx + .instantiate_binder_with_placeholders(a.map_bound(|a| (a, b.skip_binder()))); + self.relate(a, b)?; + } + Ok(a) + } +} diff --git a/compiler/rustc_infer/src/infer/relate/mod.rs b/compiler/rustc_infer/src/infer/relate/mod.rs index f688c2b74a6d2..c4838e80f9354 100644 --- a/compiler/rustc_infer/src/infer/relate/mod.rs +++ b/compiler/rustc_infer/src/infer/relate/mod.rs @@ -6,6 +6,7 @@ mod equate; pub(super) mod generalize; mod glb; mod higher_ranked; +pub mod instantiate_unchecked; mod lattice; mod lub; pub mod nll; diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs index e94ad4aa539b6..90180af3b167f 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect.rs @@ -58,8 +58,6 @@ pub struct GoalEvaluation<'tcx> { pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>, pub kind: GoalEvaluationKind<'tcx>, pub evaluation: CanonicalGoalEvaluation<'tcx>, - /// The nested goals from instantiating the query response. - pub returned_goals: Vec>>, } #[derive(Eq, PartialEq)] diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs index 54db8dbd33606..89c5eb517e565 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs @@ -48,20 +48,7 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> { }, }; writeln!(self.f, "{}: {:?}", goal_text, eval.uncanonicalized_goal)?; - self.nested(|this| this.format_canonical_goal_evaluation(&eval.evaluation))?; - if eval.returned_goals.len() > 0 { - writeln!(self.f, "NESTED GOALS ADDED TO CALLER: [")?; - self.nested(|this| { - for goal in eval.returned_goals.iter() { - writeln!(this.f, "ADDED GOAL: {goal:?},")?; - } - Ok(()) - })?; - - writeln!(self.f, "]") - } else { - Ok(()) - } + self.nested(|this| this.format_canonical_goal_evaluation(&eval.evaluation)) } pub(super) fn format_canonical_goal_evaluation( diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index db1aee1190359..914665ac545c5 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -107,21 +107,22 @@ impl<'a, Infcx: InferCtxtLike, I: Interner> Canonicalizer<'a, Infc // universes `n`, this algorithm compresses them in place so that: // // - the new universe indices are as small as possible - // - we only create a new universe if we would otherwise put a placeholder in - // the same compressed universe as an existential which cannot name it + // - we create a new universe if we would otherwise + // 1. put existentials from a different universe into the same one + // 2. put a placeholder in the same universe as an existential which cannot name it // // Let's walk through an example: // - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 0 // - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 1 // - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 1, next_orig_uv: 2 // - var_infos: [E0, U1, E5, U1, E1, E6, U6], curr_compressed_uv: 1, next_orig_uv: 5 - // - var_infos: [E0, U1, E1, U1, E1, E6, U6], curr_compressed_uv: 1, next_orig_uv: 6 - // - var_infos: [E0, U1, E1, U1, E1, E2, U2], curr_compressed_uv: 2, next_orig_uv: - + // - var_infos: [E0, U1, E2, U1, E1, E6, U6], curr_compressed_uv: 2, next_orig_uv: 6 + // - var_infos: [E0, U1, E1, U1, E1, E3, U3], curr_compressed_uv: 2, next_orig_uv: - // // This algorithm runs in `O(n²)` where `n` is the number of different universe // indices in the input. This should be fine as `n` is expected to be small. let mut curr_compressed_uv = ty::UniverseIndex::ROOT; - let mut existential_in_new_uv = false; + let mut existential_in_new_uv = None; let mut next_orig_uv = Some(ty::UniverseIndex::ROOT); while let Some(orig_uv) = next_orig_uv.take() { let mut update_uv = |var: &mut CanonicalVarInfo, orig_uv, is_existential| { @@ -130,14 +131,25 @@ impl<'a, Infcx: InferCtxtLike, I: Interner> Canonicalizer<'a, Infc Ordering::Less => (), // Already updated Ordering::Equal => { if is_existential { - existential_in_new_uv = true; - } else if existential_in_new_uv { + if existential_in_new_uv.is_some_and(|uv| uv < orig_uv) { + // Condition 1. + // + // We already put an existential from a outer universe + // into the current compressed universe, so we need to + // create a new one. + curr_compressed_uv = curr_compressed_uv.next_universe(); + } + + existential_in_new_uv = next_orig_uv; + } else if existential_in_new_uv.is_some() { + // Condition 2. + // // `var` is a placeholder from a universe which is not nameable // by an existential which we already put into the compressed // universe `curr_compressed_uv`. We therefore have to create a // new universe for `var`. curr_compressed_uv = curr_compressed_uv.next_universe(); - existential_in_new_uv = false; + existential_in_new_uv = None; } *var = var.with_updated_universe(curr_compressed_uv); 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 ecdae2521b933..e5d82daa091a8 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -17,14 +17,16 @@ use rustc_index::IndexVec; use rustc_infer::infer::canonical::query_response::make_query_region_constraints; use rustc_infer::infer::canonical::CanonicalVarValues; use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints}; +use rustc_infer::infer::relate::instantiate_unchecked::InstantiateUnchecked; use rustc_infer::infer::resolve::EagerResolver; -use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; +use rustc_infer::infer::InferCtxt; use rustc_middle::infer::canonical::Canonical; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{ ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput, }; use rustc_middle::traits::ObligationCause; +use rustc_middle::ty::relate::Relate; use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable}; use rustc_next_trait_solver::canonicalizer::{CanonicalizeMode, Canonicalizer}; use rustc_span::DUMMY_SP; @@ -191,22 +193,20 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { param_env: ty::ParamEnv<'tcx>, original_values: Vec>, response: CanonicalResponse<'tcx>, - ) -> Result<(Certainty, Vec>>), NoSolution> { + ) -> Certainty { let substitution = Self::compute_query_response_substitution(self.infcx, &original_values, &response); let Response { var_values, external_constraints, certainty } = response.substitute(self.tcx(), &substitution); - let nested_goals = - Self::unify_query_var_values(self.infcx, param_env, &original_values, var_values)?; + Self::unify_query_var_values(self.infcx, &original_values, var_values); let ExternalConstraintsData { region_constraints, opaque_types } = external_constraints.deref(); self.register_region_constraints(region_constraints); - self.register_opaque_types(param_env, opaque_types)?; - - Ok((certainty, nested_goals)) + self.register_new_opaque_types(param_env, opaque_types); + certainty } /// This returns the substitutions to instantiate the bound variables of @@ -293,32 +293,19 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { CanonicalVarValues { var_values } } - #[instrument(level = "debug", skip(infcx, param_env), ret)] + #[instrument(level = "debug", skip(infcx), ret)] fn unify_query_var_values( infcx: &InferCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, original_values: &[ty::GenericArg<'tcx>], var_values: CanonicalVarValues<'tcx>, - ) -> Result>>, NoSolution> { + ) { assert_eq!(original_values.len(), var_values.len()); - let mut nested_goals = vec![]; + let cause = ObligationCause::dummy(); + let mut rel = InstantiateUnchecked::new(infcx, &cause); for (&orig, response) in iter::zip(original_values, var_values.var_values) { - nested_goals.extend( - infcx - .at(&ObligationCause::dummy(), param_env) - .eq(DefineOpaqueTypes::No, orig, response) - .map(|InferOk { value: (), obligations }| { - obligations.into_iter().map(|o| Goal::from(o)) - }) - .map_err(|e| { - debug!(?e, "failed to equate"); - NoSolution - })?, - ); + ty::GenericArg::relate(&mut rel, orig, response).unwrap(); } - - Ok(nested_goals) } fn register_region_constraints(&mut self, region_constraints: &QueryRegionConstraints<'tcx>) { @@ -330,21 +317,17 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } - for member_constraint in ®ion_constraints.member_constraints { - // FIXME: Deal with member constraints :< - let _ = member_constraint; - } + assert!(region_constraints.member_constraints.is_empty()); } - fn register_opaque_types( + fn register_new_opaque_types( &mut self, param_env: ty::ParamEnv<'tcx>, opaque_types: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)], - ) -> Result<(), NoSolution> { + ) { for &(key, ty) in opaque_types { - self.insert_hidden_type(key, param_env, ty)?; + self.insert_hidden_type(key, param_env, ty).unwrap(); } - Ok(()) } } @@ -363,19 +346,20 @@ impl<'tcx> inspect::ProofTreeBuilder<'tcx> { ) } + /// Instantiate a `CanonicalState`. This assumes that unifying the var values + /// trivially succeeds. Adding any inference constraints which weren't present when + /// originally computing the canonical query can result in bugs. pub fn instantiate_canonical_state>>( infcx: &InferCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, original_values: &[ty::GenericArg<'tcx>], state: inspect::CanonicalState<'tcx, T>, - ) -> Result<(Vec>>, T), NoSolution> { + ) -> T { let substitution = EvalCtxt::compute_query_response_substitution(infcx, original_values, &state); let inspect::State { var_values, data } = state.substitute(infcx.tcx, &substitution); - let nested_goals = - EvalCtxt::unify_query_var_values(infcx, param_env, original_values, var_values)?; - Ok((nested_goals, data)) + EvalCtxt::unify_query_var_values(infcx, original_values, var_values); + data } } 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 76c50a111027d..5923badfaf56d 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -140,10 +140,7 @@ pub trait InferCtxtEvalExt<'tcx> { &self, goal: Goal<'tcx, ty::Predicate<'tcx>>, generate_proof_tree: GenerateProofTree, - ) -> ( - Result<(bool, Certainty, Vec>>), NoSolution>, - Option>, - ); + ) -> (Result<(bool, Certainty), NoSolution>, Option>); } impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { @@ -152,10 +149,7 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { &self, goal: Goal<'tcx, ty::Predicate<'tcx>>, generate_proof_tree: GenerateProofTree, - ) -> ( - Result<(bool, Certainty, Vec>>), NoSolution>, - Option>, - ) { + ) -> (Result<(bool, Certainty), NoSolution>, Option>) { EvalCtxt::enter_root(self, generate_proof_tree, |ecx| { ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal) }) @@ -337,7 +331,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { goal_evaluation_kind: GoalEvaluationKind, source: GoalSource, goal: Goal<'tcx, ty::Predicate<'tcx>>, - ) -> Result<(bool, Certainty, Vec>>), NoSolution> { + ) -> Result<(bool, Certainty), NoSolution> { let (orig_values, canonical_goal) = self.canonicalize_goal(goal); let mut goal_evaluation = self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind); @@ -355,26 +349,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { Ok(response) => response, }; - let (certainty, has_changed, nested_goals) = match self - .instantiate_response_discarding_overflow( - goal.param_env, - source, - orig_values, - canonical_response, - ) { - Err(e) => { - self.inspect.goal_evaluation(goal_evaluation); - return Err(e); - } - Ok(response) => response, - }; - goal_evaluation.returned_goals(&nested_goals); + let (certainty, has_changed) = self.instantiate_response_discarding_overflow( + goal.param_env, + source, + orig_values, + canonical_response, + ); self.inspect.goal_evaluation(goal_evaluation); - - if !has_changed && !nested_goals.is_empty() { - bug!("an unchanged goal shouldn't have any side-effects on instantiation"); - } - // FIXME: We previously had an assert here that checked that recomputing // a goal after applying its constraints did not change its response. // @@ -385,7 +366,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { // Once we have decided on how to handle trait-system-refactor-initiative#75, // we should re-add an assert here. - Ok((has_changed, certainty, nested_goals)) + Ok((has_changed, certainty)) } fn instantiate_response_discarding_overflow( @@ -394,7 +375,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { source: GoalSource, original_values: Vec>, response: CanonicalResponse<'tcx>, - ) -> Result<(Certainty, bool, Vec>>), NoSolution> { + ) -> (Certainty, bool) { // The old solver did not evaluate nested goals when normalizing. // It returned the selection constraints allowing a `Projection` // obligation to not hold in coherence while avoiding the fatal error @@ -415,14 +396,14 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { }; if response.value.certainty == Certainty::OVERFLOW && !keep_overflow_constraints() { - Ok((Certainty::OVERFLOW, false, Vec::new())) + (Certainty::OVERFLOW, false) } else { let has_changed = !response.value.var_values.is_identity_modulo_regions() || !response.value.external_constraints.opaque_types.is_empty(); - let (certainty, nested_goals) = - self.instantiate_and_apply_query_response(param_env, original_values, response)?; - Ok((certainty, has_changed, nested_goals)) + let certainty = + self.instantiate_and_apply_query_response(param_env, original_values, response); + (certainty, has_changed) } } @@ -546,12 +527,11 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { ty::NormalizesTo { alias: goal.predicate.alias, term: unconstrained_rhs }, ); - let (_, certainty, instantiate_goals) = self.evaluate_goal( + let (_, certainty) = self.evaluate_goal( GoalEvaluationKind::Nested { is_normalizes_to_hack: IsNormalizesToHack::Yes }, GoalSource::Misc, unconstrained_goal, )?; - self.nested_goals.goals.extend(with_misc_source(instantiate_goals)); // Finally, equate the goal's RHS with the unconstrained var. // We put the nested goals from this into goals instead of @@ -582,12 +562,11 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } for (source, goal) in goals.goals.drain(..) { - let (has_changed, certainty, instantiate_goals) = self.evaluate_goal( + let (has_changed, certainty) = self.evaluate_goal( GoalEvaluationKind::Nested { is_normalizes_to_hack: IsNormalizesToHack::No }, source, goal, )?; - self.nested_goals.goals.extend(with_misc_source(instantiate_goals)); if has_changed { unchanged_certainty = None; } 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 315df06be417c..7b904af9102a8 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs @@ -67,37 +67,26 @@ impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> { } let candidate = candidates.pop().unwrap(); - let (certainty, nested_goals) = ecx - .instantiate_and_apply_query_response( - trait_goal.param_env, - orig_values, - candidate.result, - ) - .map_err(|_| SelectionError::Unimplemented)?; + let certainty = ecx.instantiate_and_apply_query_response( + trait_goal.param_env, + orig_values, + candidate.result, + ); - Ok(Some((candidate, certainty, nested_goals))) + Ok(Some((candidate, certainty))) }); - let (candidate, certainty, nested_goals) = match result { - Ok(Some((candidate, certainty, nested_goals))) => (candidate, certainty, nested_goals), + let (candidate, certainty) = match result { + Ok(Some((candidate, certainty))) => (candidate, certainty), Ok(None) => return Ok(None), Err(e) => return Err(e), }; - let nested_obligations: Vec<_> = nested_goals - .into_iter() - .map(|goal| { - Obligation::new(self.tcx, ObligationCause::dummy(), goal.param_env, goal.predicate) - }) - .collect(); - let goal = self.resolve_vars_if_possible(trait_goal); match (certainty, candidate.source) { // Rematching the implementation will instantiate the same nested goals that // would have caused the ambiguity, so we can still make progress here regardless. - (_, CandidateSource::Impl(def_id)) => { - rematch_impl(self, goal, def_id, nested_obligations) - } + (_, CandidateSource::Impl(def_id)) => rematch_impl(self, goal, def_id), // If an unsize goal is ambiguous, then we can manually rematch it to make // selection progress for coercion during HIR typeck. If it is *not* ambiguous, @@ -110,20 +99,20 @@ impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> { | (Certainty::Yes, CandidateSource::BuiltinImpl(src @ BuiltinImplSource::Misc)) if self.tcx.lang_items().unsize_trait() == Some(goal.predicate.def_id()) => { - rematch_unsize(self, goal, nested_obligations, src, certainty) + rematch_unsize(self, goal, src, certainty) } // Technically some builtin impls have nested obligations, but if // `Certainty::Yes`, then they should've all been verified and don't // need re-checking. (Certainty::Yes, CandidateSource::BuiltinImpl(src)) => { - Ok(Some(ImplSource::Builtin(src, nested_obligations))) + Ok(Some(ImplSource::Builtin(src, Vec::new()))) } // It's fine not to do anything to rematch these, since there are no // nested obligations. (Certainty::Yes, CandidateSource::ParamEnv(_) | CandidateSource::AliasBound) => { - Ok(Some(ImplSource::Param(nested_obligations))) + Ok(Some(ImplSource::Param(Vec::new()))) } (Certainty::Maybe(_), _) => Ok(None), @@ -193,19 +182,16 @@ fn rematch_impl<'tcx>( infcx: &InferCtxt<'tcx>, goal: Goal<'tcx, ty::TraitPredicate<'tcx>>, impl_def_id: DefId, - mut nested: Vec>, ) -> SelectionResult<'tcx, Selection<'tcx>> { let args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id); let impl_trait_ref = infcx.tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(infcx.tcx, args); - nested.extend( - infcx - .at(&ObligationCause::dummy(), goal.param_env) - .eq(DefineOpaqueTypes::No, goal.predicate.trait_ref, impl_trait_ref) - .map_err(|_| SelectionError::Unimplemented)? - .into_obligations(), - ); + let mut nested = infcx + .at(&ObligationCause::dummy(), goal.param_env) + .eq(DefineOpaqueTypes::No, goal.predicate.trait_ref, impl_trait_ref) + .map_err(|_| SelectionError::Unimplemented)? + .into_obligations(); nested.extend( infcx.tcx.predicates_of(impl_def_id).instantiate(infcx.tcx, args).into_iter().map( @@ -222,11 +208,11 @@ fn rematch_impl<'tcx>( fn rematch_unsize<'tcx>( infcx: &InferCtxt<'tcx>, goal: Goal<'tcx, ty::TraitPredicate<'tcx>>, - mut nested: Vec>, source: BuiltinImplSource, certainty: Certainty, ) -> SelectionResult<'tcx, Selection<'tcx>> { let tcx = infcx.tcx; + let mut nested = vec![]; let a_ty = structurally_normalize(goal.predicate.self_ty(), infcx, goal.param_env, &mut nested); let b_ty = structurally_normalize( goal.predicate.trait_ref.args.type_at(1), diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index f08622816ec28..0f73636f47502 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -2,7 +2,6 @@ use std::mem; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::solve::MaybeCause; -use rustc_infer::traits::Obligation; use rustc_infer::traits::{ query::NoSolution, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, PredicateObligation, SelectionError, TraitEngine, @@ -11,7 +10,7 @@ use rustc_middle::ty; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use super::eval_ctxt::GenerateProofTree; -use super::{Certainty, Goal, InferCtxtEvalExt}; +use super::{Certainty, InferCtxtEvalExt}; /// A trait engine using the new trait solver. /// @@ -48,11 +47,11 @@ impl<'tcx> FulfillmentCtxt<'tcx> { &self, infcx: &InferCtxt<'tcx>, obligation: &PredicateObligation<'tcx>, - result: &Result<(bool, Certainty, Vec>>), NoSolution>, + result: &Result<(bool, Certainty), NoSolution>, ) { if let Some(inspector) = infcx.obligation_inspector.get() { let result = match result { - Ok((_, c, _)) => Ok(*c), + Ok((_, c)) => Ok(*c), Err(NoSolution) => Err(NoSolution), }; (inspector)(infcx, &obligation, result); @@ -80,13 +79,13 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { .evaluate_root_goal(obligation.clone().into(), GenerateProofTree::IfEnabled) .0 { - Ok((_, Certainty::Maybe(MaybeCause::Ambiguity), _)) => { + Ok((_, Certainty::Maybe(MaybeCause::Ambiguity))) => { FulfillmentErrorCode::Ambiguity { overflow: false } } - Ok((_, Certainty::Maybe(MaybeCause::Overflow), _)) => { + Ok((_, Certainty::Maybe(MaybeCause::Overflow))) => { FulfillmentErrorCode::Ambiguity { overflow: true } } - Ok((_, Certainty::Yes, _)) => { + Ok((_, Certainty::Yes)) => { bug!("did not expect successful goal when collecting ambiguity errors") } Err(_) => { @@ -117,7 +116,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { let goal = obligation.clone().into(); let result = infcx.evaluate_root_goal(goal, GenerateProofTree::IfEnabled).0; self.inspect_evaluated_obligation(infcx, &obligation, &result); - let (changed, certainty, nested_goals) = match result { + let (changed, certainty) = match result { Ok(result) => result, Err(NoSolution) => { errors.push(FulfillmentError { @@ -175,16 +174,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { continue; } }; - // Push any nested goals that we get from unifying our canonical response - // with our obligation onto the fulfillment context. - self.obligations.extend(nested_goals.into_iter().map(|goal| { - Obligation::new( - infcx.tcx, - obligation.cause.clone(), - goal.param_env, - goal.predicate, - ) - })); has_changed |= changed; match certainty { Certainty::Yes => {} diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index f33d0f397ce9e..33749550e9c6d 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -63,21 +63,11 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { infcx.probe(|_| { let mut instantiated_goals = vec![]; for goal in &self.nested_goals { - let goal = match ProofTreeBuilder::instantiate_canonical_state( + let goal = ProofTreeBuilder::instantiate_canonical_state( infcx, - self.goal.goal.param_env, self.goal.orig_values, *goal, - ) { - Ok((_goals, goal)) => goal, - Err(NoSolution) => { - warn!( - "unexpected failure when instantiating {:?}: {:?}", - goal, self.nested_goals - ); - return ControlFlow::Continue(()); - } - }; + ); instantiated_goals.push(goal); } diff --git a/compiler/rustc_trait_selection/src/solve/inspect/build.rs b/compiler/rustc_trait_selection/src/solve/inspect/build.rs index b587a93b24c4f..f7b310a7abe27 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/build.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/build.rs @@ -87,7 +87,6 @@ struct WipGoalEvaluation<'tcx> { pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>, pub kind: WipGoalEvaluationKind<'tcx>, pub evaluation: Option>, - pub returned_goals: Vec>>, } impl<'tcx> WipGoalEvaluation<'tcx> { @@ -103,7 +102,6 @@ impl<'tcx> WipGoalEvaluation<'tcx> { } }, evaluation: self.evaluation.unwrap().finalize(), - returned_goals: self.returned_goals, } } } @@ -312,7 +310,6 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } }, evaluation: None, - returned_goals: vec![], }) } @@ -369,17 +366,6 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } } - pub fn returned_goals(&mut self, goals: &[Goal<'tcx, ty::Predicate<'tcx>>]) { - if let Some(this) = self.as_mut() { - match this { - DebugSolver::GoalEvaluation(evaluation) => { - assert!(evaluation.returned_goals.is_empty()); - evaluation.returned_goals.extend(goals); - } - _ => unreachable!(), - } - } - } pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder<'tcx>) { if let Some(this) = self.as_mut() { match (this, *goal_evaluation.state.unwrap()) { diff --git a/tests/ui/traits/next-solver/generalize/generalize-proj-new-universe-index-2.rs b/tests/ui/traits/next-solver/generalize/generalize-proj-new-universe-index-2.rs index 70758e7deaace..9ef123fe210ee 100644 --- a/tests/ui/traits/next-solver/generalize/generalize-proj-new-universe-index-2.rs +++ b/tests/ui/traits/next-solver/generalize/generalize-proj-new-universe-index-2.rs @@ -1,8 +1,8 @@ // compile-flags: -Znext-solver -// known-bug: trait-system-refactor-initiative#60 +// check-pass // Generalizing a projection containing an inference variable -// which cannot be named by the `root_vid` can result in ambiguity. +// which cannot be named by the `root_vid` previously resulted in ambiguity. // // Because we do not decrement the universe index when exiting a forall, // this can cause unexpected failures. diff --git a/tests/ui/traits/next-solver/generalize/generalize-proj-new-universe-index-2.stderr b/tests/ui/traits/next-solver/generalize/generalize-proj-new-universe-index-2.stderr deleted file mode 100644 index 4548ab1e2972a..0000000000000 --- a/tests/ui/traits/next-solver/generalize/generalize-proj-new-universe-index-2.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0284]: type annotations needed - --> $DIR/generalize-proj-new-universe-index-2.rs:74:5 - | -LL | bound::<::Assoc, as Id>::Assoc, _>() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `V` declared on the function `bound` - | - = note: cannot satisfy `<::Assoc as WithAssoc< as Id>::Assoc>>::Assoc == _` -note: required by a bound in `bound` - --> $DIR/generalize-proj-new-universe-index-2.rs:69:21 - | -LL | fn bound() - | ----- required by a bound in this function -LL | where -LL | T: WithAssoc, - | ^^^^^^^^^ required by this bound in `bound` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/traits/next-solver/generalize/instantiate-canonical-occurs-check-failure.rs b/tests/ui/traits/next-solver/generalize/instantiate-canonical-occurs-check-failure.rs new file mode 100644 index 0000000000000..a6f2bf5ec2eb3 --- /dev/null +++ b/tests/ui/traits/next-solver/generalize/instantiate-canonical-occurs-check-failure.rs @@ -0,0 +1,29 @@ +// compile-flags: -Znext-solver +// check-pass + +// With #119106 generalization now results in `AliasRelate` if the generalized +// alias contains an inference variable which is not nameable. +// +// We previously proved alias-relate after canonicalization, which does not keep track +// of universe indices, so all inference vars are nameable inside of `AliasRelate`. +// +// If we now have a rigid projection containing an unnameable inference variables, +// we should emit an alias-relate obligation, which constrains the type of `x` to +// an alias, which then caused us to emit yet another equivalent alias-relate obligation +// when trying to instantiate the query result. This resulted in overflow. +trait Trait<'a> { + type Assoc: Default; +} + +fn takes_alias<'a, T: Trait<'a>>(_: >::Assoc) {} + +fn foo Trait<'a>>() { + let x = Default::default(); + + let _incr_universe: for<'a, 'b> fn(&'a (), &'b ()) = + (|&(), &()| ()) as for<'a> fn(&'a (), &'a ()); + + takes_alias::(x); +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.next.stderr b/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.next.stderr index ad8b24a39c701..e85d15b133f01 100644 --- a/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.next.stderr +++ b/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.next.stderr @@ -1,5 +1,5 @@ error[E0275]: overflow evaluating the requirement `<>::Id as Unnormalizable>::Assoc == _` - --> $DIR/occurs-check-nested-alias.rs:36:9 + --> $DIR/occurs-check-nested-alias.rs:38:9 | LL | x = y; | ^ diff --git a/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.rs b/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.rs index e51508d684f9c..2f4d923a98dee 100644 --- a/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.rs +++ b/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.rs @@ -1,10 +1,12 @@ // revisions: old next //[old] check-pass +//[next] compile-flags: -Znext-solver +//[next] known-bug: trait-system-refactor-initiative#8 + +// case 3 of https://github.com/rust-lang/trait-system-refactor-initiative/issues/8. // Currently always fails to generalize the outer alias, even if it // is treated as rigid by `alias-relate`. -//[next] compile-flags: -Znext-solver -//[next] known-bug: trait-system-refactor-initiative#8 #![crate_type = "lib"] #![allow(unused)] trait Unnormalizable { diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.stderr b/tests/ui/traits/next-solver/issue-118950-root-region.stderr index c16a48d5f154c..43785b00e9156 100644 --- a/tests/ui/traits/next-solver/issue-118950-root-region.stderr +++ b/tests/ui/traits/next-solver/issue-118950-root-region.stderr @@ -15,6 +15,8 @@ LL | #![feature(lazy_type_alias)] WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) })