7
7
use crate :: infer:: outlives:: env:: OutlivesEnvironment ;
8
8
use crate :: infer:: InferOk ;
9
9
use crate :: traits:: outlives_bounds:: InferCtxtExt as _;
10
- use crate :: traits:: select:: IntercrateAmbiguityCause ;
10
+ use crate :: traits:: select:: { IntercrateAmbiguityCause , TreatInductiveCycleAs } ;
11
11
use crate :: traits:: util:: impl_subject_and_oblig;
12
12
use crate :: traits:: SkipLeakCheck ;
13
13
use crate :: traits:: {
@@ -24,6 +24,7 @@ use rustc_middle::traits::DefiningAnchor;
24
24
use rustc_middle:: ty:: fast_reject:: { DeepRejectCtxt , TreatParams } ;
25
25
use rustc_middle:: ty:: visit:: { TypeVisitable , TypeVisitableExt } ;
26
26
use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeVisitor } ;
27
+ use rustc_session:: lint:: builtin:: COINDUCTIVE_OVERLAP_IN_COHERENCE ;
27
28
use rustc_span:: symbol:: sym;
28
29
use rustc_span:: DUMMY_SP ;
29
30
use std:: fmt:: Debug ;
@@ -151,14 +152,16 @@ fn with_fresh_ty_vars<'cx, 'tcx>(
151
152
. predicates_of ( impl_def_id)
152
153
. instantiate ( tcx, impl_args)
153
154
. iter ( )
154
- . map ( |( c, _ ) | c. as_predicate ( ) )
155
+ . map ( |( c, s ) | ( c. as_predicate ( ) , s ) )
155
156
. collect ( ) ,
156
157
} ;
157
158
158
- let InferOk { value : mut header, obligations } =
159
- selcx. infcx . at ( & ObligationCause :: dummy ( ) , param_env) . normalize ( header) ;
159
+ let InferOk { value : mut header, obligations } = selcx
160
+ . infcx
161
+ . at ( & ObligationCause :: dummy_with_span ( tcx. def_span ( impl_def_id) ) , param_env)
162
+ . normalize ( header) ;
160
163
161
- header. predicates . extend ( obligations. into_iter ( ) . map ( |o| o. predicate ) ) ;
164
+ header. predicates . extend ( obligations. into_iter ( ) . map ( |o| ( o. predicate , o . cause . span ) ) ) ;
162
165
header
163
166
}
164
167
@@ -207,16 +210,76 @@ fn overlap<'tcx>(
207
210
let equate_obligations = equate_impl_headers ( selcx. infcx , & impl1_header, & impl2_header) ?;
208
211
debug ! ( "overlap: unification check succeeded" ) ;
209
212
210
- if overlap_mode. use_implicit_negative ( )
211
- && impl_intersection_has_impossible_obligation (
212
- selcx,
213
- param_env,
214
- & impl1_header,
215
- impl2_header,
216
- equate_obligations,
217
- )
218
- {
219
- return None ;
213
+ if overlap_mode. use_implicit_negative ( ) {
214
+ for mode in [ TreatInductiveCycleAs :: Ambig , TreatInductiveCycleAs :: Recur ] {
215
+ if let Some ( failing_obligation) = selcx. with_treat_inductive_cycle_as ( mode, |selcx| {
216
+ impl_intersection_has_impossible_obligation (
217
+ selcx,
218
+ param_env,
219
+ & impl1_header,
220
+ & impl2_header,
221
+ & equate_obligations,
222
+ )
223
+ } ) {
224
+ if matches ! ( mode, TreatInductiveCycleAs :: Recur ) {
225
+ let first_local_impl = impl1_header
226
+ . impl_def_id
227
+ . as_local ( )
228
+ . or ( impl2_header. impl_def_id . as_local ( ) )
229
+ . expect ( "expected one of the impls to be local" ) ;
230
+ infcx. tcx . struct_span_lint_hir (
231
+ COINDUCTIVE_OVERLAP_IN_COHERENCE ,
232
+ infcx. tcx . local_def_id_to_hir_id ( first_local_impl) ,
233
+ infcx. tcx . def_span ( first_local_impl) ,
234
+ format ! (
235
+ "implementations {} will conflict in the future" ,
236
+ match impl1_header. trait_ref {
237
+ Some ( trait_ref) => {
238
+ let trait_ref = infcx. resolve_vars_if_possible( trait_ref) ;
239
+ format!(
240
+ "of `{}` for `{}`" ,
241
+ trait_ref. print_only_trait_path( ) ,
242
+ trait_ref. self_ty( )
243
+ )
244
+ }
245
+ None => format!(
246
+ "for `{}`" ,
247
+ infcx. resolve_vars_if_possible( impl1_header. self_ty)
248
+ ) ,
249
+ } ,
250
+ ) ,
251
+ |lint| {
252
+ lint. note (
253
+ "impls that are not considered to overlap may be considered to \
254
+ overlap in the future",
255
+ )
256
+ . span_label (
257
+ infcx. tcx . def_span ( impl1_header. impl_def_id ) ,
258
+ "the first impl is here" ,
259
+ )
260
+ . span_label (
261
+ infcx. tcx . def_span ( impl2_header. impl_def_id ) ,
262
+ "the second impl is here" ,
263
+ ) ;
264
+ if !failing_obligation. cause . span . is_dummy ( ) {
265
+ lint. span_label (
266
+ failing_obligation. cause . span ,
267
+ format ! (
268
+ "`{}` may be considered to hold in future releases, \
269
+ causing the impls to overlap",
270
+ infcx
271
+ . resolve_vars_if_possible( failing_obligation. predicate)
272
+ ) ,
273
+ ) ;
274
+ }
275
+ lint
276
+ } ,
277
+ ) ;
278
+ }
279
+
280
+ return None ;
281
+ }
282
+ }
220
283
}
221
284
222
285
// We toggle the `leak_check` by using `skip_leak_check` when constructing the
@@ -284,40 +347,30 @@ fn impl_intersection_has_impossible_obligation<'cx, 'tcx>(
284
347
selcx : & mut SelectionContext < ' cx , ' tcx > ,
285
348
param_env : ty:: ParamEnv < ' tcx > ,
286
349
impl1_header : & ty:: ImplHeader < ' tcx > ,
287
- impl2_header : ty:: ImplHeader < ' tcx > ,
288
- obligations : PredicateObligations < ' tcx > ,
289
- ) -> bool {
350
+ impl2_header : & ty:: ImplHeader < ' tcx > ,
351
+ obligations : & PredicateObligations < ' tcx > ,
352
+ ) -> Option < PredicateObligation < ' tcx > > {
290
353
let infcx = selcx. infcx ;
291
354
292
- let obligation_guaranteed_to_fail = move |obligation : & PredicateObligation < ' tcx > | {
293
- if infcx. next_trait_solver ( ) {
294
- infcx. evaluate_obligation ( obligation) . map_or ( false , |result| !result. may_apply ( ) )
295
- } else {
296
- // We use `evaluate_root_obligation` to correctly track
297
- // intercrate ambiguity clauses. We do not need this in the
298
- // new solver.
299
- selcx. evaluate_root_obligation ( obligation) . map_or (
300
- false , // Overflow has occurred, and treat the obligation as possibly holding.
301
- |result| !result. may_apply ( ) ,
302
- )
303
- }
304
- } ;
305
-
306
- let opt_failing_obligation = [ & impl1_header. predicates , & impl2_header. predicates ]
355
+ [ & impl1_header. predicates , & impl2_header. predicates ]
307
356
. into_iter ( )
308
357
. flatten ( )
309
- . map ( |& predicate| {
310
- Obligation :: new ( infcx. tcx , ObligationCause :: dummy ( ) , param_env, predicate)
358
+ . map ( |& ( predicate, span) | {
359
+ Obligation :: new ( infcx. tcx , ObligationCause :: dummy_with_span ( span) , param_env, predicate)
360
+ } )
361
+ . chain ( obligations. into_iter ( ) . cloned ( ) )
362
+ . find ( |obligation : & PredicateObligation < ' tcx > | {
363
+ if infcx. next_trait_solver ( ) {
364
+ infcx. evaluate_obligation ( obligation) . map_or ( false , |result| !result. may_apply ( ) )
365
+ } else {
366
+ // We use `evaluate_root_obligation` to correctly track intercrate
367
+ // ambiguity clauses. We cannot use this in the new solver.
368
+ selcx. evaluate_root_obligation ( obligation) . map_or (
369
+ false , // Overflow has occurred, and treat the obligation as possibly holding.
370
+ |result| !result. may_apply ( ) ,
371
+ )
372
+ }
311
373
} )
312
- . chain ( obligations)
313
- . find ( obligation_guaranteed_to_fail) ;
314
-
315
- if let Some ( failing_obligation) = opt_failing_obligation {
316
- debug ! ( "overlap: obligation unsatisfiable {:?}" , failing_obligation) ;
317
- true
318
- } else {
319
- false
320
- }
321
374
}
322
375
323
376
/// Check if both impls can be satisfied by a common type by considering whether
0 commit comments