rustc_hir_analysis/coherence/
mod.rs

1// Coherence phase
2//
3// The job of the coherence phase of typechecking is to ensure that
4// each trait has at most one implementation for each type. This is
5// done by the orphan and overlap modules. Then we build up various
6// mappings. That mapping code resides here.
7
8use rustc_errors::codes::*;
9use rustc_errors::struct_span_code_err;
10use rustc_hir::LangItem;
11use rustc_hir::def_id::{DefId, LocalDefId};
12use rustc_middle::query::Providers;
13use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
14use rustc_session::parse::feature_err;
15use rustc_span::{ErrorGuaranteed, sym};
16use rustc_type_ir::elaborate;
17use tracing::debug;
18
19use crate::errors;
20
21mod builtin;
22mod inherent_impls;
23mod inherent_impls_overlap;
24mod orphan;
25mod unsafety;
26
27fn check_impl(
28    tcx: TyCtxt<'_>,
29    impl_def_id: LocalDefId,
30    trait_ref: ty::TraitRef<'_>,
31    trait_def: &ty::TraitDef,
32) -> Result<(), ErrorGuaranteed> {
33    debug!(
34        "(checking implementation) adding impl for trait '{:?}', item '{}'",
35        trait_ref,
36        tcx.def_path_str(impl_def_id)
37    );
38
39    // Skip impls where one of the self type is an error type.
40    // This occurs with e.g., resolve failures (#30589).
41    if trait_ref.references_error() {
42        return Ok(());
43    }
44
45    enforce_trait_manually_implementable(tcx, impl_def_id, trait_ref.def_id, trait_def)
46        .and(enforce_empty_impls_for_marker_traits(tcx, impl_def_id, trait_ref.def_id, trait_def))
47}
48
49fn enforce_trait_manually_implementable(
50    tcx: TyCtxt<'_>,
51    impl_def_id: LocalDefId,
52    trait_def_id: DefId,
53    trait_def: &ty::TraitDef,
54) -> Result<(), ErrorGuaranteed> {
55    let impl_header_span = tcx.def_span(impl_def_id);
56
57    if tcx.is_lang_item(trait_def_id, LangItem::Freeze) && !tcx.features().freeze_impls() {
58        feature_err(
59            &tcx.sess,
60            sym::freeze_impls,
61            impl_header_span,
62            "explicit impls for the `Freeze` trait are not permitted",
63        )
64        .with_span_label(impl_header_span, format!("impl of `Freeze` not allowed"))
65        .emit();
66    }
67
68    // Disallow *all* explicit impls of traits marked `#[rustc_deny_explicit_impl]`
69    if trait_def.deny_explicit_impl {
70        let trait_name = tcx.item_name(trait_def_id);
71        let mut err = struct_span_code_err!(
72            tcx.dcx(),
73            impl_header_span,
74            E0322,
75            "explicit impls for the `{trait_name}` trait are not permitted"
76        );
77        err.span_label(impl_header_span, format!("impl of `{trait_name}` not allowed"));
78
79        // Maintain explicit error code for `Unsize`, since it has a useful
80        // explanation about using `CoerceUnsized` instead.
81        if tcx.is_lang_item(trait_def_id, LangItem::Unsize) {
82            err.code(E0328);
83        }
84
85        return Err(err.emit());
86    }
87
88    if let ty::trait_def::TraitSpecializationKind::AlwaysApplicable = trait_def.specialization_kind
89    {
90        if !tcx.features().specialization()
91            && !tcx.features().min_specialization()
92            && !impl_header_span.allows_unstable(sym::specialization)
93            && !impl_header_span.allows_unstable(sym::min_specialization)
94        {
95            return Err(tcx.dcx().emit_err(errors::SpecializationTrait { span: impl_header_span }));
96        }
97    }
98    Ok(())
99}
100
101/// We allow impls of marker traits to overlap, so they can't override impls
102/// as that could make it ambiguous which associated item to use.
103fn enforce_empty_impls_for_marker_traits(
104    tcx: TyCtxt<'_>,
105    impl_def_id: LocalDefId,
106    trait_def_id: DefId,
107    trait_def: &ty::TraitDef,
108) -> Result<(), ErrorGuaranteed> {
109    if !trait_def.is_marker {
110        return Ok(());
111    }
112
113    if tcx.associated_item_def_ids(trait_def_id).is_empty() {
114        return Ok(());
115    }
116
117    Err(struct_span_code_err!(
118        tcx.dcx(),
119        tcx.def_span(impl_def_id),
120        E0715,
121        "impls for marker traits cannot contain items"
122    )
123    .emit())
124}
125
126pub(crate) fn provide(providers: &mut Providers) {
127    use self::builtin::coerce_unsized_info;
128    use self::inherent_impls::{
129        crate_incoherent_impls, crate_inherent_impls, crate_inherent_impls_validity_check,
130        inherent_impls,
131    };
132    use self::inherent_impls_overlap::crate_inherent_impls_overlap_check;
133    use self::orphan::orphan_check_impl;
134
135    *providers = Providers {
136        coherent_trait,
137        crate_inherent_impls,
138        crate_incoherent_impls,
139        inherent_impls,
140        crate_inherent_impls_validity_check,
141        crate_inherent_impls_overlap_check,
142        coerce_unsized_info,
143        orphan_check_impl,
144        ..*providers
145    };
146}
147
148fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed> {
149    // If there are no impls for the trait, then "all impls" are trivially coherent and we won't check anything
150    // anyway. Thus we bail out even before the specialization graph, avoiding the dep_graph edge.
151    let Some(impls) = tcx.all_local_trait_impls(()).get(&def_id) else { return Ok(()) };
152    // Trigger building the specialization graph for the trait. This will detect and report any
153    // overlap errors.
154    let mut res = tcx.ensure_ok().specialization_graph_of(def_id);
155
156    for &impl_def_id in impls {
157        let trait_header = tcx.impl_trait_header(impl_def_id).unwrap();
158        let trait_ref = trait_header.trait_ref.instantiate_identity();
159        let trait_def = tcx.trait_def(trait_ref.def_id);
160
161        res = res
162            .and(check_impl(tcx, impl_def_id, trait_ref, trait_def))
163            .and(check_object_overlap(tcx, impl_def_id, trait_ref))
164            .and(unsafety::check_item(tcx, impl_def_id, trait_header, trait_def))
165            .and(tcx.ensure_ok().orphan_check_impl(impl_def_id))
166            .and(builtin::check_trait(tcx, def_id, impl_def_id, trait_header));
167    }
168
169    res
170}
171
172/// Checks whether an impl overlaps with the automatic `impl Trait for dyn Trait`.
173fn check_object_overlap<'tcx>(
174    tcx: TyCtxt<'tcx>,
175    impl_def_id: LocalDefId,
176    trait_ref: ty::TraitRef<'tcx>,
177) -> Result<(), ErrorGuaranteed> {
178    let trait_def_id = trait_ref.def_id;
179
180    if trait_ref.references_error() {
181        debug!("coherence: skipping impl {:?} with error {:?}", impl_def_id, trait_ref);
182        return Ok(());
183    }
184
185    // check for overlap with the automatic `impl Trait for dyn Trait`
186    if let ty::Dynamic(data, ..) = trait_ref.self_ty().kind() {
187        // This is something like `impl Trait1 for Trait2`. Illegal if
188        // Trait1 is a supertrait of Trait2 or Trait2 is not dyn compatible.
189
190        let component_def_ids = data.iter().flat_map(|predicate| {
191            match predicate.skip_binder() {
192                ty::ExistentialPredicate::Trait(tr) => Some(tr.def_id),
193                ty::ExistentialPredicate::AutoTrait(def_id) => Some(def_id),
194                // An associated type projection necessarily comes with
195                // an additional `Trait` requirement.
196                ty::ExistentialPredicate::Projection(..) => None,
197            }
198        });
199
200        for component_def_id in component_def_ids {
201            if !tcx.is_dyn_compatible(component_def_id) {
202                // Without the 'dyn_compatible_for_dispatch' feature this is an error
203                // which will be reported by wfcheck. Ignore it here.
204                // This is tested by `coherence-impl-trait-for-trait-dyn-compatible.rs`.
205                // With the feature enabled, the trait is not implemented automatically,
206                // so this is valid.
207            } else {
208                let mut supertrait_def_ids = elaborate::supertrait_def_ids(tcx, component_def_id);
209                if supertrait_def_ids
210                    .any(|d| d == trait_def_id && tcx.trait_def(d).implement_via_object)
211                {
212                    let span = tcx.def_span(impl_def_id);
213                    return Err(struct_span_code_err!(
214                        tcx.dcx(),
215                        span,
216                        E0371,
217                        "the object type `{}` automatically implements the trait `{}`",
218                        trait_ref.self_ty(),
219                        tcx.def_path_str(trait_def_id)
220                    )
221                    .with_span_label(
222                        span,
223                        format!(
224                            "`{}` automatically implements trait `{}`",
225                            trait_ref.self_ty(),
226                            tcx.def_path_str(trait_def_id)
227                        ),
228                    )
229                    .emit());
230                }
231            }
232        }
233    }
234    Ok(())
235}