rustc_hir_analysis/
impl_wf_check.rs1use std::assert_matches::debug_assert_matches;
12
13use min_specialization::check_min_specialization;
14use rustc_data_structures::fx::FxHashSet;
15use rustc_errors::Applicability;
16use rustc_errors::codes::*;
17use rustc_hir::def::DefKind;
18use rustc_hir::def_id::LocalDefId;
19use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
20use rustc_span::{ErrorGuaranteed, kw};
21
22use crate::constrained_generic_params as cgp;
23use crate::errors::UnconstrainedGenericParameter;
24
25mod min_specialization;
26
27pub(crate) fn check_impl_wf(
58 tcx: TyCtxt<'_>,
59 impl_def_id: LocalDefId,
60 of_trait: bool,
61) -> Result<(), ErrorGuaranteed> {
62 debug_assert_matches!(tcx.def_kind(impl_def_id), DefKind::Impl { .. });
63
64 let mut res = tcx.ensure_ok().enforce_impl_non_lifetime_params_are_constrained(impl_def_id);
68 res = res.and(enforce_impl_lifetime_params_are_constrained(tcx, impl_def_id, of_trait));
69
70 if of_trait && tcx.features().min_specialization() {
71 res = res.and(check_min_specialization(tcx, impl_def_id));
72 }
73 res
74}
75
76pub(crate) fn enforce_impl_lifetime_params_are_constrained(
77 tcx: TyCtxt<'_>,
78 impl_def_id: LocalDefId,
79 of_trait: bool,
80) -> Result<(), ErrorGuaranteed> {
81 let impl_self_ty = tcx.type_of(impl_def_id).instantiate_identity();
82
83 impl_self_ty.error_reported()?;
86
87 let impl_generics = tcx.generics_of(impl_def_id);
88 let impl_predicates = tcx.predicates_of(impl_def_id);
89 let impl_trait_ref = of_trait.then(|| tcx.impl_trait_ref(impl_def_id).instantiate_identity());
90
91 impl_trait_ref.error_reported()?;
92
93 let mut input_parameters = cgp::parameters_for_impl(tcx, impl_self_ty, impl_trait_ref);
94 cgp::identify_constrained_generic_params(
95 tcx,
96 impl_predicates,
97 impl_trait_ref,
98 &mut input_parameters,
99 );
100
101 let lifetimes_in_associated_types: FxHashSet<_> = tcx
103 .associated_item_def_ids(impl_def_id)
104 .iter()
105 .flat_map(|def_id| {
106 let item = tcx.associated_item(def_id);
107 match item.kind {
108 ty::AssocKind::Type { .. } => {
109 if item.defaultness(tcx).has_value() {
110 cgp::parameters_for(tcx, tcx.type_of(def_id).instantiate_identity(), true)
111 } else {
112 vec![]
113 }
114 }
115 ty::AssocKind::Fn { .. } | ty::AssocKind::Const { .. } => vec![],
116 }
117 })
118 .collect();
119
120 let mut res = Ok(());
121 for param in &impl_generics.own_params {
122 match param.kind {
123 ty::GenericParamDefKind::Lifetime => {
124 let param_lt = cgp::Parameter::from(param.to_early_bound_region_data());
143 if lifetimes_in_associated_types.contains(¶m_lt)
144 && !input_parameters.contains(¶m_lt)
145 {
146 let mut diag = tcx.dcx().create_err(UnconstrainedGenericParameter {
147 span: tcx.def_span(param.def_id),
148 param_name: tcx.item_ident(param.def_id),
149 param_def_kind: tcx.def_descr(param.def_id),
150 const_param_note: false,
151 const_param_note2: false,
152 });
153 diag.code(E0207);
154 for p in &impl_generics.own_params {
155 if p.name == kw::UnderscoreLifetime {
156 let span = tcx.def_span(p.def_id);
157 let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) else {
158 continue;
159 };
160
161 let (span, sugg) = if &snippet == "'_" {
162 (span, param.name.to_string())
163 } else {
164 (span.shrink_to_hi(), format!("{} ", param.name))
165 };
166 diag.span_suggestion_verbose(
167 span,
168 "consider using the named lifetime here instead of an implicit \
169 lifetime",
170 sugg,
171 Applicability::MaybeIncorrect,
172 );
173 }
174 }
175 res = Err(diag.emit());
176 }
177 }
178 ty::GenericParamDefKind::Type { .. } | ty::GenericParamDefKind::Const { .. } => {
179 }
181 }
182 }
183 res
184}
185
186pub(crate) fn enforce_impl_non_lifetime_params_are_constrained(
187 tcx: TyCtxt<'_>,
188 impl_def_id: LocalDefId,
189) -> Result<(), ErrorGuaranteed> {
190 let impl_self_ty = tcx.type_of(impl_def_id).instantiate_identity();
191
192 impl_self_ty.error_reported()?;
195
196 let impl_generics = tcx.generics_of(impl_def_id);
197 let impl_predicates = tcx.predicates_of(impl_def_id);
198 let impl_trait_ref =
199 tcx.impl_opt_trait_ref(impl_def_id).map(ty::EarlyBinder::instantiate_identity);
200
201 impl_trait_ref.error_reported()?;
202
203 let mut input_parameters = cgp::parameters_for_impl(tcx, impl_self_ty, impl_trait_ref);
204 cgp::identify_constrained_generic_params(
205 tcx,
206 impl_predicates,
207 impl_trait_ref,
208 &mut input_parameters,
209 );
210
211 let mut res = Ok(());
212 for param in &impl_generics.own_params {
213 let err = match param.kind {
214 ty::GenericParamDefKind::Type { .. } => {
216 let param_ty = ty::ParamTy::for_def(param);
217 !input_parameters.contains(&cgp::Parameter::from(param_ty))
218 }
219 ty::GenericParamDefKind::Const { .. } => {
220 let param_ct = ty::ParamConst::for_def(param);
221 !input_parameters.contains(&cgp::Parameter::from(param_ct))
222 }
223 ty::GenericParamDefKind::Lifetime => {
224 false
226 }
227 };
228 if err {
229 let const_param_note = matches!(param.kind, ty::GenericParamDefKind::Const { .. });
230 let mut diag = tcx.dcx().create_err(UnconstrainedGenericParameter {
231 span: tcx.def_span(param.def_id),
232 param_name: tcx.item_ident(param.def_id),
233 param_def_kind: tcx.def_descr(param.def_id),
234 const_param_note,
235 const_param_note2: const_param_note,
236 });
237 diag.code(E0207);
238 res = Err(diag.emit());
239 }
240 }
241 res
242}