Skip to main content

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, elaborate};
14use rustc_session::errors::feature_err;
15use rustc_span::{ErrorGuaranteed, sym};
16use tracing::debug;
17
18use crate::check::always_applicable;
19use crate::diagnostics;
20
21mod builtin;
22mod inherent_impls;
23mod inherent_impls_overlap;
24mod orphan;
25mod unsafety;
26
27fn check_impl<'tcx>(
28    tcx: TyCtxt<'tcx>,
29    impl_def_id: LocalDefId,
30    trait_ref: ty::TraitRef<'tcx>,
31    trait_def: &'tcx ty::TraitDef,
32    polarity: ty::ImplPolarity,
33) -> Result<(), ErrorGuaranteed> {
34    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_analysis/src/coherence/mod.rs:34",
                        "rustc_hir_analysis::coherence", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/coherence/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(34u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::coherence"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("(checking implementation) adding impl for trait \'{0:?}\', item \'{1}\'",
                                                    trait_ref, tcx.def_path_str(impl_def_id)) as &dyn Value))])
            });
    } else { ; }
};debug!(
35        "(checking implementation) adding impl for trait '{:?}', item '{}'",
36        trait_ref,
37        tcx.def_path_str(impl_def_id)
38    );
39
40    // Skip impls where one of the self type is an error type.
41    // This occurs with e.g., resolve failures (#30589).
42    trait_ref.error_reported()?;
43
44    enforce_trait_manually_implementable(tcx, impl_def_id, trait_ref.def_id, trait_def)
45        .and(enforce_empty_impls_for_marker_traits(tcx, impl_def_id, trait_ref.def_id, trait_def))
46        .and(always_applicable::check_negative_auto_trait_impl(
47            tcx,
48            impl_def_id,
49            trait_ref,
50            polarity,
51        ))
52}
53
54fn enforce_trait_manually_implementable(
55    tcx: TyCtxt<'_>,
56    impl_def_id: LocalDefId,
57    trait_def_id: DefId,
58    trait_def: &ty::TraitDef,
59) -> Result<(), ErrorGuaranteed> {
60    let impl_header_span = tcx.def_span(impl_def_id);
61
62    if tcx.is_lang_item(trait_def_id, LangItem::Freeze) && !tcx.features().freeze_impls() {
63        feature_err(
64            &tcx.sess,
65            sym::freeze_impls,
66            impl_header_span,
67            "explicit impls for the `Freeze` trait are not permitted",
68        )
69        .with_span_label(impl_header_span, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("impl of `Freeze` not allowed"))
    })format!("impl of `Freeze` not allowed"))
70        .emit();
71    }
72
73    // Disallow *all* explicit impls of traits marked `#[rustc_deny_explicit_impl]`
74    if trait_def.deny_explicit_impl {
75        let trait_name = tcx.item_name(trait_def_id);
76        let mut err = {
    tcx.dcx().struct_span_err(impl_header_span,
            ::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("explicit impls for the `{0}` trait are not permitted",
                            trait_name))
                })).with_code(E0322)
}struct_span_code_err!(
77            tcx.dcx(),
78            impl_header_span,
79            E0322,
80            "explicit impls for the `{trait_name}` trait are not permitted"
81        );
82        err.span_label(impl_header_span, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("impl of `{0}` not allowed",
                trait_name))
    })format!("impl of `{trait_name}` not allowed"));
