@@ -11,7 +11,7 @@ use crate::traits::util::impl_trait_ref_and_oblig;
11
11
use crate :: traits:: SkipLeakCheck ;
12
12
use crate :: traits:: {
13
13
self , FulfillmentContext , Normalized , Obligation , ObligationCause , PredicateObligation ,
14
- SelectionContext ,
14
+ PredicateObligations , SelectionContext ,
15
15
} ;
16
16
use rustc_hir:: def_id:: { DefId , LOCAL_CRATE } ;
17
17
use rustc_middle:: ty:: fast_reject:: { self , SimplifyParams , StripReferences } ;
@@ -137,12 +137,23 @@ fn with_fresh_ty_vars<'cx, 'tcx>(
137
137
header
138
138
}
139
139
140
+ #[ derive( Copy , Clone , PartialEq , Eq , Hash , Debug ) ]
140
141
enum OverlapMode {
141
142
Stable ,
142
143
WithNegative ,
143
144
Strict ,
144
145
}
145
146
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
+
146
157
fn overlap_mode < ' tcx > ( tcx : TyCtxt < ' tcx > , impl1_def_id : DefId , impl2_def_id : DefId ) -> OverlapMode {
147
158
if tcx. has_attr ( impl1_def_id, sym:: rustc_strict_coherence)
148
159
!= tcx. has_attr ( impl2_def_id, sym:: rustc_strict_coherence)
@@ -190,6 +201,16 @@ fn overlap_within_probe<'cx, 'tcx>(
190
201
let infcx = selcx. infcx ( ) ;
191
202
let tcx = infcx. tcx ;
192
203
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
+
193
214
// For the purposes of this check, we don't bring any placeholder
194
215
// types into scope; instead, we replace the generic types with
195
216
// fresh type variables, and hence we do our evaluations in an
@@ -199,29 +220,15 @@ fn overlap_within_probe<'cx, 'tcx>(
199
220
let impl1_header = with_fresh_ty_vars ( selcx, param_env, impl1_def_id) ;
200
221
let impl2_header = with_fresh_ty_vars ( selcx, param_env, impl2_def_id) ;
201
222
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) ;
212
225
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 ;
225
232
}
226
233
}
227
234
@@ -242,31 +249,29 @@ fn overlap_within_probe<'cx, 'tcx>(
242
249
Some ( OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder } )
243
250
}
244
251
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
+
245
266
/// Given impl1 and impl2 check if both impls can be satisfied by a common type (including
246
267
/// where-clauses) If so, return false, otherwise return true, they are disjoint.
247
- fn stable_disjoint < ' cx , ' tcx > (
268
+ fn implicit_negative < ' cx , ' tcx > (
248
269
selcx : & mut SelectionContext < ' cx , ' tcx > ,
249
270
param_env : ty:: ParamEnv < ' tcx > ,
250
271
impl1_header : & ty:: ImplHeader < ' tcx > ,
251
272
impl2_header : ty:: ImplHeader < ' tcx > ,
273
+ obligations : PredicateObligations < ' tcx > ,
252
274
) -> 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
-
270
275
// There's no overlap if obligations are unsatisfiable or if the obligation negated is
271
276
// satisfied.
272
277
//
@@ -318,16 +323,7 @@ fn stable_disjoint<'cx, 'tcx>(
318
323
319
324
/// Given impl1 and impl2 check if both impls are never satisfied by a common type (including
320
325
/// 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 > (
331
327
selcx : & mut SelectionContext < ' cx , ' tcx > ,
332
328
impl1_def_id : DefId ,
333
329
impl2_def_id : DefId ,
0 commit comments