]>
Commit | Line | Data |
---|---|---|
9ffffee4 | 1 | use crate::middle::resolve_bound_vars as rbv; |
2b03887a FG |
2 | use hir::{ |
3 | intravisit::{self, Visitor}, | |
4 | GenericParamKind, HirId, Node, | |
5 | }; | |
6 | use rustc_hir as hir; | |
7 | use rustc_hir::def::DefKind; | |
353b0b11 | 8 | use rustc_hir::def_id::LocalDefId; |
2b03887a FG |
9 | use rustc_middle::ty::{self, TyCtxt}; |
10 | use rustc_session::lint; | |
11 | use rustc_span::symbol::{kw, Symbol}; | |
12 | use rustc_span::Span; | |
13 | ||
353b0b11 | 14 | pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { |
2b03887a FG |
15 | use rustc_hir::*; |
16 | ||
353b0b11 | 17 | let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); |
2b03887a FG |
18 | |
19 | let node = tcx.hir().get(hir_id); | |
20 | let parent_def_id = match node { | |
21 | Node::ImplItem(_) | |
22 | | Node::TraitItem(_) | |
23 | | Node::Variant(_) | |
24 | | Node::Ctor(..) | |
25 | | Node::Field(_) => { | |
26 | let parent_id = tcx.hir().get_parent_item(hir_id); | |
27 | Some(parent_id.to_def_id()) | |
28 | } | |
29 | // FIXME(#43408) always enable this once `lazy_normalization` is | |
30 | // stable enough and does not need a feature gate anymore. | |
31 | Node::AnonConst(_) => { | |
32 | let parent_def_id = tcx.hir().get_parent_item(hir_id); | |
33 | ||
34 | let mut in_param_ty = false; | |
35 | for (_parent, node) in tcx.hir().parent_iter(hir_id) { | |
36 | if let Some(generics) = node.generics() { | |
37 | let mut visitor = AnonConstInParamTyDetector { | |
38 | in_param_ty: false, | |
39 | found_anon_const_in_param_ty: false, | |
40 | ct: hir_id, | |
41 | }; | |
42 | ||
43 | visitor.visit_generics(generics); | |
44 | in_param_ty = visitor.found_anon_const_in_param_ty; | |
45 | break; | |
46 | } | |
47 | } | |
48 | ||
49 | if in_param_ty { | |
50 | // We do not allow generic parameters in anon consts if we are inside | |
51 | // of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed. | |
52 | None | |
53 | } else if tcx.lazy_normalization() { | |
487cf647 | 54 | if let Some(param_id) = tcx.hir().opt_const_param_default_param_def_id(hir_id) { |
2b03887a FG |
55 | // If the def_id we are calling generics_of on is an anon ct default i.e: |
56 | // | |
57 | // struct Foo<const N: usize = { .. }>; | |
58 | // ^^^ ^ ^^^^^^ def id of this anon const | |
59 | // ^ ^ param_id | |
60 | // ^ parent_def_id | |
61 | // | |
62 | // then we only want to return generics for params to the left of `N`. If we don't do that we | |
63 | // end up with that const looking like: `ty::ConstKind::Unevaluated(def_id, substs: [N#0])`. | |
64 | // | |
65 | // This causes ICEs (#86580) when building the substs for Foo in `fn foo() -> Foo { .. }` as | |
66 | // we substitute the defaults with the partially built substs when we build the substs. Subst'ing | |
67 | // the `N#0` on the unevaluated const indexes into the empty substs we're in the process of building. | |
68 | // | |
69 | // We fix this by having this function return the parent's generics ourselves and truncating the | |
70 | // generics to only include non-forward declared params (with the exception of the `Self` ty) | |
71 | // | |
72 | // For the above code example that means we want `substs: []` | |
73 | // For the following struct def we want `substs: [N#0]` when generics_of is called on | |
74 | // the def id of the `{ N + 1 }` anon const | |
75 | // struct Foo<const N: usize, const M: usize = { N + 1 }>; | |
76 | // | |
77 | // This has some implications for how we get the predicates available to the anon const | |
78 | // see `explicit_predicates_of` for more information on this | |
79 | let generics = tcx.generics_of(parent_def_id.to_def_id()); | |
487cf647 | 80 | let param_def_idx = generics.param_def_id_to_index[¶m_id.to_def_id()]; |
2b03887a | 81 | // In the above example this would be .params[..N#0] |
9c376795 | 82 | let params = generics.params_to(param_def_idx as usize, tcx).to_owned(); |
2b03887a FG |
83 | let param_def_id_to_index = |
84 | params.iter().map(|param| (param.def_id, param.index)).collect(); | |
85 | ||
86 | return ty::Generics { | |
87 | // we set the parent of these generics to be our parent's parent so that we | |
88 | // dont end up with substs: [N, M, N] for the const default on a struct like this: | |
89 | // struct Foo<const N: usize, const M: usize = { ... }>; | |
90 | parent: generics.parent, | |
91 | parent_count: generics.parent_count, | |
92 | params, | |
93 | param_def_id_to_index, | |
94 | has_self: generics.has_self, | |
95 | has_late_bound_regions: generics.has_late_bound_regions, | |
96 | }; | |
97 | } | |
98 | ||
99 | // HACK(eddyb) this provides the correct generics when | |
100 | // `feature(generic_const_expressions)` is enabled, so that const expressions | |
101 | // used with const generics, e.g. `Foo<{N+1}>`, can work at all. | |
102 | // | |
103 | // Note that we do not supply the parent generics when using | |
104 | // `min_const_generics`. | |
105 | Some(parent_def_id.to_def_id()) | |
106 | } else { | |
9c376795 | 107 | let parent_node = tcx.hir().get_parent(hir_id); |
2b03887a FG |
108 | match parent_node { |
109 | // HACK(eddyb) this provides the correct generics for repeat | |
110 | // expressions' count (i.e. `N` in `[x; N]`), and explicit | |
111 | // `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`), | |
112 | // as they shouldn't be able to cause query cycle errors. | |
9c376795 | 113 | Node::Expr(Expr { kind: ExprKind::Repeat(_, constant), .. }) |
2b03887a FG |
114 | if constant.hir_id() == hir_id => |
115 | { | |
116 | Some(parent_def_id.to_def_id()) | |
117 | } | |
9c376795 | 118 | Node::Variant(Variant { disr_expr: Some(constant), .. }) |
2b03887a FG |
119 | if constant.hir_id == hir_id => |
120 | { | |
121 | Some(parent_def_id.to_def_id()) | |
122 | } | |
123 | Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => { | |
353b0b11 | 124 | Some(tcx.typeck_root_def_id(def_id.to_def_id())) |
2b03887a FG |
125 | } |
126 | // Exclude `GlobalAsm` here which cannot have generics. | |
127 | Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) | |
128 | if asm.operands.iter().any(|(op, _op_sp)| match op { | |
129 | hir::InlineAsmOperand::Const { anon_const } | |
130 | | hir::InlineAsmOperand::SymFn { anon_const } => { | |
131 | anon_const.hir_id == hir_id | |
132 | } | |
133 | _ => false, | |
134 | }) => | |
135 | { | |
136 | Some(parent_def_id.to_def_id()) | |
137 | } | |
138 | _ => None, | |
139 | } | |
140 | } | |
141 | } | |
142 | Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => { | |
353b0b11 | 143 | Some(tcx.typeck_root_def_id(def_id.to_def_id())) |
2b03887a FG |
144 | } |
145 | Node::Item(item) => match item.kind { | |
146 | ItemKind::OpaqueTy(hir::OpaqueTy { | |
147 | origin: | |
148 | hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id), | |
149 | in_trait, | |
150 | .. | |
151 | }) => { | |
152 | if in_trait { | |
153 | assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn)) | |
154 | } else { | |
155 | assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn)) | |
156 | } | |
157 | Some(fn_def_id.to_def_id()) | |
158 | } | |
159 | ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => { | |
160 | let parent_id = tcx.hir().get_parent_item(hir_id); | |
161 | assert_ne!(parent_id, hir::CRATE_OWNER_ID); | |
162 | debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent_id); | |
163 | // Opaque types are always nested within another item, and | |
164 | // inherit the generics of the item. | |
165 | Some(parent_id.to_def_id()) | |
166 | } | |
167 | _ => None, | |
168 | }, | |
169 | _ => None, | |
170 | }; | |
171 | ||
172 | enum Defaults { | |
173 | Allowed, | |
174 | // See #36887 | |
175 | FutureCompatDisallowed, | |
176 | Deny, | |
177 | } | |
178 | ||
179 | let no_generics = hir::Generics::empty(); | |
180 | let ast_generics = node.generics().unwrap_or(&no_generics); | |
181 | let (opt_self, allow_defaults) = match node { | |
182 | Node::Item(item) => { | |
183 | match item.kind { | |
184 | ItemKind::Trait(..) | ItemKind::TraitAlias(..) => { | |
185 | // Add in the self type parameter. | |
186 | // | |
187 | // Something of a hack: use the node id for the trait, also as | |
188 | // the node id for the Self type parameter. | |
189 | let opt_self = Some(ty::GenericParamDef { | |
190 | index: 0, | |
191 | name: kw::SelfUpper, | |
353b0b11 | 192 | def_id: def_id.to_def_id(), |
2b03887a FG |
193 | pure_wrt_drop: false, |
194 | kind: ty::GenericParamDefKind::Type { | |
195 | has_default: false, | |
196 | synthetic: false, | |
197 | }, | |
198 | }); | |
199 | ||
200 | (opt_self, Defaults::Allowed) | |
201 | } | |
202 | ItemKind::TyAlias(..) | |
203 | | ItemKind::Enum(..) | |
204 | | ItemKind::Struct(..) | |
205 | | ItemKind::OpaqueTy(..) | |
206 | | ItemKind::Union(..) => (None, Defaults::Allowed), | |
207 | _ => (None, Defaults::FutureCompatDisallowed), | |
208 | } | |
209 | } | |
210 | ||
211 | // GATs | |
212 | Node::TraitItem(item) if matches!(item.kind, TraitItemKind::Type(..)) => { | |
213 | (None, Defaults::Deny) | |
214 | } | |
215 | Node::ImplItem(item) if matches!(item.kind, ImplItemKind::Type(..)) => { | |
216 | (None, Defaults::Deny) | |
217 | } | |
218 | ||
219 | _ => (None, Defaults::FutureCompatDisallowed), | |
220 | }; | |
221 | ||
222 | let has_self = opt_self.is_some(); | |
223 | let mut parent_has_self = false; | |
224 | let mut own_start = has_self as u32; | |
225 | let parent_count = parent_def_id.map_or(0, |def_id| { | |
226 | let generics = tcx.generics_of(def_id); | |
227 | assert!(!has_self); | |
228 | parent_has_self = generics.has_self; | |
229 | own_start = generics.count() as u32; | |
230 | generics.parent_count + generics.params.len() | |
231 | }); | |
232 | ||
233 | let mut params: Vec<_> = Vec::with_capacity(ast_generics.params.len() + has_self as usize); | |
234 | ||
235 | if let Some(opt_self) = opt_self { | |
236 | params.push(opt_self); | |
237 | } | |
238 | ||
239 | let early_lifetimes = super::early_bound_lifetimes_from_generics(tcx, ast_generics); | |
240 | params.extend(early_lifetimes.enumerate().map(|(i, param)| ty::GenericParamDef { | |
241 | name: param.name.ident().name, | |
242 | index: own_start + i as u32, | |
487cf647 | 243 | def_id: param.def_id.to_def_id(), |
2b03887a FG |
244 | pure_wrt_drop: param.pure_wrt_drop, |
245 | kind: ty::GenericParamDefKind::Lifetime, | |
246 | })); | |
247 | ||
248 | // Now create the real type and const parameters. | |
249 | let type_start = own_start - has_self as u32 + params.len() as u32; | |
250 | let mut i = 0; | |
251 | let mut next_index = || { | |
252 | let prev = i; | |
253 | i += 1; | |
254 | prev as u32 + type_start | |
255 | }; | |
256 | ||
257 | const TYPE_DEFAULT_NOT_ALLOWED: &'static str = "defaults for type parameters are only allowed in \ | |
258 | `struct`, `enum`, `type`, or `trait` definitions"; | |
259 | ||
260 | params.extend(ast_generics.params.iter().filter_map(|param| match param.kind { | |
261 | GenericParamKind::Lifetime { .. } => None, | |
9c376795 | 262 | GenericParamKind::Type { default, synthetic, .. } => { |
2b03887a FG |
263 | if default.is_some() { |
264 | match allow_defaults { | |
265 | Defaults::Allowed => {} | |
266 | Defaults::FutureCompatDisallowed | |
267 | if tcx.features().default_type_parameter_fallback => {} | |
268 | Defaults::FutureCompatDisallowed => { | |
269 | tcx.struct_span_lint_hir( | |
270 | lint::builtin::INVALID_TYPE_PARAM_DEFAULT, | |
271 | param.hir_id, | |
272 | param.span, | |
273 | TYPE_DEFAULT_NOT_ALLOWED, | |
274 | |lint| lint, | |
275 | ); | |
276 | } | |
277 | Defaults::Deny => { | |
278 | tcx.sess.span_err(param.span, TYPE_DEFAULT_NOT_ALLOWED); | |
279 | } | |
280 | } | |
281 | } | |
282 | ||
283 | let kind = ty::GenericParamDefKind::Type { has_default: default.is_some(), synthetic }; | |
284 | ||
285 | Some(ty::GenericParamDef { | |
286 | index: next_index(), | |
287 | name: param.name.ident().name, | |
487cf647 | 288 | def_id: param.def_id.to_def_id(), |
2b03887a FG |
289 | pure_wrt_drop: param.pure_wrt_drop, |
290 | kind, | |
291 | }) | |
292 | } | |
293 | GenericParamKind::Const { default, .. } => { | |
294 | if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() { | |
295 | tcx.sess.span_err( | |
296 | param.span, | |
297 | "defaults for const parameters are only allowed in \ | |
298 | `struct`, `enum`, `type`, or `trait` definitions", | |
299 | ); | |
300 | } | |
301 | ||
302 | Some(ty::GenericParamDef { | |
303 | index: next_index(), | |
304 | name: param.name.ident().name, | |
487cf647 | 305 | def_id: param.def_id.to_def_id(), |
2b03887a FG |
306 | pure_wrt_drop: param.pure_wrt_drop, |
307 | kind: ty::GenericParamDefKind::Const { has_default: default.is_some() }, | |
308 | }) | |
309 | } | |
310 | })); | |
311 | ||
312 | // provide junk type parameter defs - the only place that | |
313 | // cares about anything but the length is instantiation, | |
314 | // and we don't do that for closures. | |
315 | if let Node::Expr(&hir::Expr { | |
316 | kind: hir::ExprKind::Closure(hir::Closure { movability: gen, .. }), | |
317 | .. | |
318 | }) = node | |
319 | { | |
320 | let dummy_args = if gen.is_some() { | |
321 | &["<resume_ty>", "<yield_ty>", "<return_ty>", "<witness>", "<upvars>"][..] | |
322 | } else { | |
323 | &["<closure_kind>", "<closure_signature>", "<upvars>"][..] | |
324 | }; | |
325 | ||
326 | params.extend(dummy_args.iter().map(|&arg| ty::GenericParamDef { | |
327 | index: next_index(), | |
328 | name: Symbol::intern(arg), | |
353b0b11 | 329 | def_id: def_id.to_def_id(), |
2b03887a FG |
330 | pure_wrt_drop: false, |
331 | kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false }, | |
332 | })); | |
333 | } | |
334 | ||
335 | // provide junk type parameter defs for const blocks. | |
336 | if let Node::AnonConst(_) = node { | |
9c376795 | 337 | let parent_node = tcx.hir().get_parent(hir_id); |
2b03887a FG |
338 | if let Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) = parent_node { |
339 | params.push(ty::GenericParamDef { | |
340 | index: next_index(), | |
341 | name: Symbol::intern("<const_ty>"), | |
353b0b11 | 342 | def_id: def_id.to_def_id(), |
2b03887a FG |
343 | pure_wrt_drop: false, |
344 | kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false }, | |
345 | }); | |
346 | } | |
347 | } | |
348 | ||
349 | let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect(); | |
350 | ||
351 | ty::Generics { | |
352 | parent: parent_def_id, | |
353 | parent_count, | |
354 | params, | |
355 | param_def_id_to_index, | |
356 | has_self: has_self || parent_has_self, | |
357 | has_late_bound_regions: has_late_bound_regions(tcx, node), | |
358 | } | |
359 | } | |
360 | ||
361 | fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<Span> { | |
362 | struct LateBoundRegionsDetector<'tcx> { | |
363 | tcx: TyCtxt<'tcx>, | |
364 | outer_index: ty::DebruijnIndex, | |
365 | has_late_bound_regions: Option<Span>, | |
366 | } | |
367 | ||
368 | impl<'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'tcx> { | |
369 | fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { | |
370 | if self.has_late_bound_regions.is_some() { | |
371 | return; | |
372 | } | |
373 | match ty.kind { | |
374 | hir::TyKind::BareFn(..) => { | |
375 | self.outer_index.shift_in(1); | |
376 | intravisit::walk_ty(self, ty); | |
377 | self.outer_index.shift_out(1); | |
378 | } | |
379 | _ => intravisit::walk_ty(self, ty), | |
380 | } | |
381 | } | |
382 | ||
383 | fn visit_poly_trait_ref(&mut self, tr: &'tcx hir::PolyTraitRef<'tcx>) { | |
384 | if self.has_late_bound_regions.is_some() { | |
385 | return; | |
386 | } | |
387 | self.outer_index.shift_in(1); | |
388 | intravisit::walk_poly_trait_ref(self, tr); | |
389 | self.outer_index.shift_out(1); | |
390 | } | |
391 | ||
392 | fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) { | |
393 | if self.has_late_bound_regions.is_some() { | |
394 | return; | |
395 | } | |
396 | ||
9ffffee4 FG |
397 | match self.tcx.named_bound_var(lt.hir_id) { |
398 | Some(rbv::ResolvedArg::StaticLifetime | rbv::ResolvedArg::EarlyBound(..)) => {} | |
399 | Some(rbv::ResolvedArg::LateBound(debruijn, _, _)) | |
400 | if debruijn < self.outer_index => {} | |
401 | Some( | |
402 | rbv::ResolvedArg::LateBound(..) | |
403 | | rbv::ResolvedArg::Free(..) | |
404 | | rbv::ResolvedArg::Error(_), | |
405 | ) | |
406 | | None => { | |
487cf647 | 407 | self.has_late_bound_regions = Some(lt.ident.span); |
2b03887a FG |
408 | } |
409 | } | |
410 | } | |
411 | } | |
412 | ||
413 | fn has_late_bound_regions<'tcx>( | |
414 | tcx: TyCtxt<'tcx>, | |
415 | generics: &'tcx hir::Generics<'tcx>, | |
416 | decl: &'tcx hir::FnDecl<'tcx>, | |
417 | ) -> Option<Span> { | |
418 | let mut visitor = LateBoundRegionsDetector { | |
419 | tcx, | |
420 | outer_index: ty::INNERMOST, | |
421 | has_late_bound_regions: None, | |
422 | }; | |
423 | for param in generics.params { | |
424 | if let GenericParamKind::Lifetime { .. } = param.kind { | |
425 | if tcx.is_late_bound(param.hir_id) { | |
426 | return Some(param.span); | |
427 | } | |
428 | } | |
429 | } | |
430 | visitor.visit_fn_decl(decl); | |
431 | visitor.has_late_bound_regions | |
432 | } | |
433 | ||
434 | match node { | |
9c376795 FG |
435 | Node::TraitItem(item) => match &item.kind { |
436 | hir::TraitItemKind::Fn(sig, _) => has_late_bound_regions(tcx, &item.generics, sig.decl), | |
2b03887a FG |
437 | _ => None, |
438 | }, | |
9c376795 FG |
439 | Node::ImplItem(item) => match &item.kind { |
440 | hir::ImplItemKind::Fn(sig, _) => has_late_bound_regions(tcx, &item.generics, sig.decl), | |
2b03887a FG |
441 | _ => None, |
442 | }, | |
443 | Node::ForeignItem(item) => match item.kind { | |
9c376795 | 444 | hir::ForeignItemKind::Fn(fn_decl, _, generics) => { |
2b03887a FG |
445 | has_late_bound_regions(tcx, generics, fn_decl) |
446 | } | |
447 | _ => None, | |
448 | }, | |
9c376795 FG |
449 | Node::Item(item) => match &item.kind { |
450 | hir::ItemKind::Fn(sig, .., generics, _) => { | |
2b03887a FG |
451 | has_late_bound_regions(tcx, generics, sig.decl) |
452 | } | |
453 | _ => None, | |
454 | }, | |
455 | _ => None, | |
456 | } | |
457 | } | |
458 | ||
459 | struct AnonConstInParamTyDetector { | |
460 | in_param_ty: bool, | |
461 | found_anon_const_in_param_ty: bool, | |
462 | ct: HirId, | |
463 | } | |
464 | ||
465 | impl<'v> Visitor<'v> for AnonConstInParamTyDetector { | |
466 | fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) { | |
467 | if let GenericParamKind::Const { ty, default: _ } = p.kind { | |
468 | let prev = self.in_param_ty; | |
469 | self.in_param_ty = true; | |
470 | self.visit_ty(ty); | |
471 | self.in_param_ty = prev; | |
472 | } | |
473 | } | |
474 | ||
475 | fn visit_anon_const(&mut self, c: &'v hir::AnonConst) { | |
476 | if self.in_param_ty && self.ct == c.hir_id { | |
477 | self.found_anon_const_in_param_ty = true; | |
478 | } else { | |
479 | intravisit::walk_anon_const(self, c) | |
480 | } | |
481 | } | |
482 | } |