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::parse::feature_err;
15use rustc_span::{ErrorGuaranteed, sym};
16use tracing::debug;
17
18use crate::check::always_applicable;
19use crate::errors;
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.dcx().emit_err(errors::SpecializationTrait { span: impl_header_span }));
101        }
102    }
103
104    if !trait_def.impl_restriction.is_allowed_in(impl_def_id.to_def_id(), tcx) {
105        return Err(tcx.dcx().emit_err(errors::ImplOfRestrictedTrait {
106            impl_span: impl_header_span,
107            restriction_span: trait_def.impl_restriction.expect_span(),
108            restriction_path: trait_def.impl_restriction.restriction_path(tcx),
109        }));
110    }
111    Ok(())
112}
113
114/// We allow impls of marker traits to overlap, so they can't override impls
115/// as that could make it ambiguous which associated item to use.
116fn enforce_empty_impls_for_marker_traits(
117    tcx: TyCtxt<'_>,
118    impl_def_id: LocalDefId,
119    trait_def_id: DefId,
120    trait_def: &ty::TraitDef,
121) -> Result<(), ErrorGuaranteed> {
122    if !trait_def.is_marker {
123        return Ok(());
124    }
125
126    if tcx.associated_item_def_ids(trait_def_id).is_empty() {
127        return Ok(());
128    }
129
130    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!(
131        tcx.dcx(),
132        tcx.def_span(impl_def_id),
133        E0715,
134        "impls for marker traits cannot contain items"
135    )
136    .emit())
137}
138
139/// Adds query implementations to the [Providers] vtable, see [`rustc_middle::query`].
140pub(crate) fn provide(providers: &mut Providers) {
141    use self::builtin::coerce_unsized_info;
142    use self::inherent_impls::{
143        crate_incoherent_impls, crate_inherent_impls, crate_inherent_impls_validity_check,
144        inherent_impls,
145    };
146    use self::inherent_impls_overlap::crate_inherent_impls_overlap_check;
147    use self::orphan::orphan_check_impl;
148
149    *providers = Providers {
150        coherent_trait,
151        crate_inherent_impls,
152        crate_incoherent_impls,
153        inherent_impls,
154        crate_inherent_impls_validity_check,
155        crate_inherent_impls_overlap_check,
156        coerce_unsized_info,
157        orphan_check_impl,
158        ..*providers
159    };
160}
161
162fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed> {
163    let impls = tcx.local_trait_impls(def_id);
164    // If there are no impls for the trait, then "all impls" are trivially coherent and we won't check anything
165    // anyway. Thus we bail out even before the specialization graph, avoiding the dep_graph edge.
166    if impls.is_empty() {
167        return Ok(());
168    }
169    // Trigger building the specialization graph for the trait. This will detect and report any
170    // overlap errors.
171    let mut res = tcx.ensure_result().specialization_graph_of(def_id);
172
173    for &impl_def_id in impls {
174        let impl_header = tcx.impl_trait_header(impl_def_id);
175        let trait_ref = impl_header.trait_ref.instantiate_identity().skip_norm_wip();
176        let trait_def = tcx.trait_def(trait_ref.def_id);
177
178        res = res
179            .and(check_impl(tcx, impl_def_id, trait_ref, trait_def, impl_header.polarity))
180            .and(check_object_overlap(tcx, impl_def_id, trait_ref))
181            .and(unsafety::check_item(tcx, impl_def_id, impl_header, trait_def))
182            .and(tcx.ensure_result().orphan_check_impl(impl_def_id))
183            .and(builtin::check_trait(tcx, def_id, impl_def_id, impl_header));
184    }
185
186    res
187}
188
189/// Checks whether an impl overlaps with the automatic `impl Trait for dyn Trait`.
190fn check_object_overlap<'tcx>(
191    tcx: TyCtxt<'tcx>,
192    impl_def_id: LocalDefId,
193    trait_ref: ty::TraitRef<'tcx>,
194) -> Result<(), ErrorGuaranteed> {
195    let trait_def_id = trait_ref.def_id;
196
197    if let Err(guar) = trait_ref.error_reported() {
198        {
    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:198",
                        "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(198u32),
                        ::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);
199        return Err(guar);
200    }
201
202    // check for overlap with the automatic `impl Trait for dyn Trait`
203    if let ty::Dynamic(data, ..) = trait_ref.self_ty().kind() {
204        // This is something like `impl Trait1 for Trait2`. Illegal if
205        // Trait1 is a supertrait of Trait2 or Trait2 is not dyn compatible.
206
207        let component_def_ids = data.iter().flat_map(|predicate| {
208            match predicate.skip_binder() {
209                ty::ExistentialPredicate::Trait(tr) => Some(tr.def_id),
210                ty::ExistentialPredicate::AutoTrait(def_id) => Some(def_id),
211                // An associated type projection necessarily comes with
212                // an additional `Trait` requirement.
213                ty::ExistentialPredicate::Projection(..) => None,
214            }
215        });
216
217        for component_def_id in component_def_ids {
218            if !tcx.is_dyn_compatible(component_def_id) {
219                // This is a WF error tested by `coherence-impl-trait-for-trait-dyn-compatible.rs`.
220            } else {
221                let mut supertrait_def_ids = elaborate::supertrait_def_ids(tcx, component_def_id);
222                if supertrait_def_ids.any(|d| d == trait_def_id) {
223                    let span = tcx.def_span(impl_def_id);
224                    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!(
225                        tcx.dcx(),
226                        span,
227                        E0371,
228                        "the object type `{}` automatically implements the trait `{}`",
229                        trait_ref.self_ty(),
230                        tcx.def_path_str(trait_def_id)
231                    )
232                    .with_span_label(
233                        span,
234                        ::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!(
235                            "`{}` automatically implements trait `{}`",
236                            trait_ref.self_ty(),
237                            tcx.def_path_str(trait_def_id)
238                        ),
239                    )
240                    .emit());
241                }
242            }
243        }
244    }
245    Ok(())
246}