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