Rollup merge of #113317 - lcnr:sketchy-new-select, r=oli-obk
-Ztrait-solver=next: stop depending on old solver removes the final dependencies on the old solver when `-Ztrait-solver=next` is enabled.
This commit is contained in:
commit
a1f8edb5d5
@ -21,29 +21,18 @@ pub fn infer_projection(
|
|||||||
recursion_depth: usize,
|
recursion_depth: usize,
|
||||||
obligations: &mut Vec<PredicateObligation<'tcx>>,
|
obligations: &mut Vec<PredicateObligation<'tcx>>,
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
if self.next_trait_solver() {
|
debug_assert!(!self.next_trait_solver());
|
||||||
// FIXME(-Ztrait-solver=next): Instead of branching here,
|
let def_id = projection_ty.def_id;
|
||||||
// completely change the normalization routine with the new solver.
|
let ty_var = self.next_ty_var(TypeVariableOrigin {
|
||||||
//
|
kind: TypeVariableOriginKind::NormalizeProjectionType,
|
||||||
// The new solver correctly handles projection equality so this hack
|
span: self.tcx.def_span(def_id),
|
||||||
// is not necessary. if re-enabled it should emit `PredicateKind::AliasRelate`
|
});
|
||||||
// not `PredicateKind::Clause(ClauseKind::Projection(..))` as in the new solver
|
let projection = ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Projection(
|
||||||
// `Projection` is used as `normalizes-to` which will fail for `<T as Trait>::Assoc eq ?0`.
|
ty::ProjectionPredicate { projection_ty, term: ty_var.into() },
|
||||||
return projection_ty.to_ty(self.tcx);
|
)));
|
||||||
} else {
|
let obligation =
|
||||||
let def_id = projection_ty.def_id;
|
Obligation::with_depth(self.tcx, cause, recursion_depth, param_env, projection);
|
||||||
let ty_var = self.next_ty_var(TypeVariableOrigin {
|
obligations.push(obligation);
|
||||||
kind: TypeVariableOriginKind::NormalizeProjectionType,
|
ty_var
|
||||||
span: self.tcx.def_span(def_id),
|
|
||||||
});
|
|
||||||
let projection =
|
|
||||||
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Projection(
|
|
||||||
ty::ProjectionPredicate { projection_ty, term: ty_var.into() },
|
|
||||||
)));
|
|
||||||
let obligation =
|
|
||||||
Obligation::with_depth(self.tcx, cause, recursion_depth, param_env, projection);
|
|
||||||
obligations.push(obligation);
|
|
||||||
ty_var
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,6 +159,7 @@ fn try_fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
|
|||||||
fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
|
fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
|
||||||
let reveal = self.at.param_env.reveal();
|
let reveal = self.at.param_env.reveal();
|
||||||
let infcx = self.at.infcx;
|
let infcx = self.at.infcx;
|
||||||
|
debug_assert_eq!(ty, infcx.shallow_resolve(ty));
|
||||||
if !needs_normalization(&ty, reveal) {
|
if !needs_normalization(&ty, reveal) {
|
||||||
return Ok(ty);
|
return Ok(ty);
|
||||||
}
|
}
|
||||||
@ -192,6 +193,7 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
|
|||||||
fn try_fold_const(&mut self, ct: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
|
fn try_fold_const(&mut self, ct: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
|
||||||
let reveal = self.at.param_env.reveal();
|
let reveal = self.at.param_env.reveal();
|
||||||
let infcx = self.at.infcx;
|
let infcx = self.at.infcx;
|
||||||
|
debug_assert_eq!(ct, infcx.shallow_resolve(ct));
|
||||||
if !needs_normalization(&ct, reveal) {
|
if !needs_normalization(&ct, reveal) {
|
||||||
return Ok(ct);
|
return Ok(ct);
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
use std::iter;
|
use std::iter;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
|
use super::query::evaluate_obligation::InferCtxtExt;
|
||||||
use super::NormalizeExt;
|
use super::NormalizeExt;
|
||||||
|
|
||||||
/// Whether we do the orphan check relative to this crate or
|
/// Whether we do the orphan check relative to this crate or
|
||||||
@ -290,6 +291,20 @@ fn impl_intersection_has_impossible_obligation<'cx, 'tcx>(
|
|||||||
) -> bool {
|
) -> bool {
|
||||||
let infcx = selcx.infcx;
|
let infcx = selcx.infcx;
|
||||||
|
|
||||||
|
let obligation_guaranteed_to_fail = move |obligation: &PredicateObligation<'tcx>| {
|
||||||
|
if infcx.next_trait_solver() {
|
||||||
|
infcx.evaluate_obligation(obligation).map_or(false, |result| !result.may_apply())
|
||||||
|
} else {
|
||||||
|
// We use `evaluate_root_obligation` to correctly track
|
||||||
|
// intercrate ambiguity clauses. We do not need this in the
|
||||||
|
// new solver.
|
||||||
|
selcx.evaluate_root_obligation(obligation).map_or(
|
||||||
|
false, // Overflow has occurred, and treat the obligation as possibly holding.
|
||||||
|
|result| !result.may_apply(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let opt_failing_obligation = [&impl1_header.predicates, &impl2_header.predicates]
|
let opt_failing_obligation = [&impl1_header.predicates, &impl2_header.predicates]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flatten()
|
.flatten()
|
||||||
@ -297,12 +312,7 @@ fn impl_intersection_has_impossible_obligation<'cx, 'tcx>(
|
|||||||
Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, predicate)
|
Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, predicate)
|
||||||
})
|
})
|
||||||
.chain(obligations)
|
.chain(obligations)
|
||||||
.find(|o| {
|
.find(obligation_guaranteed_to_fail);
|
||||||
selcx.evaluate_root_obligation(o).map_or(
|
|
||||||
false, // Overflow has occurred, and treat the obligation as possibly holding.
|
|
||||||
|result| !result.may_apply(),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some(failing_obligation) = opt_failing_obligation {
|
if let Some(failing_obligation) = opt_failing_obligation {
|
||||||
debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
|
debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
|
||||||
|
@ -447,6 +447,7 @@ fn new(
|
|||||||
depth: usize,
|
depth: usize,
|
||||||
obligations: &'a mut Vec<PredicateObligation<'tcx>>,
|
obligations: &'a mut Vec<PredicateObligation<'tcx>>,
|
||||||
) -> AssocTypeNormalizer<'a, 'b, 'tcx> {
|
) -> AssocTypeNormalizer<'a, 'b, 'tcx> {
|
||||||
|
debug_assert!(!selcx.infcx.next_trait_solver());
|
||||||
AssocTypeNormalizer {
|
AssocTypeNormalizer {
|
||||||
selcx,
|
selcx,
|
||||||
param_env,
|
param_env,
|
||||||
@ -1122,6 +1123,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
|
|||||||
obligations: &mut Vec<PredicateObligation<'tcx>>,
|
obligations: &mut Vec<PredicateObligation<'tcx>>,
|
||||||
) -> Result<Option<Term<'tcx>>, InProgress> {
|
) -> Result<Option<Term<'tcx>>, InProgress> {
|
||||||
let infcx = selcx.infcx;
|
let infcx = selcx.infcx;
|
||||||
|
debug_assert!(!selcx.infcx.next_trait_solver());
|
||||||
// Don't use the projection cache in intercrate mode -
|
// Don't use the projection cache in intercrate mode -
|
||||||
// the `infcx` may be re-used between intercrate in non-intercrate
|
// the `infcx` may be re-used between intercrate in non-intercrate
|
||||||
// mode, which could lead to using incorrect cache results.
|
// mode, which could lead to using incorrect cache results.
|
||||||
|
@ -97,6 +97,7 @@ fn evaluate_obligation(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
assert!(!self.intercrate);
|
||||||
let c_pred = self.canonicalize_query_keep_static(
|
let c_pred = self.canonicalize_query_keep_static(
|
||||||
param_env.and(obligation.predicate),
|
param_env.and(obligation.predicate),
|
||||||
&mut _orig_values,
|
&mut _orig_values,
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::solve;
|
||||||
use crate::traits::query::NoSolution;
|
use crate::traits::query::NoSolution;
|
||||||
use crate::traits::wf;
|
use crate::traits::wf;
|
||||||
use crate::traits::ObligationCtxt;
|
use crate::traits::ObligationCtxt;
|
||||||
@ -6,6 +7,7 @@
|
|||||||
use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
|
use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
|
||||||
use rustc_infer::traits::query::OutlivesBound;
|
use rustc_infer::traits::query::OutlivesBound;
|
||||||
use rustc_middle::infer::canonical::CanonicalQueryResponse;
|
use rustc_middle::infer::canonical::CanonicalQueryResponse;
|
||||||
|
use rustc_middle::traits::ObligationCause;
|
||||||
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
|
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
|
||||||
use rustc_span::def_id::CRATE_DEF_ID;
|
use rustc_span::def_id::CRATE_DEF_ID;
|
||||||
use rustc_span::source_map::DUMMY_SP;
|
use rustc_span::source_map::DUMMY_SP;
|
||||||
@ -164,19 +166,29 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
|
|||||||
|
|
||||||
// We lazily compute the outlives components as
|
// We lazily compute the outlives components as
|
||||||
// `select_all_or_error` constrains inference variables.
|
// `select_all_or_error` constrains inference variables.
|
||||||
let implied_bounds = outlives_bounds
|
let mut implied_bounds = Vec::new();
|
||||||
.into_iter()
|
for ty::OutlivesPredicate(a, r_b) in outlives_bounds {
|
||||||
.flat_map(|ty::OutlivesPredicate(a, r_b)| match a.unpack() {
|
match a.unpack() {
|
||||||
ty::GenericArgKind::Lifetime(r_a) => vec![OutlivesBound::RegionSubRegion(r_b, r_a)],
|
ty::GenericArgKind::Lifetime(r_a) => {
|
||||||
|
implied_bounds.push(OutlivesBound::RegionSubRegion(r_b, r_a))
|
||||||
|
}
|
||||||
ty::GenericArgKind::Type(ty_a) => {
|
ty::GenericArgKind::Type(ty_a) => {
|
||||||
let ty_a = ocx.infcx.resolve_vars_if_possible(ty_a);
|
let mut ty_a = ocx.infcx.resolve_vars_if_possible(ty_a);
|
||||||
|
// Need to manually normalize in the new solver as `wf::obligations` does not.
|
||||||
|
if ocx.infcx.next_trait_solver() {
|
||||||
|
ty_a = solve::deeply_normalize(
|
||||||
|
ocx.infcx.at(&ObligationCause::dummy(), param_env),
|
||||||
|
ty_a,
|
||||||
|
)
|
||||||
|
.map_err(|_errs| NoSolution)?;
|
||||||
|
}
|
||||||
let mut components = smallvec![];
|
let mut components = smallvec![];
|
||||||
push_outlives_components(tcx, ty_a, &mut components);
|
push_outlives_components(tcx, ty_a, &mut components);
|
||||||
implied_bounds_from_components(r_b, components)
|
implied_bounds.extend(implied_bounds_from_components(r_b, components))
|
||||||
}
|
}
|
||||||
ty::GenericArgKind::Const(_) => unreachable!(),
|
ty::GenericArgKind::Const(_) => unreachable!(),
|
||||||
})
|
}
|
||||||
.collect();
|
}
|
||||||
|
|
||||||
Ok(implied_bounds)
|
Ok(implied_bounds)
|
||||||
}
|
}
|
||||||
|
@ -388,7 +388,7 @@ fn assemble_candidates_from_impls(
|
|||||||
/// `FnPtr`, when we wanted to report that it doesn't implement `Trait`.
|
/// `FnPtr`, when we wanted to report that it doesn't implement `Trait`.
|
||||||
#[instrument(level = "trace", skip(self), ret)]
|
#[instrument(level = "trace", skip(self), ret)]
|
||||||
fn reject_fn_ptr_impls(
|
fn reject_fn_ptr_impls(
|
||||||
&self,
|
&mut self,
|
||||||
impl_def_id: DefId,
|
impl_def_id: DefId,
|
||||||
obligation: &TraitObligation<'tcx>,
|
obligation: &TraitObligation<'tcx>,
|
||||||
impl_self_ty: Ty<'tcx>,
|
impl_self_ty: Ty<'tcx>,
|
||||||
@ -464,7 +464,7 @@ fn reject_fn_ptr_impls(
|
|||||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))
|
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
if let Ok(r) = self.infcx.evaluate_obligation(&obligation) {
|
if let Ok(r) = self.evaluate_root_obligation(&obligation) {
|
||||||
if !r.may_apply() {
|
if !r.may_apply() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -34,8 +34,6 @@
|
|||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_infer::infer::DefineOpaqueTypes;
|
use rustc_infer::infer::DefineOpaqueTypes;
|
||||||
use rustc_infer::infer::LateBoundRegionConversionTime;
|
use rustc_infer::infer::LateBoundRegionConversionTime;
|
||||||
use rustc_infer::traits::TraitEngine;
|
|
||||||
use rustc_infer::traits::TraitEngineExt;
|
|
||||||
use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
|
use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
|
||||||
use rustc_middle::mir::interpret::ErrorHandled;
|
use rustc_middle::mir::interpret::ErrorHandled;
|
||||||
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
|
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
|
||||||
@ -312,6 +310,7 @@ fn candidate_from_obligation<'o>(
|
|||||||
&mut self,
|
&mut self,
|
||||||
stack: &TraitObligationStack<'o, 'tcx>,
|
stack: &TraitObligationStack<'o, 'tcx>,
|
||||||
) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
|
) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
|
||||||
|
debug_assert!(!self.infcx.next_trait_solver());
|
||||||
// Watch out for overflow. This intentionally bypasses (and does
|
// Watch out for overflow. This intentionally bypasses (and does
|
||||||
// not update) the cache.
|
// not update) the cache.
|
||||||
self.check_recursion_limit(&stack.obligation, &stack.obligation)?;
|
self.check_recursion_limit(&stack.obligation, &stack.obligation)?;
|
||||||
@ -526,21 +525,20 @@ fn candidate_from_obligation_no_cache<'o>(
|
|||||||
/// Evaluates whether the obligation `obligation` can be satisfied
|
/// Evaluates whether the obligation `obligation` can be satisfied
|
||||||
/// and returns an `EvaluationResult`. This is meant for the
|
/// and returns an `EvaluationResult`. This is meant for the
|
||||||
/// *initial* call.
|
/// *initial* call.
|
||||||
|
///
|
||||||
|
/// Do not use this directly, use `infcx.evaluate_obligation` instead.
|
||||||
pub fn evaluate_root_obligation(
|
pub fn evaluate_root_obligation(
|
||||||
&mut self,
|
&mut self,
|
||||||
obligation: &PredicateObligation<'tcx>,
|
obligation: &PredicateObligation<'tcx>,
|
||||||
) -> Result<EvaluationResult, OverflowError> {
|
) -> Result<EvaluationResult, OverflowError> {
|
||||||
|
debug_assert!(!self.infcx.next_trait_solver());
|
||||||
self.evaluation_probe(|this| {
|
self.evaluation_probe(|this| {
|
||||||
let goal =
|
let goal =
|
||||||
this.infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env));
|
this.infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env));
|
||||||
let mut result = if this.infcx.next_trait_solver() {
|
let mut result = this.evaluate_predicate_recursively(
|
||||||
this.evaluate_predicates_recursively_in_new_solver([obligation.clone()])?
|
TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
|
||||||
} else {
|
obligation.clone(),
|
||||||
this.evaluate_predicate_recursively(
|
)?;
|
||||||
TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
|
|
||||||
obligation.clone(),
|
|
||||||
)?
|
|
||||||
};
|
|
||||||
// If the predicate has done any inference, then downgrade the
|
// If the predicate has done any inference, then downgrade the
|
||||||
// result to ambiguous.
|
// result to ambiguous.
|
||||||
if this.infcx.shallow_resolve(goal) != goal {
|
if this.infcx.shallow_resolve(goal) != goal {
|
||||||
@ -587,42 +585,19 @@ fn evaluate_predicates_recursively<'o, I>(
|
|||||||
where
|
where
|
||||||
I: IntoIterator<Item = PredicateObligation<'tcx>> + std::fmt::Debug,
|
I: IntoIterator<Item = PredicateObligation<'tcx>> + std::fmt::Debug,
|
||||||
{
|
{
|
||||||
if self.infcx.next_trait_solver() {
|
let mut result = EvaluatedToOk;
|
||||||
self.evaluate_predicates_recursively_in_new_solver(predicates)
|
for mut obligation in predicates {
|
||||||
} else {
|
obligation.set_depth_from_parent(stack.depth());
|
||||||
let mut result = EvaluatedToOk;
|
let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?;
|
||||||
for mut obligation in predicates {
|
if let EvaluatedToErr = eval {
|
||||||
obligation.set_depth_from_parent(stack.depth());
|
// fast-path - EvaluatedToErr is the top of the lattice,
|
||||||
let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?;
|
// so we don't need to look on the other predicates.
|
||||||
if let EvaluatedToErr = eval {
|
return Ok(EvaluatedToErr);
|
||||||
// fast-path - EvaluatedToErr is the top of the lattice,
|
} else {
|
||||||
// so we don't need to look on the other predicates.
|
result = cmp::max(result, eval);
|
||||||
return Ok(EvaluatedToErr);
|
|
||||||
} else {
|
|
||||||
result = cmp::max(result, eval);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(result)
|
|
||||||
}
|
}
|
||||||
}
|
Ok(result)
|
||||||
|
|
||||||
/// Evaluates the predicates using the new solver when `-Ztrait-solver=next` is enabled
|
|
||||||
fn evaluate_predicates_recursively_in_new_solver(
|
|
||||||
&mut self,
|
|
||||||
predicates: impl IntoIterator<Item = PredicateObligation<'tcx>>,
|
|
||||||
) -> Result<EvaluationResult, OverflowError> {
|
|
||||||
let mut fulfill_cx = crate::solve::FulfillmentCtxt::new(self.infcx);
|
|
||||||
fulfill_cx.register_predicate_obligations(self.infcx, predicates);
|
|
||||||
// True errors
|
|
||||||
// FIXME(-Ztrait-solver=next): Overflows are reported as ambig here, is that OK?
|
|
||||||
if !fulfill_cx.select_where_possible(self.infcx).is_empty() {
|
|
||||||
return Ok(EvaluatedToErr);
|
|
||||||
}
|
|
||||||
if !fulfill_cx.select_all_or_error(self.infcx).is_empty() {
|
|
||||||
return Ok(EvaluatedToAmbig);
|
|
||||||
}
|
|
||||||
// Regions and opaques are handled in the `evaluation_probe` by looking at the snapshot
|
|
||||||
Ok(EvaluatedToOk)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(
|
#[instrument(
|
||||||
@ -636,6 +611,7 @@ fn evaluate_predicate_recursively<'o>(
|
|||||||
previous_stack: TraitObligationStackList<'o, 'tcx>,
|
previous_stack: TraitObligationStackList<'o, 'tcx>,
|
||||||
obligation: PredicateObligation<'tcx>,
|
obligation: PredicateObligation<'tcx>,
|
||||||
) -> Result<EvaluationResult, OverflowError> {
|
) -> Result<EvaluationResult, OverflowError> {
|
||||||
|
debug_assert!(!self.infcx.next_trait_solver());
|
||||||
// `previous_stack` stores a `TraitObligation`, while `obligation` is
|
// `previous_stack` stores a `TraitObligation`, while `obligation` is
|
||||||
// a `PredicateObligation`. These are distinct types, so we can't
|
// a `PredicateObligation`. These are distinct types, so we can't
|
||||||
// use any `Option` combinator method that would force them to be
|
// use any `Option` combinator method that would force them to be
|
||||||
@ -1179,6 +1155,7 @@ fn evaluate_stack<'o>(
|
|||||||
&mut self,
|
&mut self,
|
||||||
stack: &TraitObligationStack<'o, 'tcx>,
|
stack: &TraitObligationStack<'o, 'tcx>,
|
||||||
) -> Result<EvaluationResult, OverflowError> {
|
) -> Result<EvaluationResult, OverflowError> {
|
||||||
|
debug_assert!(!self.infcx.next_trait_solver());
|
||||||
// In intercrate mode, whenever any of the generics are unbound,
|
// In intercrate mode, whenever any of the generics are unbound,
|
||||||
// there can always be an impl. Even if there are no impls in
|
// there can always be an impl. Even if there are no impls in
|
||||||
// this crate, perhaps the type would be unified with
|
// this crate, perhaps the type would be unified with
|
||||||
|
@ -302,6 +302,16 @@ fn cause(&self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCa
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn normalize(self, infcx: &InferCtxt<'tcx>) -> Vec<traits::PredicateObligation<'tcx>> {
|
fn normalize(self, infcx: &InferCtxt<'tcx>) -> Vec<traits::PredicateObligation<'tcx>> {
|
||||||
|
// Do not normalize `wf` obligations with the new solver.
|
||||||
|
//
|
||||||
|
// The current deep normalization routine with the new solver does not
|
||||||
|
// handle ambiguity and the new solver correctly deals with unnnormalized goals.
|
||||||
|
// If the user relies on normalized types, e.g. for `fn implied_outlives_bounds`,
|
||||||
|
// it is their responsibility to normalize while avoiding ambiguity.
|
||||||
|
if infcx.next_trait_solver() {
|
||||||
|
return self.out;
|
||||||
|
}
|
||||||
|
|
||||||
let cause = self.cause(traits::WellFormed(None));
|
let cause = self.cause(traits::WellFormed(None));
|
||||||
let param_env = self.param_env;
|
let param_env = self.param_env;
|
||||||
let mut obligations = Vec::with_capacity(self.out.len());
|
let mut obligations = Vec::with_capacity(self.out.len());
|
||||||
|
Loading…
Reference in New Issue
Block a user