|
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::{
|
@@ -210,16 +210,53 @@ fn overlap<'tcx>(
|
210 | 210 | let equate_obligations = equate_impl_headers(selcx.infcx, &impl1_header, &impl2_header)?;
|
211 | 211 | debug!("overlap: unification check succeeded");
|
212 | 212 |
|
213 |
| - if overlap_mode.use_implicit_negative() |
214 |
| - && impl_intersection_has_impossible_obligation( |
215 |
| - selcx, |
216 |
| - param_env, |
217 |
| - &impl1_header, |
218 |
| - impl2_header, |
219 |
| - equate_obligations, |
220 |
| - ) |
221 |
| - { |
222 |
| - 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 | + "impls that are not considered to overlap may be considered to \ |
| 235 | + overlap in the future", |
| 236 | + |lint| { |
| 237 | + lint.span_label( |
| 238 | + infcx.tcx.def_span(impl1_header.impl_def_id), |
| 239 | + "the first impl is here", |
| 240 | + ) |
| 241 | + .span_label( |
| 242 | + infcx.tcx.def_span(impl2_header.impl_def_id), |
| 243 | + "the second impl is here", |
| 244 | + ); |
| 245 | + if !failing_obligation.cause.span.is_dummy() { |
| 246 | + lint.span_label( |
| 247 | + failing_obligation.cause.span, |
| 248 | + "this where-clause causes a cycle, but it may be treated \ |
| 249 | + as possibly holding in the future, causing the impls to overlap", |
| 250 | + ); |
| 251 | + } |
| 252 | + lint |
| 253 | + }, |
| 254 | + ); |
| 255 | + } |
| 256 | + |
| 257 | + return None; |
| 258 | + } |
| 259 | + } |
223 | 260 | }
|
224 | 261 |
|
225 | 262 | // We toggle the `leak_check` by using `skip_leak_check` when constructing the
|
@@ -287,78 +324,30 @@ fn impl_intersection_has_impossible_obligation<'cx, 'tcx>(
|
287 | 324 | selcx: &mut SelectionContext<'cx, 'tcx>,
|
288 | 325 | param_env: ty::ParamEnv<'tcx>,
|
289 | 326 | impl1_header: &ty::ImplHeader<'tcx>,
|
290 |
| - impl2_header: ty::ImplHeader<'tcx>, |
291 |
| - obligations: PredicateObligations<'tcx>, |
292 |
| -) -> bool { |
| 327 | + impl2_header: &ty::ImplHeader<'tcx>, |
| 328 | + obligations: &PredicateObligations<'tcx>, |
| 329 | +) -> Option<PredicateObligation<'tcx>> { |
293 | 330 | let infcx = selcx.infcx;
|
294 | 331 |
|
295 |
| - let obligation_guaranteed_to_fail = |obligation: &PredicateObligation<'tcx>| { |
296 |
| - if infcx.next_trait_solver() { |
297 |
| - infcx.evaluate_obligation(obligation).map_or(false, |result| !result.may_apply()) |
298 |
| - } else { |
299 |
| - // We use `evaluate_root_obligation` to correctly track intercrate |
300 |
| - // ambiguity clauses. We cannot use this in the new solver. |
301 |
| - selcx.evaluate_root_obligation(obligation).map_or( |
302 |
| - false, // Overflow has occurred, and treat the obligation as possibly holding. |
303 |
| - |result| !result.may_apply(), |
304 |
| - ) |
305 |
| - } |
306 |
| - }; |
307 |
| - |
308 |
| - let opt_failing_obligation = [&impl1_header.predicates, &impl2_header.predicates] |
| 332 | + [&impl1_header.predicates, &impl2_header.predicates] |
309 | 333 | .into_iter()
|
310 | 334 | .flatten()
|
311 | 335 | .map(|&(predicate, span)| {
|
312 | 336 | Obligation::new(infcx.tcx, ObligationCause::dummy_with_span(span), param_env, predicate)
|
313 | 337 | })
|
314 |
| - .chain(obligations) |
315 |
| - .find(obligation_guaranteed_to_fail); |
316 |
| - |
317 |
| - if let Some(failing_obligation) = opt_failing_obligation { |
318 |
| - // Check the failing obligation once again, treating inductive cycles as |
319 |
| - // ambiguous instead of error. |
320 |
| - if !infcx.next_trait_solver() |
321 |
| - && SelectionContext::with_treat_inductive_cycle_as_ambiguous(infcx) |
322 |
| - .evaluate_root_obligation(&failing_obligation) |
323 |
| - .map_or(true, |result| result.may_apply()) |
324 |
| - { |
325 |
| - let first_local_impl = impl1_header |
326 |
| - .impl_def_id |
327 |
| - .as_local() |
328 |
| - .or(impl2_header.impl_def_id.as_local()) |
329 |
| - .expect("expected one of the impls to be local"); |
330 |
| - infcx.tcx.struct_span_lint_hir( |
331 |
| - COINDUCTIVE_OVERLAP_IN_COHERENCE, |
332 |
| - infcx.tcx.local_def_id_to_hir_id(first_local_impl), |
333 |
| - infcx.tcx.def_span(first_local_impl), |
334 |
| - "impls that are not considered to overlap may be considered to \ |
335 |
| - overlap in the future", |
336 |
| - |lint| { |
337 |
| - lint.span_label( |
338 |
| - infcx.tcx.def_span(impl1_header.impl_def_id), |
339 |
| - "the first impl is here", |
340 |
| - ) |
341 |
| - .span_label( |
342 |
| - infcx.tcx.def_span(impl2_header.impl_def_id), |
343 |
| - "the second impl is here", |
344 |
| - ); |
345 |
| - if !failing_obligation.cause.span.is_dummy() { |
346 |
| - lint.span_label( |
347 |
| - failing_obligation.cause.span, |
348 |
| - "this where-clause causes a cycle, but it may be treated \ |
349 |
| - as possibly holding in the future, causing the impls to overlap", |
350 |
| - ); |
351 |
| - } |
352 |
| - lint |
353 |
| - }, |
354 |
| - ); |
355 |
| - } |
356 |
| - |
357 |
| - debug!("overlap: obligation unsatisfiable {:?}", failing_obligation); |
358 |
| - true |
359 |
| - } else { |
360 |
| - false |
361 |
| - } |
| 338 | + .chain(obligations.into_iter().cloned()) |
| 339 | + .find(|obligation: &PredicateObligation<'tcx>| { |
| 340 | + if infcx.next_trait_solver() { |
| 341 | + infcx.evaluate_obligation(obligation).map_or(false, |result| !result.may_apply()) |
| 342 | + } else { |
| 343 | + // We use `evaluate_root_obligation` to correctly track intercrate |
| 344 | + // ambiguity clauses. We cannot use this in the new solver. |
| 345 | + selcx.evaluate_root_obligation(obligation).map_or( |
| 346 | + false, // Overflow has occurred, and treat the obligation as possibly holding. |
| 347 | + |result| !result.may_apply(), |
| 348 | + ) |
| 349 | + } |
| 350 | + }) |
362 | 351 | }
|
363 | 352 |
|
364 | 353 | /// Check if both impls can be satisfied by a common type by considering whether
|
|
0 commit comments