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;
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 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 { .. });
63
64 let mut res = tcx.ensure_result().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().skip_norm_wip();
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 =
90 of_trait.then(|| tcx.impl_trait_ref(impl_def_id).instantiate_identity().skip_norm_wip());
91
92 impl_trait_ref.error_reported()?;
93
94 let mut input_parameters = cgp::parameters_for_impl(tcx, impl_self_ty, impl_trait_ref);
95 cgp::identify_constrained_generic_params(
96 tcx,
97 impl_predicates,
98 impl_trait_ref,
99 &mut input_parameters,
100 );
101
102 let lifetimes_in_associated_types: FxHashSet<_> = tcx
104 .associated_item_def_ids(impl_def_id)
105 .iter()
106 .flat_map(|&def_id| {
107 let item = tcx.associated_item(def_id);
108 match item.kind {
109 ty::AssocKind::Type { .. } => {
110 if item.defaultness(tcx).has_value() {
111 cgp::parameters_for(
112 tcx,
113 tcx.type_of(def_id).instantiate_identity().skip_norm_wip(),
114 true,
115 )
116 } else {
117 ::alloc::vec::Vec::new()vec![]
118 }
119 }
120 ty::AssocKind::Fn { .. } | ty::AssocKind::Const { .. } => ::alloc::vec::Vec::new()vec![],
121 }
122 })
123 .collect();
124
125 let mut res = Ok(());
126 for param in &impl_generics.own_params {
127 match param.kind {
128 ty::GenericParamDefKind::Lifetime => {
129 let param_lt = cgp::Parameter::from(param.to_early_bound_region_data());
148 if lifetimes_in_associated_types.contains(¶m_lt)
149 && !input_parameters.contains(¶m_lt)
150 {
151 let mut diag = tcx.dcx().create_err(UnconstrainedGenericParameter {
152 span: tcx.def_span(param.def_id),
153 param_name: tcx.item_ident(param.def_id),
154 param_def_kind: tcx.def_descr(param.def_id),
155 const_param_note: false,
156 const_param_note2: false,
157 });
158 diag.code(E0207);
159 for p in &impl_generics.own_params {
160 if p.name == kw::UnderscoreLifetime {
161 let span = tcx.def_span(p.def_id);
162 let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) else {
163 continue;
164 };
165
166 let (span, sugg) = if &snippet == "'_" {
167 (span, param.name.to_string())
168 } else {
169 (span.shrink_to_hi(), ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} ", param.name))
})format!("{} ", param.name))
170 };
171 diag.span_suggestion_verbose(
172 span,
173 "consider using the named lifetime here instead of an implicit \
174 lifetime",
175 sugg,
176 Applicability::MaybeIncorrect,
177 );
178 }
179 }
180 res = Err(diag.emit());
181 }
182 }
183 ty::GenericParamDefKind::Type { .. } | ty::GenericParamDefKind::Const { .. } => {
184 }
186 }
187 }
188 res
189}
190
191pub(crate) fn enforce_impl_non_lifetime_params_are_constrained(
192 tcx: TyCtxt<'_>,
193 impl_def_id: LocalDefId,
194) -> Result<(), ErrorGuaranteed> {
195 let impl_self_ty = tcx.type_of(impl_def_id).instantiate_identity().skip_norm_wip();
196
197 impl_self_ty.error_reported()?;
200
201 let impl_generics = tcx.generics_of(impl_def_id);
202 let impl_predicates = tcx.predicates_of(impl_def_id);
203 let impl_trait_ref = tcx
204 .impl_opt_trait_ref(impl_def_id)
205 .map(ty::EarlyBinder::instantiate_identity)
206 .map(Unnormalized::skip_norm_wip);
207
208 impl_trait_ref.error_reported()?;
209
210 let mut input_parameters = cgp::parameters_for_impl(tcx, impl_self_ty, impl_trait_ref);
211 cgp::identify_constrained_generic_params(
212 tcx,
213 impl_predicates,
214 impl_trait_ref,
215 &mut input_parameters,
216 );
217
218 let mut res = Ok(());
219 for param in &impl_generics.own_params {
220 let err = match param.kind {
221 ty::GenericParamDefKind::Type { .. } => {
223 let param_ty = ty::ParamTy::for_def(param);
224 !input_parameters.contains(&cgp::Parameter::from(param_ty))
225 }
226 ty::GenericParamDefKind::Const { .. } => {
227 let param_ct = ty::ParamConst::for_def(param);
228 !input_parameters.contains(&cgp::Parameter::from(param_ct))
229 }
230 ty::GenericParamDefKind::Lifetime => {
231 false
233 }
234 };
235 if err {
236 let const_param_note = #[allow(non_exhaustive_omitted_patterns)] match param.kind {
ty::GenericParamDefKind::Const { .. } => true,
_ => false,
}matches!(param.kind, ty::GenericParamDefKind::Const { .. });
237 let mut diag = tcx.dcx().create_err(UnconstrainedGenericParameter {
238 span: tcx.def_span(param.def_id),
239 param_name: tcx.item_ident(param.def_id),
240 param_def_kind: tcx.def_descr(param.def_id),
241 const_param_note,
242 const_param_note2: const_param_note,
243 });
244 diag.code(E0207);
245 res = Err(diag.emit());
246 }
247 }
248 res
249}