83
84        // Maintain explicit error code for `Unsize`, since it has a useful
85        // explanation about using `CoerceUnsized` instead.
86        if tcx.is_lang_item(trait_def_id, LangItem::Unsize) {
87            err.code(E0328);
88        }
89
90        return Err(err.emit());
91    }
92
93    if let ty::trait_def::TraitSpecializationKind::AlwaysApplicable = trait_def.specialization_kind
94    {
95        if !tcx.features().specialization()
96            && !tcx.features().min_specialization()
97            && !impl_header_span.allows_unstable(sym::specialization)
98            && !impl_header_span.allows_unstable(sym::min_specialization)
99        {
100            return Err(tcx
101                .dcx()
102                .emit_err(diagnostics::SpecializationTrait { span: impl_header_span }));
103        }
104    }
105
106    if !trait_def.impl_restriction.is_allowed_in(impl_def_id.to_def_id(), tcx) {
107        return Err(tcx.dcx().emit_err(diagnostics::ImplOfRestrictedTrait {
108            impl_span: impl_header_span,
109            restriction_span: trait_def.impl_restriction.expect_span(),
110            restriction_path: trait_def.impl_restriction.restriction_path(tcx),
111        }));
112    }
113    Ok(())
114}
115
116/// We allow impls of marker traits to overlap, so they can't override impls
117/// as that could make it ambiguous which associated item to use.
118fn enforce_empty_impls_for_marker_traits(
119    tcx: TyCtxt<'_>,
120    impl_def_id: LocalDefId,
121    trait_def_id: DefId,
122    trait_def: &ty::TraitDef,
123) -> Result<(), ErrorGuaranteed> {
124    if !trait_def.is_marker {
125        return Ok(());
126    }
127
128    if tcx.associated_item_def_ids(trait_def_id).is_empty() {
129        return Ok(());
130    }
131
132    Err({
    tcx.dcx().struct_span_err(tcx.def_span(impl_def_id),
            ::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("impls for marker traits cannot contain items"))
                })).with_code(E0715)
}struct_span_code_err!(
133        tcx.dcx(),
134        tcx.def_span(impl_def_id),
135        E0715,
136        "impls for marker traits cannot contain items"
137    )
138    .emit())
139}
140
141/// Adds query implementations to the [Providers] vtable, see [`rustc_middle::query`].
142pub(crate) fn provide(providers: &mut Providers) {
143    use self::builtin::coerce_unsized_info;
144    use self::inherent_impls::{
145        crate_incoherent_impls, crate_inherent_impls, crate_inherent_impls_validity_check,
146        inherent_impls,
147    };
148    use self::inherent_impls_overlap::crate_inherent_impls_overlap_check;
149    use self::orphan::orphan_check_impl;
150
151    *providers = Providers {
152        coherent_trait,
153        crate_inherent_impls,
154        crate_incoherent_impls,
155        inherent_impls,
156        crate_inherent_impls_validity_check,
157        crate_inherent_impls_overlap_check,
158        coerce_unsized_info,
159        orphan_check_impl,
160        ..*providers
161    };
162}
163
164fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed> {
165    let impls = tcx.local_trait_impls(def_id);
166    // If there are no impls for the trait, then "all impls" are trivially coherent and we won't check anything
167    // anyway. Thus we bail out even before the specialization graph, avoiding the dep_graph edge.
168    if impls.is_empty() {
169        return Ok(());
170    }
171    // Trigger building the specialization graph for the trait. This will detect and report any
172    // overlap errors.
173    let mut res = tcx.ensure_result().specialization_graph_of(def_id);
174
175    for &impl_def_id in impls {
176        let impl_header = tcx.impl_trait_header(impl_def_id);
177        let trait_ref = impl_header.trait_ref.instantiate_identity().skip_norm_wip();
178        let trait_def = tcx.trait_def(trait_ref.def_id);
179
180        res = res
181            .and(check_impl(tcx, impl_def_id, trait_ref, trait_def, impl_header.polarity))
182            .and(check_object_overlap(tcx, impl_def_id, trait_ref))
183            .and(unsafety::check_item(tcx, impl_def_id, impl_header, trait_def))
184            .and(tcx.ensure_result().orphan_check_impl(impl_def_id))
185            .and(builtin::check_trait(tcx, def_id, impl_def_id, impl_header));
186    }
187
188    res
189}
190
191/// Checks whether an impl overlaps with the automatic `impl Trait for dyn Trait`.
192fn check_object_overlap<'tcx>(
193    tcx: TyCtxt<'tcx>,
194    impl_def_id: LocalDefId,
195    trait_ref: ty::TraitRef<'tcx>,
196) -> Result<(), ErrorGuaranteed> {
197    let trait_def_id = trait_ref.def_id;
198
199    if let Err(guar) = trait_ref.error_reported() {
200        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_analysis/src/coherence/mod.rs:200",
                        "rustc_hir_analysis::coherence", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/coherence/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(200u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::coherence"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("coherence: skipping impl {0:?} with error {1:?}",
                                                    impl_def_id, trait_ref) as &dyn Value))])
            });
    } else { ; }
};debug!("coherence: skipping impl {:?} with error {:?}", impl_def_id, trait_ref);
201        return Err(guar);
202    }
203
204    // check for overlap with the automatic `impl Trait for dyn Trait`
205    if let ty::Dynamic(data, ..) = trait_ref.self_ty().kind() {
206        // This is something like `impl Trait1 for Trait2`. Illegal if
207        // Trait1 is a supertrait of Trait2 or Trait2 is not dyn compatible.
208
209        let component_def_ids = data.iter().flat_map(|predicate| {
210            match predicate.skip_binder() {
211                ty::ExistentialPredicate::Trait(tr) => Some(tr.def_id),
212                ty::ExistentialPredicate::AutoTrait(def_id) => Some(def_id),
213                // An associated type projection necessarily comes with
214                // an additional `Trait` requirement.
215                ty::ExistentialPredicate::Projection(..) => None,
216            }
217        });
218
219        for component_def_id in component_def_ids {
220            if !tcx.is_dyn_compatible(component_def_id) {
221                // This is a WF error tested by `coherence-impl-trait-for-trait-dyn-compatible.rs`.
222            } else {
223                let mut supertrait_def_ids = elaborate::supertrait_def_ids(tcx, component_def_id);
224                if supertrait_def_ids.any(|d| d == trait_def_id) {
225                    let span = tcx.def_span(impl_def_id);
226                    return Err({
    tcx.dcx().struct_span_err(span,
            ::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("the object type `{0}` automatically implements the trait `{1}`",
                            trait_ref.self_ty(), tcx.def_path_str(trait_def_id)))
                })).with_code(E0371)
}struct_span_code_err!(
227                        tcx.dcx(),
228                        span,
229                        E0371,
230                        "the object type `{}` automatically implements the trait `{}`",
231                        trait_ref.self_ty(),
232                        tcx.def_path_str(trait_def_id)
233                    )
234                    .with_span_label(
235                        span,
236                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` automatically implements trait `{1}`",
                trait_ref.self_ty(), tcx.def_path_str(trait_def_id)))
    })format!(
237                            "`{}` automatically implements trait `{}`",
238                            trait_ref.self_ty(),
239                            tcx.def_path_str(trait_def_id)
240                        ),
241                    )
242                    .emit());
243                }
244            }
245        }
246    }
247    Ok(())
248}