diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2023-03-23 08:35:35 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-03-23 08:35:35 +0100 |
| commit | 5d28853efe7ae11a77f5f7601a216e8ca36d6234 (patch) | |
| tree | 39057754d38d0831647d115d0d81ea461e6f9551 /compiler/rustc_trait_selection/src | |
| parent | a26ac4cb94f0cd1afb2c05439f757cb3ba465b83 (diff) | |
| parent | 244cdaa457d80b3e1ef90795a48833f948ac0db9 (diff) | |
| download | rust-5d28853efe7ae11a77f5f7601a216e8ca36d6234.tar.gz rust-5d28853efe7ae11a77f5f7601a216e8ca36d6234.zip | |
Rollup merge of #109462 - compiler-errors:alias-relate, r=BoxyUwU,lcnr
Make alias-eq have a relation direction (and rename it to alias-relate) Emitting an "alias-eq" is too strict in some situations, since we don't always want strict equality between a projection and rigid ty. Adds a relation direction. * I could probably just reuse this [`RelationDir`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_infer/infer/combine/enum.RelationDir.html) -- happy to uplift that struct into middle and use that instead, but I didn't feel compelled to... 🤷 * Some of the matching in `compute_alias_relate_goal` is a bit verbose -- I guess I could simplify it by using [`At::relate`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_infer/infer/at/struct.At.html#method.relate) and mapping the relation-dir to a variance. * Alternatively, I coulld simplify things by making more helper functions on `EvalCtxt` (e.g. `EvalCtxt::relate_with_direction(T, T)` that also does the nested goal registration). No preference. r? ```@lcnr``` cc ```@BoxyUwU``` though boxy can claim it if she wants NOTE: first commit is all the changes, the second is just renaming stuff
Diffstat (limited to 'compiler/rustc_trait_selection/src')
10 files changed, 121 insertions, 61 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 95412922357..75b304cce4e 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -223,9 +223,11 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("TypeWellFormedFromEnv is only used for Chalk") } - ty::PredicateKind::AliasEq(lhs, rhs) => { - self.compute_alias_eq_goal(Goal { param_env, predicate: (lhs, rhs) }) - } + ty::PredicateKind::AliasRelate(lhs, rhs, direction) => self + .compute_alias_relate_goal(Goal { + param_env, + predicate: (lhs, rhs, direction), + }), } } else { let kind = self.infcx.instantiate_binder_with_placeholders(kind); @@ -457,6 +459,25 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { }) } + #[instrument(level = "debug", skip(self, param_env), ret)] + pub(super) fn sub<T: ToTrace<'tcx>>( + &mut self, + param_env: ty::ParamEnv<'tcx>, + sub: T, + sup: T, + ) -> Result<(), NoSolution> { + self.infcx + .at(&ObligationCause::dummy(), param_env) + .sub(DefineOpaqueTypes::No, sub, sup) + .map(|InferOk { value: (), obligations }| { + self.add_goals(obligations.into_iter().map(|o| o.into())); + }) + .map_err(|e| { + debug!(?e, "failed to subtype"); + NoSolution + }) + } + /// Equates two values returning the nested goals without adding them /// to the nested goals of the `EvalCtxt`. /// diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 38120b9760f..01f171762ab 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -73,7 +73,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { MismatchedProjectionTypes { err: TypeError::Mismatch }, ) } - ty::PredicateKind::AliasEq(_, _) => { + ty::PredicateKind::AliasRelate(_, _, _) => { FulfillmentErrorCode::CodeProjectionError( MismatchedProjectionTypes { err: TypeError::Mismatch }, ) diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 606c2eaa510..4c87d36ca0d 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -17,7 +17,6 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues}; -use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; use rustc_infer::traits::query::NoSolution; use rustc_middle::traits::solve::{ CanonicalGoal, CanonicalResponse, Certainty, ExternalConstraints, ExternalConstraintsData, @@ -101,11 +100,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { // That won't actually reflect in the query response, so it seems moot. self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) } else { - let InferOk { value: (), obligations } = self - .infcx - .at(&ObligationCause::dummy(), goal.param_env) - .sub(DefineOpaqueTypes::No, goal.predicate.a, goal.predicate.b)?; - self.add_goals(obligations.into_iter().map(|pred| pred.into())); + self.sub(goal.param_env, goal.predicate.a, goal.predicate.b)?; self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } @@ -156,55 +151,94 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } #[instrument(level = "debug", skip(self), ret)] - fn compute_alias_eq_goal( + fn compute_alias_relate_goal( &mut self, - goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>)>, + goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>, ty::AliasRelationDirection)>, ) -> QueryResult<'tcx> { let tcx = self.tcx(); + // We may need to invert the alias relation direction if dealing an alias on the RHS. + enum Invert { + No, + Yes, + } + let evaluate_normalizes_to = + |ecx: &mut EvalCtxt<'_, 'tcx>, alias, other, direction, invert| { + debug!("evaluate_normalizes_to(alias={:?}, other={:?})", alias, other); + let result = ecx.probe(|ecx| { + let other = match direction { + // This is purely an optimization. + ty::AliasRelationDirection::Equate => other, + + ty::AliasRelationDirection::Subtype => { + let fresh = ecx.next_term_infer_of_kind(other); + let (sub, sup) = match invert { + Invert::No => (fresh, other), + Invert::Yes => (other, fresh), + }; + ecx.sub(goal.param_env, sub, sup)?; + fresh + } + }; + ecx.add_goal(goal.with( + tcx, + ty::Binder::dummy(ty::ProjectionPredicate { + projection_ty: alias, + term: other, + }), + )); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }); + debug!("evaluate_normalizes_to({alias}, {other}, {direction:?}) -> {result:?}"); + result + }; - let evaluate_normalizes_to = |ecx: &mut EvalCtxt<'_, 'tcx>, alias, other| { - debug!("evaluate_normalizes_to(alias={:?}, other={:?})", alias, other); - let r = ecx.probe(|ecx| { - ecx.add_goal(goal.with( - tcx, - ty::Binder::dummy(ty::ProjectionPredicate { - projection_ty: alias, - term: other, - }), - )); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }); - debug!("evaluate_normalizes_to(..) -> {:?}", r); - r - }; + let (lhs, rhs, direction) = goal.predicate; - if goal.predicate.0.is_infer() || goal.predicate.1.is_infer() { + if lhs.is_infer() || rhs.is_infer() { bug!( - "`AliasEq` goal with an infer var on lhs or rhs which should have been instantiated" + "`AliasRelate` goal with an infer var on lhs or rhs which should have been instantiated" ); } - match ( - goal.predicate.0.to_alias_term_no_opaque(tcx), - goal.predicate.1.to_alias_term_no_opaque(tcx), - ) { - (None, None) => bug!("`AliasEq` goal without an alias on either lhs or rhs"), - (Some(alias), None) => evaluate_normalizes_to(self, alias, goal.predicate.1), - (None, Some(alias)) => evaluate_normalizes_to(self, alias, goal.predicate.0), - (Some(alias_lhs), Some(alias_rhs)) => { - debug!("compute_alias_eq_goal: both sides are aliases"); + match (lhs.to_projection_term(tcx), rhs.to_projection_term(tcx)) { + (None, None) => bug!("`AliasRelate` goal without an alias on either lhs or rhs"), - let mut candidates = Vec::with_capacity(3); + // RHS is not a projection, only way this is true is if LHS normalizes-to RHS + (Some(alias_lhs), None) => { + evaluate_normalizes_to(self, alias_lhs, rhs, direction, Invert::No) + } - // Evaluate all 3 potential candidates for the alias' being equal - candidates.push(evaluate_normalizes_to(self, alias_lhs, goal.predicate.1)); - candidates.push(evaluate_normalizes_to(self, alias_rhs, goal.predicate.0)); - candidates.push(self.probe(|ecx| { - debug!("compute_alias_eq_goal: alias defids are equal, equating substs"); - ecx.eq(goal.param_env, alias_lhs, alias_rhs)?; - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - })); + // LHS is not a projection, only way this is true is if RHS normalizes-to LHS + (None, Some(alias_rhs)) => { + evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes) + } + (Some(alias_lhs), Some(alias_rhs)) => { + debug!("compute_alias_relate_goal: both sides are aliases"); + + let candidates = vec![ + // LHS normalizes-to RHS + evaluate_normalizes_to(self, alias_lhs, rhs, direction, Invert::No), + // RHS normalizes-to RHS + evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes), + // Relate via substs + self.probe(|ecx| { + debug!( + "compute_alias_relate_goal: alias defids are equal, equating substs" + ); + + match direction { + ty::AliasRelationDirection::Equate => { + ecx.eq(goal.param_env, alias_lhs, alias_rhs)?; + } + ty::AliasRelationDirection::Subtype => { + ecx.sub(goal.param_env, alias_lhs, alias_rhs)?; + } + } + + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }), + ]; debug!(?candidates); self.try_merge_responses(candidates.into_iter()) diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index dbf6775afc2..6b3a59b1ed5 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -832,7 +832,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { // the `ParamEnv`. ty::PredicateKind::WellFormed(..) | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs index 1174efdbfa8..13607b9079a 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs @@ -92,6 +92,11 @@ impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> { } impl<'tcx> ObligationEmittingRelation<'tcx> for CollectAllMismatches<'_, 'tcx> { + fn alias_relate_direction(&self) -> ty::AliasRelationDirection { + // FIXME(deferred_projection_equality): We really should get rid of this relation. + ty::AliasRelationDirection::Equate + } + fn register_obligations(&mut self, _obligations: PredicateObligations<'tcx>) { // FIXME(deferred_projection_equality) } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 41ffaeeac1c..617d53b609d 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1276,9 +1276,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { "TypeWellFormedFromEnv predicate should only exist in the environment" ), - ty::PredicateKind::AliasEq(..) => span_bug!( + ty::PredicateKind::AliasRelate(..) => span_bug!( span, - "AliasEq predicate should never be the predicate cause of a SelectionError" + "AliasRelate predicate should never be the predicate cause of a SelectionError" ), ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 23754480fcf..07e31e87bfb 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -361,8 +361,8 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("TypeWellFormedFromEnv is only used for Chalk") } - ty::PredicateKind::AliasEq(..) => { - bug!("AliasEq is only used for new solver") + ty::PredicateKind::AliasRelate(..) => { + bug!("AliasRelate is only used for new solver") } }, Some(pred) => match pred { @@ -630,8 +630,8 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("TypeWellFormedFromEnv is only used for Chalk") } - ty::PredicateKind::AliasEq(..) => { - bug!("AliasEq is only used for new solver") + ty::PredicateKind::AliasRelate(..) => { + bug!("AliasRelate is only used for new solver") } ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq( diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 038f8964471..5d2af5ff33c 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -335,7 +335,7 @@ fn predicate_references_self<'tcx>( has_self_ty(&ty.into()).then_some(sp) } - ty::PredicateKind::AliasEq(..) => bug!("`AliasEq` not allowed as assumption"), + ty::PredicateKind::AliasRelate(..) => bug!("`AliasRelate` not allowed as assumption"), ty::PredicateKind::WellFormed(..) | ty::PredicateKind::ObjectSafe(..) @@ -395,7 +395,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => false, } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index b8758ad9323..bffefdf359a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -977,8 +977,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("TypeWellFormedFromEnv is only used for chalk") } - ty::PredicateKind::AliasEq(..) => { - bug!("AliasEq is only used for new solver") + ty::PredicateKind::AliasRelate(..) => { + bug!("AliasRelate is only used for new solver") } ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig), ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index d498af359c5..ec5bd982a3c 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -191,8 +191,8 @@ pub fn predicate_obligations<'tcx>( ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("TypeWellFormedFromEnv is only used for Chalk") } - ty::PredicateKind::AliasEq(..) => { - bug!("We should only wf check where clauses and `AliasEq` is not a `Clause`") + ty::PredicateKind::AliasRelate(..) => { + bug!("We should only wf check where clauses and `AliasRelate` is not a `Clause`") } } @@ -936,7 +936,7 @@ pub(crate) fn required_region_bounds<'tcx>( | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( ref t, |
