rustc_trait_selection/traits/specialize/
mod.rs1pub 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::traits::query::NoSolution;
22use rustc_middle::ty::print::PrintTraitRefExt as _;
23use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, TypingMode};
24use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK;
25use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, sym};
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).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.evaluate_obligations_error_on_ambiguity().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.tcx.impl_trait_ref(target_impl).instantiate(infcx.tcx, target_args),
180 );
181
182 ocx.eq(cause, param_env, source_trait_ref, target_trait_ref)?;
184
185 let predicates = ocx.normalize(
189 cause,
190 param_env,
191 infcx.tcx.predicates_of(target_impl).instantiate(infcx.tcx, target_args),
192 );
193 let obligations = predicates_for_generics(|_, _| cause.clone(), param_env, predicates);
194 ocx.register_obligations(obligations);
195
196 let errors = ocx.evaluate_obligations_error_on_ambiguity();
197 if !errors.is_empty() {
198 debug!(
200 "fulfill_implication: for impls on {:?} and {:?}, \
201 could not fulfill: {:?} given {:?}",
202 source_trait_ref,
203 target_trait_ref,
204 errors,
205 param_env.caller_bounds()
206 );
207 return Err(NoSolution);
208 }
209
210 debug!(
211 "fulfill_implication: an impl for {:?} specializes {:?}",
212 source_trait_ref, target_trait_ref
213 );
214
215 Ok(infcx.resolve_vars_if_possible(target_args))
218}
219
220pub(super) fn specialization_enabled_in(tcx: TyCtxt<'_>, _: LocalCrate) -> bool {
221 tcx.features().specialization() || tcx.features().min_specialization()
222}
223
224#[instrument(skip(tcx), level = "debug")]
236pub(super) fn specializes(
237 tcx: TyCtxt<'_>,
238 (specializing_impl_def_id, parent_impl_def_id): (DefId, DefId),
239) -> bool {
240 if !tcx.specialization_enabled_in(specializing_impl_def_id.krate) {
247 let span = tcx.def_span(specializing_impl_def_id);
248 if !span.allows_unstable(sym::specialization)
249 && !span.allows_unstable(sym::min_specialization)
250 {
251 return false;
252 }
253 }
254
255 let specializing_impl_trait_header = tcx.impl_trait_header(specializing_impl_def_id);
256
257 if specializing_impl_trait_header.polarity != tcx.impl_polarity(parent_impl_def_id) {
271 return false;
272 }
273
274 let param_env = tcx.param_env(specializing_impl_def_id);
277
278 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
280
281 let specializing_impl_trait_ref =
282 specializing_impl_trait_header.trait_ref.instantiate_identity();
283 let cause = &ObligationCause::dummy();
284 debug!(
285 "fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)",
286 param_env, specializing_impl_trait_ref, parent_impl_def_id
287 );
288
289 let ocx = ObligationCtxt::new(&infcx);
292 let specializing_impl_trait_ref = ocx.normalize(cause, param_env, specializing_impl_trait_ref);
293
294 if !ocx.evaluate_obligations_error_on_ambiguity().is_empty() {
295 infcx.dcx().span_delayed_bug(
296 infcx.tcx.def_span(specializing_impl_def_id),
297 format!("failed to fully normalize {specializing_impl_trait_ref}"),
298 );
299 return false;
300 }
301
302 let parent_args = infcx.fresh_args_for_item(DUMMY_SP, parent_impl_def_id);
303 let parent_impl_trait_ref = ocx.normalize(
304 cause,
305 param_env,
306 infcx.tcx.impl_trait_ref(parent_impl_def_id).instantiate(infcx.tcx, parent_args),
307 );
308
309 let Ok(()) = ocx.eq(cause, param_env, specializing_impl_trait_ref, parent_impl_trait_ref)
311 else {
312 return false;
313 };
314
315 let predicates = ocx.normalize(
319 cause,
320 param_env,
321 infcx.tcx.predicates_of(parent_impl_def_id).instantiate(infcx.tcx, parent_args),
322 );
323 let obligations = predicates_for_generics(|_, _| cause.clone(), param_env, predicates);
324 ocx.register_obligations(obligations);
325
326 let errors = ocx.evaluate_obligations_error_on_ambiguity();
327 if !errors.is_empty() {
328 debug!(
330 "fulfill_implication: for impls on {:?} and {:?}, \
331 could not fulfill: {:?} given {:?}",
332 specializing_impl_trait_ref,
333 parent_impl_trait_ref,
334 errors,
335 param_env.caller_bounds()
336 );
337 return false;
338 }
339
340 if tcx.is_conditionally_const(parent_impl_def_id) {
344 if !tcx.is_conditionally_const(specializing_impl_def_id) {
345 return false;
346 }
347
348 let const_conditions = ocx.normalize(
349 cause,
350 param_env,
351 infcx.tcx.const_conditions(parent_impl_def_id).instantiate(infcx.tcx, parent_args),
352 );
353 ocx.register_obligations(const_conditions.into_iter().map(|(trait_ref, _)| {
354 Obligation::new(
355 infcx.tcx,
356 cause.clone(),
357 param_env,
358 trait_ref.to_host_effect_clause(infcx.tcx, ty::BoundConstness::Maybe),
359 )
360 }));
361
362 let errors = ocx.evaluate_obligations_error_on_ambiguity();
363 if !errors.is_empty() {
364 debug!(
366 "fulfill_implication: for impls on {:?} and {:?}, \
367 could not fulfill: {:?} given {:?}",
368 specializing_impl_trait_ref,
369 parent_impl_trait_ref,
370 errors,
371 param_env.caller_bounds()
372 );
373 return false;
374 }
375 }
376
377 debug!(
378 "fulfill_implication: an impl for {:?} specializes {:?}",
379 specializing_impl_trait_ref, parent_impl_trait_ref
380 );
381
382 true
383}
384
385pub(super) fn specialization_graph_provider(
387 tcx: TyCtxt<'_>,
388 trait_id: DefId,
389) -> Result<&'_ specialization_graph::Graph, ErrorGuaranteed> {
390 let mut sg = specialization_graph::Graph::new();
391 let overlap_mode = specialization_graph::OverlapMode::get(tcx, trait_id);
392
393 let mut trait_impls: Vec<_> = tcx.all_impls(trait_id).collect();
394
395 trait_impls
400 .sort_unstable_by_key(|def_id| (-(def_id.krate.as_u32() as i64), def_id.index.index()));
401
402 let mut errored = Ok(());
403
404 for impl_def_id in trait_impls {
405 if let Some(impl_def_id) = impl_def_id.as_local() {
406 let insert_result = sg.insert(tcx, impl_def_id.to_def_id(), overlap_mode);
408 let (overlap, used_to_be_allowed) = match insert_result {
410 Err(overlap) => (Some(overlap), None),
411 Ok(Some(overlap)) => (Some(overlap.error), Some(overlap.kind)),
412 Ok(None) => (None, None),
413 };
414
415 if let Some(overlap) = overlap {
416 errored = errored.and(report_overlap_conflict(
417 tcx,
418 overlap,
419 impl_def_id,
420 used_to_be_allowed,
421 ));
422 }
423 } else {
424 let parent = tcx.impl_parent(impl_def_id).unwrap_or(trait_id);
425 sg.record_impl_from_cstore(tcx, parent, impl_def_id)
426 }
427 }
428 errored?;
429
430 Ok(tcx.arena.alloc(sg))
431}
432
433#[cold]
437#[inline(never)]
438fn report_overlap_conflict<'tcx>(
439 tcx: TyCtxt<'tcx>,
440 overlap: OverlapError<'tcx>,
441 impl_def_id: LocalDefId,
442 used_to_be_allowed: Option<FutureCompatOverlapErrorKind>,
443) -> Result<(), ErrorGuaranteed> {
444 let impl_polarity = tcx.impl_polarity(impl_def_id.to_def_id());
445 let other_polarity = tcx.impl_polarity(overlap.with_impl);
446 match (impl_polarity, other_polarity) {
447 (ty::ImplPolarity::Negative, ty::ImplPolarity::Positive) => {
448 Err(report_negative_positive_conflict(
449 tcx,
450 &overlap,
451 impl_def_id,
452 impl_def_id.to_def_id(),
453 overlap.with_impl,
454 ))
455 }
456
457 (ty::ImplPolarity::Positive, ty::ImplPolarity::Negative) => {
458 Err(report_negative_positive_conflict(
459 tcx,
460 &overlap,
461 impl_def_id,
462 overlap.with_impl,
463 impl_def_id.to_def_id(),
464 ))
465 }
466
467 _ => report_conflicting_impls(tcx, overlap, impl_def_id, used_to_be_allowed),
468 }
469}
470
471fn report_negative_positive_conflict<'tcx>(
472 tcx: TyCtxt<'tcx>,
473 overlap: &OverlapError<'tcx>,
474 local_impl_def_id: LocalDefId,
475 negative_impl_def_id: DefId,
476 positive_impl_def_id: DefId,
477) -> ErrorGuaranteed {
478 let mut diag = tcx.dcx().create_err(NegativePositiveConflict {
479 impl_span: tcx.def_span(local_impl_def_id),
480 trait_desc: overlap.trait_ref,
481 self_ty: overlap.self_ty,
482 negative_impl_span: tcx.span_of_impl(negative_impl_def_id),
483 positive_impl_span: tcx.span_of_impl(positive_impl_def_id),
484 });
485
486 for cause in &overlap.intercrate_ambiguity_causes {
487 cause.add_intercrate_ambiguity_hint(&mut diag);
488 }
489
490 diag.emit()
491}
492
493fn report_conflicting_impls<'tcx>(
494 tcx: TyCtxt<'tcx>,
495 overlap: OverlapError<'tcx>,
496 impl_def_id: LocalDefId,
497 used_to_be_allowed: Option<FutureCompatOverlapErrorKind>,
498) -> Result<(), ErrorGuaranteed> {
499 let impl_span = tcx.def_span(impl_def_id);
500
501 fn decorate<'tcx, G: EmissionGuarantee>(
505 tcx: TyCtxt<'tcx>,
506 overlap: &OverlapError<'tcx>,
507 impl_span: Span,
508 err: &mut Diag<'_, G>,
509 ) {
510 match tcx.span_of_impl(overlap.with_impl) {
511 Ok(span) => {
512 err.span_label(span, "first implementation here");
513
514 err.span_label(
515 impl_span,
516 format!(
517 "conflicting implementation{}",
518 overlap.self_ty.map_or_else(String::new, |ty| format!(" for `{ty}`"))
519 ),
520 );
521 }
522 Err(cname) => {
523 let msg = match to_pretty_impl_header(tcx, overlap.with_impl) {
524 Some(s) => {
525 format!("conflicting implementation in crate `{cname}`:\n- {s}")
526 }
527 None => format!("conflicting implementation in crate `{cname}`"),
528 };
529 err.note(msg);
530 }
531 }
532
533 for cause in &overlap.intercrate_ambiguity_causes {
534 cause.add_intercrate_ambiguity_hint(err);
535 }
536
537 if overlap.involves_placeholder {
538 coherence::add_placeholder_note(err);
539 }
540
541 if !overlap.overflowing_predicates.is_empty() {
542 coherence::suggest_increasing_recursion_limit(
543 tcx,
544 err,
545 &overlap.overflowing_predicates,
546 );
547 }
548 }
549
550 let msg = || {
551 format!(
552 "conflicting implementations of trait `{}`{}",
553 overlap.trait_ref.print_trait_sugared(),
554 overlap.self_ty.map_or_else(String::new, |ty| format!(" for type `{ty}`")),
555 )
556 };
557
558 if let Err(err) = (overlap.trait_ref, overlap.self_ty).error_reported() {
560 return Err(err);
561 }
562
563 match used_to_be_allowed {
564 None => {
565 let reported = if overlap.with_impl.is_local()
566 || tcx.ensure_ok().orphan_check_impl(impl_def_id).is_ok()
567 {
568 let mut err = tcx.dcx().struct_span_err(impl_span, msg());
569 err.code(E0119);
570 decorate(tcx, &overlap, impl_span, &mut err);
571 err.emit()
572 } else {
573 tcx.dcx().span_delayed_bug(impl_span, "impl should have failed the orphan check")
574 };
575 Err(reported)
576 }
577 Some(kind) => {
578 let lint = match kind {
579 FutureCompatOverlapErrorKind::LeakCheck => COHERENCE_LEAK_CHECK,
580 };
581 tcx.node_span_lint(lint, tcx.local_def_id_to_hir_id(impl_def_id), impl_span, |err| {
582 err.primary_message(msg());
583 decorate(tcx, &overlap, impl_span, err);
584 });
585 Ok(())
586 }
587 }
588}