@@ -11,7 +11,7 @@ use crate::traits::util::impl_trait_ref_and_oblig;
1111use crate :: traits:: SkipLeakCheck ;
1212use crate :: traits:: {
1313 self , FulfillmentContext , Normalized , Obligation , ObligationCause , PredicateObligation ,
14- SelectionContext ,
14+ PredicateObligations , SelectionContext ,
1515} ;
1616use rustc_hir:: def_id:: { DefId , LOCAL_CRATE } ;
1717use rustc_middle:: ty:: fast_reject:: { self , SimplifyParams , StripReferences } ;
@@ -137,12 +137,23 @@ fn with_fresh_ty_vars<'cx, 'tcx>(
137137 header
138138}
139139
140+ #[ derive( Copy , Clone , PartialEq , Eq , Hash , Debug ) ]
140141enum OverlapMode {
141142 Stable ,
142143 WithNegative ,
143144 Strict ,
144145}
145146
147+ impl OverlapMode {
148+ fn use_negative_impl ( & self ) -> bool {
149+ * self == OverlapMode :: Strict || * self == OverlapMode :: WithNegative
150+ }
151+
152+ fn use_implicit_negative ( & self ) -> bool {
153+ * self == OverlapMode :: Stable || * self == OverlapMode :: WithNegative
154+ }
155+ }
156+
146157fn overlap_mode < ' tcx > ( tcx : TyCtxt < ' tcx > , impl1_def_id : DefId , impl2_def_id : DefId ) -> OverlapMode {
147158 if tcx. has_attr ( impl1_def_id, sym:: rustc_strict_coherence)
148159 != tcx. has_attr ( impl2_def_id, sym:: rustc_strict_coherence)
@@ -190,6 +201,16 @@ fn overlap_within_probe<'cx, 'tcx>(
190201 let infcx = selcx. infcx ( ) ;
191202 let tcx = infcx. tcx ;
192203
204+ let overlap_mode = overlap_mode ( tcx, impl1_def_id, impl2_def_id) ;
205+
206+ if overlap_mode. use_negative_impl ( ) {
207+ if negative_impl ( selcx, impl1_def_id, impl2_def_id)
208+ || negative_impl ( selcx, impl2_def_id, impl1_def_id)
209+ {
210+ return None ;
211+ }
212+ }
213+
193214 // For the purposes of this check, we don't bring any placeholder
194215 // types into scope; instead, we replace the generic types with
195216 // fresh type variables, and hence we do our evaluations in an
@@ -199,29 +220,15 @@ fn overlap_within_probe<'cx, 'tcx>(
199220 let impl1_header = with_fresh_ty_vars ( selcx, param_env, impl1_def_id) ;
200221 let impl2_header = with_fresh_ty_vars ( selcx, param_env, impl2_def_id) ;
201222
202- match overlap_mode ( tcx, impl1_def_id, impl2_def_id) {
203- OverlapMode :: Stable => {
204- if stable_disjoint ( selcx, param_env, & impl1_header, impl2_header) {
205- return None ;
206- }
207- }
208- OverlapMode :: Strict => {
209- if strict_disjoint ( selcx, impl1_def_id, impl2_def_id) {
210- return None ;
211- }
223+ debug ! ( "overlap: impl1_header={:?}" , impl1_header) ;
224+ debug ! ( "overlap: impl2_header={:?}" , impl2_header) ;
212225
213- // Equate for error reporting
214- let _ = selcx
215- . infcx ( )
216- . at ( & ObligationCause :: dummy ( ) , param_env)
217- . eq_impl_headers ( & impl1_header, & impl2_header) ;
218- }
219- OverlapMode :: WithNegative => {
220- if stable_disjoint ( selcx, param_env, & impl1_header, impl2_header)
221- || strict_disjoint ( selcx, impl1_def_id, impl2_def_id)
222- {
223- return None ;
224- }
226+ let obligations = equate_impl_headers ( selcx, & impl1_header, & impl2_header) ?;
227+ debug ! ( "overlap: unification check succeeded" ) ;
228+
229+ if overlap_mode. use_implicit_negative ( ) {
230+ if implicit_negative ( selcx, param_env, & impl1_header, impl2_header, obligations) {
231+ return None ;
225232 }
226233 }
227234
@@ -242,31 +249,29 @@ fn overlap_within_probe<'cx, 'tcx>(
242249 Some ( OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder } )
243250}
244251
252+ fn equate_impl_headers < ' cx , ' tcx > (
253+ selcx : & mut SelectionContext < ' cx , ' tcx > ,
254+ impl1_header : & ty:: ImplHeader < ' tcx > ,
255+ impl2_header : & ty:: ImplHeader < ' tcx > ,
256+ ) -> Option < PredicateObligations < ' tcx > > {
257+ // Do `a` and `b` unify? If not, no overlap.
258+ selcx
259+ . infcx ( )
260+ . at ( & ObligationCause :: dummy ( ) , ty:: ParamEnv :: empty ( ) )
261+ . eq_impl_headers ( impl1_header, impl2_header)
262+ . map ( |infer_ok| infer_ok. obligations )
263+ . ok ( )
264+ }
265+
245266/// Given impl1 and impl2 check if both impls can be satisfied by a common type (including
246267/// where-clauses) If so, return false, otherwise return true, they are disjoint.
247- fn stable_disjoint < ' cx , ' tcx > (
268+ fn implicit_negative < ' cx , ' tcx > (
248269 selcx : & mut SelectionContext < ' cx , ' tcx > ,
249270 param_env : ty:: ParamEnv < ' tcx > ,
250271 impl1_header : & ty:: ImplHeader < ' tcx > ,
251272 impl2_header : ty:: ImplHeader < ' tcx > ,
273+ obligations : PredicateObligations < ' tcx > ,
252274) -> bool {
253- debug ! ( "overlap: impl1_header={:?}" , impl1_header) ;
254- debug ! ( "overlap: impl2_header={:?}" , impl2_header) ;
255-
256- // Do `a` and `b` unify? If not, no overlap.
257- let obligations = match selcx
258- . infcx ( )
259- . at ( & ObligationCause :: dummy ( ) , param_env)
260- . eq_impl_headers ( & impl1_header, & impl2_header)
261- {
262- Ok ( InferOk { obligations, value : ( ) } ) => obligations,
263- Err ( _) => {
264- return true ;
265- }
266- } ;
267-
268- debug ! ( "overlap: unification check succeeded" ) ;
269-
270275 // There's no overlap if obligations are unsatisfiable or if the obligation negated is
271276 // satisfied.
272277 //
@@ -318,16 +323,7 @@ fn stable_disjoint<'cx, 'tcx>(
318323
319324/// Given impl1 and impl2 check if both impls are never satisfied by a common type (including
320325/// where-clauses) If so, return true, they are disjoint and false otherwise.
321- fn strict_disjoint < ' cx , ' tcx > (
322- selcx : & mut SelectionContext < ' cx , ' tcx > ,
323- impl1_def_id : DefId ,
324- impl2_def_id : DefId ,
325- ) -> bool {
326- explicit_disjoint ( selcx, impl1_def_id, impl2_def_id)
327- || explicit_disjoint ( selcx, impl2_def_id, impl1_def_id)
328- }
329-
330- fn explicit_disjoint < ' cx , ' tcx > (
326+ fn negative_impl < ' cx , ' tcx > (
331327 selcx : & mut SelectionContext < ' cx , ' tcx > ,
332328 impl1_def_id : DefId ,
333329 impl2_def_id : DefId ,
0 commit comments