rustc_hir_analysis/coherence/
mod.rs1use 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 debug!(
35 "(checking implementation) adding impl for trait '{:?}', item '{}'",
36 trait_ref,
37 tcx.def_path_str(impl_def_id)
38 );
39
40 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, format!("impl of `Freeze` not allowed"))
70 .emit();
71 }
72
73 if trait_def.deny_explicit_impl {
75 let trait_name = tcx.item_name(trait_def_id);
76 let mut err = 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, format!("impl of `{trait_name}` not allowed"));
83
84 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 Ok(())
104}
105
106fn enforce_empty_impls_for_marker_traits(
109 tcx: TyCtxt<'_>,
110 impl_def_id: LocalDefId,
111 trait_def_id: DefId,
112 trait_def: &ty::TraitDef,
113) -> Result<(), ErrorGuaranteed> {
114 if !trait_def.is_marker {
115 return Ok(());
116 }
117
118 if tcx.associated_item_def_ids(trait_def_id).is_empty() {
119 return Ok(());
120 }
121
122 Err(struct_span_code_err!(
123 tcx.dcx(),
124 tcx.def_span(impl_def_id),
125 E0715,
126 "impls for marker traits cannot contain items"
127 )
128 .emit())
129}
130
131pub(crate) fn provide(providers: &mut Providers) {
133 use self::builtin::coerce_unsized_info;
134 use self::inherent_impls::{
135 crate_incoherent_impls, crate_inherent_impls, crate_inherent_impls_validity_check,
136 inherent_impls,
137 };
138 use self::inherent_impls_overlap::crate_inherent_impls_overlap_check;
139 use self::orphan::orphan_check_impl;
140
141 *providers = Providers {
142 coherent_trait,
143 crate_inherent_impls,
144 crate_incoherent_impls,
145 inherent_impls,
146 crate_inherent_impls_validity_check,
147 crate_inherent_impls_overlap_check,
148 coerce_unsized_info,
149 orphan_check_impl,
150 ..*providers
151 };
152}
153
154fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed> {
155 let impls = tcx.local_trait_impls(def_id);
156 if impls.is_empty() {
159 return Ok(());
160 }
161 let mut res = tcx.ensure_ok().specialization_graph_of(def_id);
164
165 for &impl_def_id in impls {
166 let impl_header = tcx.impl_trait_header(impl_def_id);
167 let trait_ref = impl_header.trait_ref.instantiate_identity();
168 let trait_def = tcx.trait_def(trait_ref.def_id);
169
170 res = res
171 .and(check_impl(tcx, impl_def_id, trait_ref, trait_def, impl_header.polarity))
172 .and(check_object_overlap(tcx, impl_def_id, trait_ref))
173 .and(unsafety::check_item(tcx, impl_def_id, impl_header, trait_def))
174 .and(tcx.ensure_ok().orphan_check_impl(impl_def_id))
175 .and(builtin::check_trait(tcx, def_id, impl_def_id, impl_header));
176 }
177
178 res
179}
180
181fn check_object_overlap<'tcx>(
183 tcx: TyCtxt<'tcx>,
184 impl_def_id: LocalDefId,
185 trait_ref: ty::TraitRef<'tcx>,
186) -> Result<(), ErrorGuaranteed> {
187 let trait_def_id = trait_ref.def_id;
188
189 if let Err(guar) = trait_ref.error_reported() {
190 debug!("coherence: skipping impl {:?} with error {:?}", impl_def_id, trait_ref);
191 return Err(guar);
192 }
193
194 if let ty::Dynamic(data, ..) = trait_ref.self_ty().kind() {
196 let component_def_ids = data.iter().flat_map(|predicate| {
200 match predicate.skip_binder() {
201 ty::ExistentialPredicate::Trait(tr) => Some(tr.def_id),
202 ty::ExistentialPredicate::AutoTrait(def_id) => Some(def_id),
203 ty::ExistentialPredicate::Projection(..) => None,
206 }
207 });
208
209 for component_def_id in component_def_ids {
210 if !tcx.is_dyn_compatible(component_def_id) {
211 } else {
213 let mut supertrait_def_ids = elaborate::supertrait_def_ids(tcx, component_def_id);
214 if supertrait_def_ids
215 .any(|d| d == trait_def_id && tcx.trait_def(d).implement_via_object)
216 {
217 let span = tcx.def_span(impl_def_id);
218 return Err(struct_span_code_err!(
219 tcx.dcx(),
220 span,
221 E0371,
222 "the object type `{}` automatically implements the trait `{}`",
223 trait_ref.self_ty(),
224 tcx.def_path_str(trait_def_id)
225 )
226 .with_span_label(
227 span,
228 format!(
229 "`{}` automatically implements trait `{}`",
230 trait_ref.self_ty(),
231 tcx.def_path_str(trait_def_id)
232 ),
233 )
234 .emit());
235 }
236 }
237 }
238 }
239 Ok(())
240}