Extract impl_subject_and_oglibations fn and make equate receive subjects

This commit is contained in:
Santiago Pastorino 2022-03-24 12:27:09 -03:00
parent 64df2ee1eb
commit 22b311bd82
No known key found for this signature in database
GPG Key ID: 8131A24E0C79EFAF
4 changed files with 94 additions and 47 deletions

View File

@ -28,7 +28,7 @@
use super::*; use super::*;
use rustc_middle::ty::relate::{Relate, TypeRelation}; use rustc_middle::ty::relate::{Relate, TypeRelation};
use rustc_middle::ty::Const; use rustc_middle::ty::{Const, ImplSubject};
pub struct At<'a, 'tcx> { pub struct At<'a, 'tcx> {
pub infcx: &'a InferCtxt<'a, 'tcx>, pub infcx: &'a InferCtxt<'a, 'tcx>,
@ -272,6 +272,29 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
} }
} }
impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> {
fn to_trace(
tcx: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
b: Self,
) -> TypeTrace<'tcx> {
match (a, b) {
(ImplSubject::Trait(trait_ref_a), ImplSubject::Trait(trait_ref_b)) => {
ToTrace::to_trace(tcx, cause, a_is_expected, trait_ref_a, trait_ref_b)
}
(ImplSubject::Inherent(ty_a), ImplSubject::Inherent(ty_b)) => {
ToTrace::to_trace(tcx, cause, a_is_expected, ty_a, ty_b)
}
(ImplSubject::Trait(_), ImplSubject::Inherent(_))
| (ImplSubject::Inherent(_), ImplSubject::Trait(_)) => {
bug!("can not trace TraitRef and Ty");
}
}
}
}
impl<'tcx> ToTrace<'tcx> for Ty<'tcx> { impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
fn to_trace( fn to_trace(
_: TyCtxt<'tcx>, _: TyCtxt<'tcx>,

View File

@ -44,6 +44,7 @@ use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::Span; use rustc_span::Span;
use rustc_target::abi::Align; use rustc_target::abi::Align;
use std::fmt::Debug;
use std::hash::Hash; use std::hash::Hash;
use std::ops::ControlFlow; use std::ops::ControlFlow;
use std::{fmt, str}; use std::{fmt, str};
@ -172,7 +173,7 @@ pub struct ImplHeader<'tcx> {
pub predicates: Vec<Predicate<'tcx>>, pub predicates: Vec<Predicate<'tcx>>,
} }
#[derive(Debug)] #[derive(Copy, Clone, Debug, TypeFoldable)]
pub enum ImplSubject<'tcx> { pub enum ImplSubject<'tcx> {
Trait(TraitRef<'tcx>), Trait(TraitRef<'tcx>),
Inherent(Ty<'tcx>), Inherent(Ty<'tcx>),

View File

@ -7,7 +7,7 @@
use crate::mir::interpret::{get_slice_bytes, ConstValue, GlobalAlloc, Scalar}; use crate::mir::interpret::{get_slice_bytes, ConstValue, GlobalAlloc, Scalar};
use crate::ty::error::{ExpectedFound, TypeError}; use crate::ty::error::{ExpectedFound, TypeError};
use crate::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef}; use crate::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
use crate::ty::{self, Term, Ty, TyCtxt, TypeFoldable}; use crate::ty::{self, ImplSubject, Term, Ty, TyCtxt, TypeFoldable};
use rustc_hir as ast; use rustc_hir as ast;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_span::DUMMY_SP; use rustc_span::DUMMY_SP;
@ -356,6 +356,30 @@ impl<'tcx> Relate<'tcx> for GeneratorWitness<'tcx> {
} }
} }
impl<'tcx> Relate<'tcx> for ImplSubject<'tcx> {
#[inline]
fn relate<R: TypeRelation<'tcx>>(
relation: &mut R,
a: ImplSubject<'tcx>,
b: ImplSubject<'tcx>,
) -> RelateResult<'tcx, ImplSubject<'tcx>> {
match (a, b) {
(ImplSubject::Trait(trait_ref_a), ImplSubject::Trait(trait_ref_b)) => {
let trait_ref = ty::TraitRef::relate(relation, trait_ref_a, trait_ref_b)?;
Ok(ImplSubject::Trait(trait_ref))
}
(ImplSubject::Inherent(ty_a), ImplSubject::Inherent(ty_b)) => {
let ty = Ty::relate(relation, ty_a, ty_b)?;
Ok(ImplSubject::Inherent(ty))
}
(ImplSubject::Trait(_), ImplSubject::Inherent(_))
| (ImplSubject::Inherent(_), ImplSubject::Trait(_)) => {
bug!("can not relate TraitRef and Ty");
}
}
}
}
impl<'tcx> Relate<'tcx> for Ty<'tcx> { impl<'tcx> Relate<'tcx> for Ty<'tcx> {
#[inline] #[inline]
fn relate<R: TypeRelation<'tcx>>( fn relate<R: TypeRelation<'tcx>>(

View File

@ -17,7 +17,6 @@ use crate::traits::{
use rustc_errors::Diagnostic; use rustc_errors::Diagnostic;
use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_hir::CRATE_HIR_ID; use rustc_hir::CRATE_HIR_ID;
use rustc_infer::infer::at::ToTrace;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::{util, TraitEngine}; use rustc_infer::traits::{util, TraitEngine};
use rustc_middle::traits::specialization_graph::OverlapMode; use rustc_middle::traits::specialization_graph::OverlapMode;
@ -305,64 +304,64 @@ fn negative_impl<'cx, 'tcx>(
// Create an infcx, taking the predicates of impl1 as assumptions: // Create an infcx, taking the predicates of impl1 as assumptions:
tcx.infer_ctxt().enter(|infcx| { tcx.infer_ctxt().enter(|infcx| {
// create a parameter environment corresponding to a (placeholder) instantiation of impl1 // create a parameter environment corresponding to a (placeholder) instantiation of impl1
let impl1_env = tcx.param_env(impl1_def_id); let impl_env = tcx.param_env(impl1_def_id);
let subject1 = match tcx.impl_subject(impl1_def_id) {
match tcx.impl_subject(impl1_def_id) {
ImplSubject::Trait(impl1_trait_ref) => { ImplSubject::Trait(impl1_trait_ref) => {
// Normalize the trait reference. The WF rules ought to ensure match traits::fully_normalize(
// that this always succeeds.
let impl1_trait_ref = match traits::fully_normalize(
&infcx, &infcx,
FulfillmentContext::new(), FulfillmentContext::new(),
ObligationCause::dummy(), ObligationCause::dummy(),
impl1_env, impl_env,
impl1_trait_ref, impl1_trait_ref,
) { ) {
Ok(impl1_trait_ref) => impl1_trait_ref, Ok(impl1_trait_ref) => ImplSubject::Trait(impl1_trait_ref),
Err(err) => { Err(err) => {
bug!("failed to fully normalize {:?}: {:?}", impl1_trait_ref, err); bug!("failed to fully normalize {:?}: {:?}", impl1_trait_ref, err);
} }
}
}
subject @ ImplSubject::Inherent(_) => subject,
}; };
let (subject2, obligations) =
impl_subject_and_obligations(&infcx, impl_env, subject1, impl2_def_id);
!equate(&infcx, impl_env, impl1_def_id, subject1, subject2, obligations)
})
}
fn impl_subject_and_obligations<'cx, 'tcx>(
infcx: &InferCtxt<'cx, 'tcx>,
impl_env: ty::ParamEnv<'tcx>,
subject1: ImplSubject<'tcx>,
impl2_def_id: DefId,
) -> (ImplSubject<'tcx>, Box<dyn Iterator<Item = PredicateObligation<'tcx>> + 'tcx>) {
if let ImplSubject::Trait(_) = subject1 {
// Attempt to prove that impl2 applies, given all of the above. // Attempt to prove that impl2 applies, given all of the above.
let selcx = &mut SelectionContext::new(&infcx); let selcx = &mut SelectionContext::new(&infcx);
let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id); let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id);
let (impl2_trait_ref, obligations) = let (impl2_trait_ref, obligations) =
impl_trait_ref_and_oblig(selcx, impl1_env, impl2_def_id, impl2_substs); impl_trait_ref_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs);
!equate( (ImplSubject::Trait(impl2_trait_ref), Box::new(obligations))
&infcx, } else {
impl1_env, (infcx.tcx.impl_subject(impl2_def_id), Box::new(iter::empty()))
impl1_def_id,
impl1_trait_ref,
impl2_trait_ref,
obligations,
)
} }
ImplSubject::Inherent(ty1) => {
let ty2 = tcx.type_of(impl2_def_id);
!equate(&infcx, impl1_env, impl1_def_id, ty1, ty2, iter::empty())
}
}
})
} }
fn equate<'cx, 'tcx, T: Debug + ToTrace<'tcx>>( fn equate<'cx, 'tcx>(
infcx: &InferCtxt<'cx, 'tcx>, infcx: &InferCtxt<'cx, 'tcx>,
impl1_env: ty::ParamEnv<'tcx>, impl_env: ty::ParamEnv<'tcx>,
impl1_def_id: DefId, impl1_def_id: DefId,
impl1: T, subject1: ImplSubject<'tcx>,
impl2: T, subject2: ImplSubject<'tcx>,
obligations: impl Iterator<Item = PredicateObligation<'tcx>>, obligations: impl Iterator<Item = PredicateObligation<'tcx>>,
) -> bool { ) -> bool {
// do the impls unify? If not, not disjoint. // do the impls unify? If not, not disjoint.
let Ok(InferOk { obligations: more_obligations, .. }) = infcx let Ok(InferOk { obligations: more_obligations, .. }) =
.at(&ObligationCause::dummy(), impl1_env) infcx.at(&ObligationCause::dummy(), impl_env).eq(subject1, subject2)
.eq(impl1, impl2) else { else {
debug!( debug!("explicit_disjoint: {:?} does not unify with {:?}", subject1, subject2);
"explicit_disjoint: {:?} does not unify with {:?}",
impl1, impl2
);
return true; return true;
}; };
@ -370,7 +369,7 @@ fn equate<'cx, 'tcx, T: Debug + ToTrace<'tcx>>(
let opt_failing_obligation = obligations let opt_failing_obligation = obligations
.into_iter() .into_iter()
.chain(more_obligations) .chain(more_obligations)
.find(|o| negative_impl_exists(selcx, impl1_env, impl1_def_id, o)); .find(|o| negative_impl_exists(selcx, impl_env, impl1_def_id, o));
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);