77use crate :: infer:: outlives:: env:: OutlivesEnvironment ;
88use crate :: infer:: InferOk ;
99use crate :: traits:: outlives_bounds:: InferCtxtExt as _;
10- use crate :: traits:: select:: IntercrateAmbiguityCause ;
10+ use crate :: traits:: select:: { IntercrateAmbiguityCause , TreatInductiveCycleAs } ;
1111use crate :: traits:: util:: impl_subject_and_oblig;
1212use crate :: traits:: SkipLeakCheck ;
1313use crate :: traits:: {
@@ -24,6 +24,7 @@ use rustc_middle::traits::DefiningAnchor;
2424use rustc_middle:: ty:: fast_reject:: { DeepRejectCtxt , TreatParams } ;
2525use rustc_middle:: ty:: visit:: { TypeVisitable , TypeVisitableExt } ;
2626use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeVisitor } ;
27+ use rustc_session:: lint:: builtin:: COINDUCTIVE_OVERLAP_IN_COHERENCE ;
2728use rustc_span:: symbol:: sym;
2829use rustc_span:: DUMMY_SP ;
2930use std:: fmt:: Debug ;
@@ -151,14 +152,16 @@ fn with_fresh_ty_vars<'cx, 'tcx>(
151152 . predicates_of ( impl_def_id)
152153 . instantiate ( tcx, impl_args)
153154 . iter ( )
154- . map ( |( c, _ ) | c. as_predicate ( ) )
155+ . map ( |( c, s ) | ( c. as_predicate ( ) , s ) )
155156 . collect ( ) ,
156157 } ;
157158
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) ;
160163
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 ) ) ) ;
162165 header
163166}
164167
@@ -207,16 +210,76 @@ fn overlap<'tcx>(
207210 let equate_obligations = equate_impl_headers ( selcx. infcx , & impl1_header, & impl2_header) ?;
208211 debug ! ( "overlap: unification check succeeded" ) ;
209212
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+ }
220283 }
221284
222285 // 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>(
284347 selcx : & mut SelectionContext < ' cx , ' tcx > ,
285348 param_env : ty:: ParamEnv < ' tcx > ,
286349 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 > > {
290353 let infcx = selcx. infcx ;
291354
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 ]
307356 . into_iter ( )
308357 . 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+ }
311373 } )
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- }
321374}
322375
323376/// Check if both impls can be satisfied by a common type by considering whether
0 commit comments