diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 1053f0cefbed..4bc0d3a4d860 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -7,10 +7,10 @@ pub mod nested_filter; pub mod place; use crate::ty::query::Providers; -use crate::ty::TyCtxt; +use crate::ty::{ImplSubject, TyCtxt}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_hir::def_id::LocalDefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::*; use rustc_query_system::ich::StableHashingContext; use rustc_span::DUMMY_SP; @@ -54,6 +54,12 @@ impl<'tcx> TyCtxt<'tcx> { pub fn parent_module(self, id: HirId) -> LocalDefId { self.parent_module_from_def_id(id.owner) } + + pub fn impl_header(self, def_id: DefId) -> ImplSubject<'tcx> { + self.impl_trait_ref(def_id) + .map(ImplSubject::Trait) + .unwrap_or_else(|| ImplSubject::Inherent(self.type_of(def_id))) + } } pub fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 83ab761aa55a..91d2d64c52e4 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -172,6 +172,12 @@ pub struct ImplHeader<'tcx> { pub predicates: Vec>, } +#[derive(Debug)] +pub enum ImplSubject<'tcx> { + Trait(TraitRef<'tcx>), + Inherent(Ty<'tcx>), +} + #[derive( Copy, Clone, diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 8698384800c5..a0fbf94c01d4 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -24,7 +24,7 @@ use rustc_middle::traits::specialization_graph::OverlapMode; use rustc_middle::ty::fast_reject::{self, TreatParams}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::Subst; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt}; use rustc_span::symbol::sym; use rustc_span::DUMMY_SP; use std::fmt::Debug; @@ -307,46 +307,47 @@ fn negative_impl<'cx, 'tcx>( // create a parameter environment corresponding to a (placeholder) instantiation of impl1 let impl1_env = tcx.param_env(impl1_def_id); - if let Some(impl1_trait_ref) = tcx.impl_trait_ref(impl1_def_id) { - // Normalize the trait reference. The WF rules ought to ensure - // that this always succeeds. - let impl1_trait_ref = match traits::fully_normalize( - &infcx, - FulfillmentContext::new(), - ObligationCause::dummy(), - impl1_env, - impl1_trait_ref, - ) { - Ok(impl1_trait_ref) => impl1_trait_ref, - Err(err) => { - bug!("failed to fully normalize {:?}: {:?}", impl1_trait_ref, err); - } - }; + match tcx.impl_header(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( + &infcx, + FulfillmentContext::new(), + ObligationCause::dummy(), + impl1_env, + impl1_trait_ref, + ) { + Ok(impl1_trait_ref) => 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); + // 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); - !obligations_satisfiable( - &infcx, - impl1_env, - impl1_def_id, - impl1_trait_ref, - impl2_trait_ref, - obligations, - ) - } else { - let ty1 = tcx.type_of(impl1_def_id); - let ty2 = tcx.type_of(impl2_def_id); - - !obligations_satisfiable(&infcx, impl1_env, impl1_def_id, ty1, ty2, iter::empty()) + !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()) + } } }) } -fn obligations_satisfiable<'cx, 'tcx, T: Debug + ToTrace<'tcx>>( +fn equate<'cx, 'tcx, T: Debug + ToTrace<'tcx>>( infcx: &InferCtxt<'cx, 'tcx>, impl1_env: ty::ParamEnv<'tcx>, impl1_def_id: DefId,