rustc_hir_analysis/
impl_wf_check.rs1use std::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, Unnormalized};
20use rustc_span::{ErrorGuaranteed, kw};
21
22use crate::constrained_generic_params as cgp;
23use crate::errors::UnconstrainedGenericParameter;
24use crate::errors::remove_or_use_generic::suggest_to_remove_or_use_generic;
25
26mod min_specialization;
27
28pub(crate) fn check_impl_wf(
59 tcx: TyCtxt<'_>,
60 impl_def_id: LocalDefId,
61 of_trait: bool,
62) -> Result<(), ErrorGuaranteed> {
63 if true {
{
match tcx.def_kind(impl_def_id) {
DefKind::Impl { .. } => {}
ref left_val => {
::core::panicking::assert_matches_failed(left_val,
"DefKind::Impl { .. }", ::core::option::Option::None);
}
}
};
};debug_assert_matches!(tcx.def_kind(impl_def_id), DefKind::Impl { .. });
64
65 let mut res = tcx.ensure_result().enforce_impl_non_lifetime_params_are_constrained(impl_def_id);
69 res = res.and(enforce_impl_lifetime_params_are_constrained(tcx, impl_def_id, of_trait));
70
71 if of_trait && tcx.features().min_specialization() {
72 res = res.and(check_min_specialization(tcx, impl_def_id));
73 }
74 res
75}
76
77pub(crate) fn enforce_impl_lifetime_params_are_constrained(
78 tcx: TyCtxt<'_>,
79 impl_def_id: LocalDefId,
80 of_trait: bool,
81) -> Result<(), ErrorGuaranteed> {
82 let impl_self_ty = tcx.type_of(impl_def_id).instantiate_identity().skip_norm_wip();
83
84 impl_self_ty.error_reported()?;
87
88 let impl_generics = tcx.generics_of(impl_def_id);
89 let impl_predicates = tcx.predicates_of(impl_def_id);
90 let impl_trait_ref =
91 of_trait.then(|| tcx.impl_trait_ref(impl_def_id).instantiate_identity().skip_norm_wip());
92
93 impl_trait_ref.error_reported()?;
94
95 let mut input_parameters = cgp::parameters_for_impl(tcx, impl_self_ty, impl_trait_ref);
96 cgp::identify_constrained_generic_params(
97 tcx,
98 impl_predicates,
99 impl_trait_ref,
100 &mut input_parameters,
101 );
102
103 let lifetimes_in_associated_types: FxHashSet<_> = tcx
105 .associated_item_def_ids(impl_def_id)
106 .iter()
107 .flat_map(|&def_id| {
108 let item = tcx.associated_item(def_id);
109 match item.kind {
110 ty::AssocKind::Type { .. } => {
111 if item.defaultness(tcx).has_value() {
112 cgp::parameters_for(
113 tcx,
114 tcx.type_of(def_id).instantiate_identity().skip_norm_wip(),
115 true,
116 )
117 } else {
118 ::alloc::vec::Vec::new()vec![]
119 }
120 }
121 ty::AssocKind::Fn { .. } | ty::AssocKind::Const { .. } => ::alloc::vec::Vec::new()vec![],
122 }
123 })
124 .collect();
125
126 let mut res = Ok(());
127 for param in &impl_generics.own_params {
128 match param.kind {
129 ty::GenericParamDefKind::Lifetime => {
130 let param_lt = cgp::Parameter::from(param.to_early_bound_region_data());
149 if lifetimes_in_associated_types.contains(¶m_lt)
150 && !input_parameters.contains(¶m_lt)
151 {
152 let mut diag = tcx.dcx().create_err(UnconstrainedGenericParameter {
153 span: tcx.def_span(param.def_id),
154 param_name: tcx.item_ident(param.def_id),
155 param_def_kind: tcx.def_descr(param.def_id),
156 const_param_note: false,
157 const_param_note2: false,
158 });
159 diag.code(E0207);
160 for p in &impl_generics.own_params {
161 if p.name == kw::UnderscoreLifetime {
162 let span = tcx.def_span(p.def_id);
163 let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) else {
164 continue;
165 };
166
167 let (span, sugg) = if &snippet == "'_" {
168 (span, param.name.to_string())
169 } else {
170 (span.shrink_to_hi(), ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} ", param.name))
})format!("{} ", param.name))
171 };
172 diag.span_suggestion_verbose(
173 span,
174 "consider using the named lifetime here instead of an implicit \
175 lifetime",
176 sugg,
177 Applicability::MaybeIncorrect,
178 );
179 }
180 }
181 suggest_to_remove_or_use_generic(tcx, &mut diag, impl_def_id, param, true);
182 res = Err(diag.emit());
183 }
184 }
185 ty::GenericParamDefKind::Type { .. } | ty::GenericParamDefKind::Const { .. } => {
186 }
188 }
189 }
190 res
191}
192
193pub(crate) fn enforce_impl_non_lifetime_params_are_constrained(
194 tcx: TyCtxt<'_>,
195 impl_def_id: LocalDefId,
196) -> Result<(), ErrorGuaranteed> {
197 let impl_self_ty = tcx.type_of(impl_def_id).instantiate_identity().skip_norm_wip();
198
199 impl_self_ty.error_reported()?;
202
203 let impl_generics = tcx.generics_of(impl_def_id);
204 let impl_predicates = tcx.predicates_of(impl_def_id);
205 let impl_trait_ref = tcx
206 .impl_opt_trait_ref(impl_def_id)
207 .map(ty::EarlyBinder::instantiate_identity)
208 .map(Unnormalized::skip_norm_wip);
209
210 impl_trait_ref.error_reported()?;
211
212 let mut input_parameters = cgp::parameters_for_impl(tcx, impl_self_ty, impl_trait_ref);
213 cgp::identify_constrained_generic_params(
214 tcx,
215 impl_predicates,
216 impl_trait_ref,
217 &mut input_parameters,
218 );
219
220 let mut res = Ok(());
221 for param in &impl_generics.own_params {
222 let err = match param.kind {
223 ty::GenericParamDefKind::Type { .. } => {
225 let param_ty = ty::ParamTy::for_def(param);
226 !input_parameters.contains(&cgp::Parameter::from(param_ty))
227 }
228 ty::GenericParamDefKind::Const { .. } => {
229 let param_ct = ty::ParamConst::for_def(param);
230 !input_parameters.contains(&cgp::Parameter::from(param_ct))
231 }
232 ty::GenericParamDefKind::Lifetime => {
233 false
235 }
236 };
237 if err {
238 let const_param_note = #[allow(non_exhaustive_omitted_patterns)] match param.kind {
ty::GenericParamDefKind::Const { .. } => true,
_ => false,
}matches!(param.kind, ty::GenericParamDefKind::Const { .. });
239 let mut diag = tcx.dcx().create_err(UnconstrainedGenericParameter {
240 span: tcx.def_span(param.def_id),
241 param_name: tcx.item_ident(param.def_id),
242 param_def_kind: tcx.def_descr(param.def_id),
243 const_param_note,
244 const_param_note2: const_param_note,
245 });
246 diag.code(E0207);
247 suggest_to_remove_or_use_generic(tcx, &mut diag, impl_def_id, ¶m, false);
248 res = Err(diag.emit());
249 }
250 }
251 res
252}