1pub mod specialization_graph;
13
14use rustc_data_structures::fx::FxIndexSet;
15use rustc_errors::codes::*;
16use rustc_errors::{Diag, EmissionGuarantee};
17use rustc_hir::def_id::{DefId, LocalDefId};
18use rustc_infer::traits::Obligation;
19use rustc_middle::bug;
20use rustc_middle::query::LocalCrate;
21use rustc_middle::ty::print::PrintTraitRefExt as _;
22use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, TypingMode};
23use rustc_session::lint::builtin::{COHERENCE_LEAK_CHECK, ORDER_DEPENDENT_TRAIT_OBJECTS};
24use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, sym};
25use rustc_type_ir::solve::NoSolution;
26use specialization_graph::GraphExt;
27use tracing::{debug, instrument};
28
29use crate::error_reporting::traits::to_pretty_impl_header;
30use crate::errors::NegativePositiveConflict;
31use crate::infer::{InferCtxt, TyCtxtInferExt};
32use crate::traits::select::IntercrateAmbiguityCause;
33use crate::traits::{
34 FutureCompatOverlapErrorKind, ObligationCause, ObligationCtxt, coherence,
35 predicates_for_generics,
36};
37
38#[derive(Debug)]
40pub struct OverlapError<'tcx> {
41 pub with_impl: DefId,
42 pub trait_ref: ty::TraitRef<'tcx>,
43 pub self_ty: Option<Ty<'tcx>>,
44 pub intercrate_ambiguity_causes: FxIndexSet<IntercrateAmbiguityCause<'tcx>>,
45 pub involves_placeholder: bool,
46 pub overflowing_predicates: Vec<ty::Predicate<'tcx>>,
47}
48
49pub fn translate_args<'tcx>(
85 infcx: &InferCtxt<'tcx>,
86 param_env: ty::ParamEnv<'tcx>,
87 source_impl: DefId,
88 source_args: GenericArgsRef<'tcx>,
89 target_node: specialization_graph::Node,
90) -> GenericArgsRef<'tcx> {
91 translate_args_with_cause(
92 infcx,
93 param_env,
94 source_impl,
95 source_args,
96 target_node,
97 &ObligationCause::dummy(),
98 )
99}
100
101pub fn translate_args_with_cause<'tcx>(
108 infcx: &InferCtxt<'tcx>,
109 param_env: ty::ParamEnv<'tcx>,
110 source_impl: DefId,
111 source_args: GenericArgsRef<'tcx>,
112 target_node: specialization_graph::Node,
113 cause: &ObligationCause<'tcx>,
114) -> GenericArgsRef<'tcx> {
115 debug!(
116 "translate_args({:?}, {:?}, {:?}, {:?})",
117 param_env, source_impl, source_args, target_node
118 );
119 let source_trait_ref =
120 infcx.tcx.impl_trait_ref(source_impl).unwrap().instantiate(infcx.tcx, source_args);
121
122 let target_args = match target_node {
125 specialization_graph::Node::Impl(target_impl) => {
126 if source_impl == target_impl {
128 return source_args;
129 }
130
131 fulfill_implication(infcx, param_env, source_trait_ref, source_impl, target_impl, cause)
132 .unwrap_or_else(|_| {
133 bug!(
134 "When translating generic parameters from {source_impl:?} to \
135 {target_impl:?}, the expected specialization failed to hold"
136 )
137 })
138 }
139 specialization_graph::Node::Trait(..) => source_trait_ref.args,
140 };
141
142 source_args.rebase_onto(infcx.tcx, source_impl, target_args)
144}
145
146fn fulfill_implication<'tcx>(
152 infcx: &InferCtxt<'tcx>,
153 param_env: ty::ParamEnv<'tcx>,
154 source_trait_ref: ty::TraitRef<'tcx>,
155 source_impl: DefId,
156 target_impl: DefId,
157 cause: &ObligationCause<'tcx>,
158) -> Result<GenericArgsRef<'tcx>, NoSolution> {
159 debug!(
160 "fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)",
161 param_env, source_trait_ref, target_impl
162 );
163
164 let ocx = ObligationCtxt::new(infcx);
165 let source_trait_ref = ocx.normalize(cause, param_env, source_trait_ref);
166
167 if !ocx.select_all_or_error().is_empty() {
168 infcx.dcx().span_delayed_bug(
169 infcx.tcx.def_span(source_impl),
170 format!("failed to fully normalize {source_trait_ref}"),
171 );
172 return Err(NoSolution);
173 }
174
175 let target_args = infcx.fresh_args_for_item(DUMMY_SP, target_impl);
176 let target_trait_ref = ocx.normalize(
177 cause,
178 param_env,
179 infcx
180 .tcx
181 .impl_trait_ref(target_impl)
182 .expect("expected source impl to be a trait impl")
183 .instantiate(infcx.tcx, target_args),
184 );
185
186 ocx.eq(cause, param_env, source_trait_ref, target_trait_ref)?;
188
189 let predicates = ocx.normalize(
193 cause,
194 param_env,
195 infcx.tcx.predicates_of(target_impl).instantiate(infcx.tcx, target_args),
196 );
197 let obligations = predicates_for_generics(|_, _| cause.clone(), param_env, predicates);
198 ocx.register_obligations(obligations);
199
200 let errors = ocx.select_all_or_error();
201 if !errors.is_empty() {
202 debug!(
204 "fulfill_implication: for impls on {:?} and {:?}, \
205 could not fulfill: {:?} given {:?}",
206 source_trait_ref,
207 target_trait_ref,
208 errors,
209 param_env.caller_bounds()
210 );
211 return Err(NoSolution);
212 }
213
214 debug!(
215 "fulfill_implication: an impl for {:?} specializes {:?}",
216 source_trait_ref, target_trait_ref
217 );
218
219 Ok(infcx.resolve_vars_if_possible(target_args))
222}
223
224pub(super) fn specialization_enabled_in(tcx: TyCtxt<'_>, _: LocalCrate) -> bool {
225 tcx.features().specialization() || tcx.features().min_specialization()
226}
227
228#[instrument(skip(tcx), level = "debug")]
240pub(super) fn specializes(
241 tcx: TyCtxt<'_>,
242 (specializing_impl_def_id, parent_impl_def_id): (DefId, DefId),
243) -> bool {
244 if !tcx.specialization_enabled_in(specializing_impl_def_id.krate) {
251 let span = tcx.def_span(specializing_impl_def_id);
252 if !span.allows_unstable(sym::specialization)
253 && !span.allows_unstable(sym::min_specialization)
254 {
255 return false;
256 }
257 }
258
259 let specializing_impl_trait_header = tcx.impl_trait_header(specializing_impl_def_id).unwrap();
260
261 if specializing_impl_trait_header.polarity != tcx.impl_polarity(parent_impl_def_id) {
275 return false;
276 }
277
278 let param_env = tcx.param_env(specializing_impl_def_id);
281
282 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
284
285 let specializing_impl_trait_ref =
286 specializing_impl_trait_header.trait_ref.instantiate_identity();
287 let cause = &ObligationCause::dummy();
288 debug!(
289 "fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)",
290 param_env, specializing_impl_trait_ref, parent_impl_def_id
291 );
292
293 let ocx = ObligationCtxt::new(&infcx);
296 let specializing_impl_trait_ref = ocx.normalize(cause, param_env, specializing_impl_trait_ref);
297
298 if !ocx.select_all_or_error().is_empty() {
299 infcx.dcx().span_delayed_bug(
300 infcx.tcx.def_span(specializing_impl_def_id),
301 format!("failed to fully normalize {specializing_impl_trait_ref}"),
302 );
303 return false;
304 }
305
306 let parent_args = infcx.fresh_args_for_item(DUMMY_SP, parent_impl_def_id);
307 let parent_impl_trait_ref = ocx.normalize(
308 cause,
309 param_env,
310 infcx
311 .tcx
312 .impl_trait_ref(parent_impl_def_id)
313 .expect("expected source impl to be a trait impl")
314 .instantiate(infcx.tcx, parent_args),
315 );
316
317 let Ok(()) = ocx.eq(cause, param_env, specializing_impl_trait_ref, parent_impl_trait_ref)
319 else {
320 return false;
321 };
322
323 let predicates = ocx.normalize(
327 cause,
328 param_env,
329 infcx.tcx.predicates_of(parent_impl_def_id).instantiate(infcx.tcx, parent_args),
330 );
331 let obligations = predicates_for_generics(|_, _| cause.clone(), param_env, predicates);
332 ocx.register_obligations(obligations);
333
334 let errors = ocx.select_all_or_error();
335 if !errors.is_empty() {
336 debug!(
338 "fulfill_implication: for impls on {:?} and {:?}, \
339 could not fulfill: {:?} given {:?}",
340 specializing_impl_trait_ref,
341 parent_impl_trait_ref,
342 errors,
343 param_env.caller_bounds()
344 );
345 return false;
346 }
347
348 if tcx.is_conditionally_const(parent_impl_def_id) {
352 if !tcx.is_conditionally_const(specializing_impl_def_id) {
353 return false;
354 }
355
356 let const_conditions = ocx.normalize(
357 cause,
358 param_env,
359 infcx.tcx.const_conditions(parent_impl_def_id).instantiate(infcx.tcx, parent_args),
360 );
361 ocx.register_obligations(const_conditions.into_iter().map(|(trait_ref, _)| {
362 Obligation::new(
363 infcx.tcx,
364 cause.clone(),
365 param_env,
366 trait_ref.to_host_effect_clause(infcx.tcx, ty::BoundConstness::Maybe),
367 )
368 }));
369
370 let errors = ocx.select_all_or_error();
371 if !errors.is_empty() {
372 debug!(
374 "fulfill_implication: for impls on {:?} and {:?}, \
375 could not fulfill: {:?} given {:?}",
376 specializing_impl_trait_ref,
377 parent_impl_trait_ref,
378 errors,
379 param_env.caller_bounds()
380 );
381 return false;
382 }
383 }
384
385 debug!(
386 "fulfill_implication: an impl for {:?} specializes {:?}",
387 specializing_impl_trait_ref, parent_impl_trait_ref
388 );
389
390 true
391}
392
393pub(super) fn specialization_graph_provider(
395 tcx: TyCtxt<'_>,
396 trait_id: DefId,
397) -> Result<&'_ specialization_graph::Graph, ErrorGuaranteed> {
398 let mut sg = specialization_graph::Graph::new();
399 let overlap_mode = specialization_graph::OverlapMode::get(tcx, trait_id);
400
401 let mut trait_impls: Vec<_> = tcx.all_impls(trait_id).collect();
402
403 trait_impls
408 .sort_unstable_by_key(|def_id| (-(def_id.krate.as_u32() as i64), def_id.index.index()));
409
410 let mut errored = Ok(());
411
412 for impl_def_id in trait_impls {
413 if let Some(impl_def_id) = impl_def_id.as_local() {
414 let insert_result = sg.insert(tcx, impl_def_id.to_def_id(), overlap_mode);
416 let (overlap, used_to_be_allowed) = match insert_result {
418 Err(overlap) => (Some(overlap), None),
419 Ok(Some(overlap)) => (Some(overlap.error), Some(overlap.kind)),
420 Ok(None) => (None, None),
421 };
422
423 if let Some(overlap) = overlap {
424 errored = errored.and(report_overlap_conflict(
425 tcx,
426 overlap,
427 impl_def_id,
428 used_to_be_allowed,
429 ));
430 }
431 } else {
432 let parent = tcx.impl_parent(impl_def_id).unwrap_or(trait_id);
433 sg.record_impl_from_cstore(tcx, parent, impl_def_id)
434 }
435 }
436 errored?;
437
438 Ok(tcx.arena.alloc(sg))
439}
440
441#[cold]
445#[inline(never)]
446fn report_overlap_conflict<'tcx>(
447 tcx: TyCtxt<'tcx>,
448 overlap: OverlapError<'tcx>,
449 impl_def_id: LocalDefId,
450 used_to_be_allowed: Option<FutureCompatOverlapErrorKind>,
451) -> Result<(), ErrorGuaranteed> {
452 let impl_polarity = tcx.impl_polarity(impl_def_id.to_def_id());
453 let other_polarity = tcx.impl_polarity(overlap.with_impl);
454 match (impl_polarity, other_polarity) {
455 (ty::ImplPolarity::Negative, ty::ImplPolarity::Positive) => {
456 Err(report_negative_positive_conflict(
457 tcx,
458 &overlap,
459 impl_def_id,
460 impl_def_id.to_def_id(),
461 overlap.with_impl,
462 ))
463 }
464
465 (ty::ImplPolarity::Positive, ty::ImplPolarity::Negative) => {
466 Err(report_negative_positive_conflict(
467 tcx,
468 &overlap,
469 impl_def_id,
470 overlap.with_impl,
471 impl_def_id.to_def_id(),
472 ))
473 }
474
475 _ => report_conflicting_impls(tcx, overlap, impl_def_id, used_to_be_allowed),
476 }
477}
478
479fn report_negative_positive_conflict<'tcx>(
480 tcx: TyCtxt<'tcx>,
481 overlap: &OverlapError<'tcx>,
482 local_impl_def_id: LocalDefId,
483 negative_impl_def_id: DefId,
484 positive_impl_def_id: DefId,
485) -> ErrorGuaranteed {
486 let mut diag = tcx.dcx().create_err(NegativePositiveConflict {
487 impl_span: tcx.def_span(local_impl_def_id),
488 trait_desc: overlap.trait_ref,
489 self_ty: overlap.self_ty,
490 negative_impl_span: tcx.span_of_impl(negative_impl_def_id),
491 positive_impl_span: tcx.span_of_impl(positive_impl_def_id),
492 });
493
494 for cause in &overlap.intercrate_ambiguity_causes {
495 cause.add_intercrate_ambiguity_hint(&mut diag);
496 }
497
498 diag.emit()
499}
500
501fn report_conflicting_impls<'tcx>(
502 tcx: TyCtxt<'tcx>,
503 overlap: OverlapError<'tcx>,
504 impl_def_id: LocalDefId,
505 used_to_be_allowed: Option<FutureCompatOverlapErrorKind>,
506) -> Result<(), ErrorGuaranteed> {
507 let impl_span = tcx.def_span(impl_def_id);
508
509 fn decorate<'tcx, G: EmissionGuarantee>(
513 tcx: TyCtxt<'tcx>,
514 overlap: &OverlapError<'tcx>,
515 impl_span: Span,
516 err: &mut Diag<'_, G>,
517 ) {
518 match tcx.span_of_impl(overlap.with_impl) {
519 Ok(span) => {
520 err.span_label(span, "first implementation here");
521
522 err.span_label(
523 impl_span,
524 format!(
525 "conflicting implementation{}",
526 overlap.self_ty.map_or_else(String::new, |ty| format!(" for `{ty}`"))
527 ),
528 );
529 }
530 Err(cname) => {
531 let msg = match to_pretty_impl_header(tcx, overlap.with_impl) {
532 Some(s) => {
533 format!("conflicting implementation in crate `{cname}`:\n- {s}")
534 }
535 None => format!("conflicting implementation in crate `{cname}`"),
536 };
537 err.note(msg);
538 }
539 }
540
541 for cause in &overlap.intercrate_ambiguity_causes {
542 cause.add_intercrate_ambiguity_hint(err);
543 }
544
545 if overlap.involves_placeholder {
546 coherence::add_placeholder_note(err);
547 }
548
549 if !overlap.overflowing_predicates.is_empty() {
550 coherence::suggest_increasing_recursion_limit(
551 tcx,
552 err,
553 &overlap.overflowing_predicates,
554 );
555 }
556 }
557
558 let msg = || {
559 format!(
560 "conflicting implementations of trait `{}`{}{}",
561 overlap.trait_ref.print_trait_sugared(),
562 overlap.self_ty.map_or_else(String::new, |ty| format!(" for type `{ty}`")),
563 match used_to_be_allowed {
564 Some(FutureCompatOverlapErrorKind::OrderDepTraitObjects) => ": (E0119)",
565 _ => "",
566 }
567 )
568 };
569
570 if let Err(err) = (overlap.trait_ref, overlap.self_ty).error_reported() {
572 return Err(err);
573 }
574
575 match used_to_be_allowed {
576 None => {
577 let reported = if overlap.with_impl.is_local()
578 || tcx.ensure_ok().orphan_check_impl(impl_def_id).is_ok()
579 {
580 let mut err = tcx.dcx().struct_span_err(impl_span, msg());
581 err.code(E0119);
582 decorate(tcx, &overlap, impl_span, &mut err);
583 err.emit()
584 } else {
585 tcx.dcx().span_delayed_bug(impl_span, "impl should have failed the orphan check")
586 };
587 Err(reported)
588 }
589 Some(kind) => {
590 let lint = match kind {
591 FutureCompatOverlapErrorKind::OrderDepTraitObjects => ORDER_DEPENDENT_TRAIT_OBJECTS,
592 FutureCompatOverlapErrorKind::LeakCheck => COHERENCE_LEAK_CHECK,
593 };
594 tcx.node_span_lint(lint, tcx.local_def_id_to_hir_id(impl_def_id), impl_span, |err| {
595 err.primary_message(msg());
596 decorate(tcx, &overlap, impl_span, err);
597 });
598 Ok(())
599 }
600 }
601}