From 22b311bd826f0a79abfdd2483eed933e86baa31e Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 24 Mar 2022 12:27:09 -0300 Subject: [PATCH] Extract impl_subject_and_oglibations fn and make equate receive subjects --- compiler/rustc_infer/src/infer/at.rs | 25 +++++- compiler/rustc_middle/src/ty/mod.rs | 3 +- compiler/rustc_middle/src/ty/relate.rs | 26 +++++- .../src/traits/coherence.rs | 87 +++++++++---------- 4 files changed, 94 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 94991fdb201..ff8082840e1 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -28,7 +28,7 @@ use super::*; use rustc_middle::ty::relate::{Relate, TypeRelation}; -use rustc_middle::ty::Const; +use rustc_middle::ty::{Const, ImplSubject}; pub struct At<'a, 'tcx> { pub infcx: &'a InferCtxt<'a, 'tcx>, @@ -272,6 +272,29 @@ pub fn glb(self, a: T, b: T) -> InferResult<'tcx, T> } } +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> { fn to_trace( _: TyCtxt<'tcx>, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 91d2d64c52e..3a0019cf92b 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -44,6 +44,7 @@ use rustc_span::Span; use rustc_target::abi::Align; +use std::fmt::Debug; use std::hash::Hash; use std::ops::ControlFlow; use std::{fmt, str}; @@ -172,7 +173,7 @@ pub struct ImplHeader<'tcx> { pub predicates: Vec>, } -#[derive(Debug)] +#[derive(Copy, Clone, Debug, TypeFoldable)] pub enum ImplSubject<'tcx> { Trait(TraitRef<'tcx>), Inherent(Ty<'tcx>), diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 81ee7942c4d..99cd0c789de 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -7,7 +7,7 @@ use crate::mir::interpret::{get_slice_bytes, ConstValue, GlobalAlloc, Scalar}; use crate::ty::error::{ExpectedFound, TypeError}; 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::def_id::DefId; use rustc_span::DUMMY_SP; @@ -356,6 +356,30 @@ fn relate>( } } +impl<'tcx> Relate<'tcx> for ImplSubject<'tcx> { + #[inline] + fn relate>( + 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> { #[inline] fn relate>( diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 559401c0bd1..7ac6c083076 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -17,7 +17,6 @@ use rustc_errors::Diagnostic; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::CRATE_HIR_ID; -use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{util, TraitEngine}; use rustc_middle::traits::specialization_graph::OverlapMode; @@ -305,72 +304,72 @@ fn negative_impl<'cx, 'tcx>( // Create an infcx, taking the predicates of impl1 as assumptions: tcx.infer_ctxt().enter(|infcx| { // create a parameter environment corresponding to a (placeholder) instantiation of impl1 - let impl1_env = tcx.param_env(impl1_def_id); - - match tcx.impl_subject(impl1_def_id) { + let impl_env = tcx.param_env(impl1_def_id); + let subject1 = match tcx.impl_subject(impl1_def_id) { ImplSubject::Trait(impl1_trait_ref) => { - // Normalize the trait reference. The WF rules ought to ensure - // that this always succeeds. - let impl1_trait_ref = match traits::fully_normalize( + match traits::fully_normalize( &infcx, FulfillmentContext::new(), ObligationCause::dummy(), - impl1_env, + impl_env, impl1_trait_ref, ) { - Ok(impl1_trait_ref) => impl1_trait_ref, + Ok(impl1_trait_ref) => ImplSubject::Trait(impl1_trait_ref), Err(err) => { bug!("failed to fully normalize {:?}: {:?}", impl1_trait_ref, err); } - }; - - // Attempt to prove that impl2 applies, given all of the above. - let selcx = &mut SelectionContext::new(&infcx); - let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id); - let (impl2_trait_ref, obligations) = - impl_trait_ref_and_oblig(selcx, impl1_env, impl2_def_id, impl2_substs); - - !equate( - &infcx, - impl1_env, - 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()) - } - } + 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 equate<'cx, 'tcx, T: Debug + ToTrace<'tcx>>( +fn impl_subject_and_obligations<'cx, 'tcx>( infcx: &InferCtxt<'cx, 'tcx>, - impl1_env: ty::ParamEnv<'tcx>, + impl_env: ty::ParamEnv<'tcx>, + subject1: ImplSubject<'tcx>, + impl2_def_id: DefId, +) -> (ImplSubject<'tcx>, Box> + 'tcx>) { + if let ImplSubject::Trait(_) = subject1 { + // Attempt to prove that impl2 applies, given all of the above. + let selcx = &mut SelectionContext::new(&infcx); + let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id); + let (impl2_trait_ref, obligations) = + impl_trait_ref_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs); + + (ImplSubject::Trait(impl2_trait_ref), Box::new(obligations)) + } else { + (infcx.tcx.impl_subject(impl2_def_id), Box::new(iter::empty())) + } +} + +fn equate<'cx, 'tcx>( + infcx: &InferCtxt<'cx, 'tcx>, + impl_env: ty::ParamEnv<'tcx>, impl1_def_id: DefId, - impl1: T, - impl2: T, + subject1: ImplSubject<'tcx>, + subject2: ImplSubject<'tcx>, obligations: impl Iterator>, ) -> bool { // do the impls unify? If not, not disjoint. - let Ok(InferOk { obligations: more_obligations, .. }) = infcx - .at(&ObligationCause::dummy(), impl1_env) - .eq(impl1, impl2) else { - debug!( - "explicit_disjoint: {:?} does not unify with {:?}", - impl1, impl2 - ); - return true; - }; + let Ok(InferOk { obligations: more_obligations, .. }) = + infcx.at(&ObligationCause::dummy(), impl_env).eq(subject1, subject2) + else { + debug!("explicit_disjoint: {:?} does not unify with {:?}", subject1, subject2); + return true; + }; let selcx = &mut SelectionContext::new(&infcx); let opt_failing_obligation = obligations .into_iter() .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 { debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);