]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_hir_analysis/src/collect/type_of.rs
New upstream version 1.70.0+dfsg1
[rustc.git] / compiler / rustc_hir_analysis / src / collect / type_of.rs
CommitLineData
5e7ed085 1use rustc_errors::{Applicability, StashKey};
74b04a01 2use rustc_hir as hir;
f9f354fc 3use rustc_hir::def_id::{DefId, LocalDefId};
74b04a01
XL
4use rustc_hir::intravisit;
5use rustc_hir::intravisit::Visitor;
5869c6ff 6use rustc_hir::{HirId, Node};
5099ac24 7use rustc_middle::hir::nested_filter;
9c376795 8use rustc_middle::ty::print::with_forced_trimmed_paths;
5099ac24 9use rustc_middle::ty::subst::InternalSubsts;
ba9703b0 10use rustc_middle::ty::util::IntTypeExt;
353b0b11 11use rustc_middle::ty::{self, ImplTraitInTraitData, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
f035d41b 12use rustc_span::symbol::Ident;
74b04a01
XL
13use rustc_span::{Span, DUMMY_SP};
14
15use super::ItemCtxt;
a2a8927a 16use super::{bad_placeholder, is_suggestable_infer_ty};
04454e1e 17use crate::errors::UnconstrainedOpaqueType;
74b04a01 18
3dfed10e
XL
19/// Computes the relevant generic parameter for a potential generic const argument.
20///
21/// This should be called using the query `tcx.opt_const_param_of`.
22pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<DefId> {
23 use hir::*;
3dfed10e
XL
24 let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
25
5099ac24
FG
26 match tcx.hir().get(hir_id) {
27 Node::AnonConst(_) => (),
28 _ => return None,
29 };
6a06907d 30
9c376795 31 let parent_node_id = tcx.hir().parent_id(hir_id);
5099ac24 32 let parent_node = tcx.hir().get(parent_node_id);
6a06907d 33
5099ac24
FG
34 let (generics, arg_idx) = match parent_node {
35 // This match arm is for when the def_id appears in a GAT whose
36 // path can't be resolved without typechecking e.g.
37 //
38 // trait Foo {
39 // type Assoc<const N: usize>;
40 // fn foo() -> Self::Assoc<3>;
41 // }
42 //
43 // In the above code we would call this query with the def_id of 3 and
44 // the parent_node we match on would be the hir node for Self::Assoc<3>
45 //
5e7ed085 46 // `Self::Assoc<3>` cant be resolved without typechecking here as we
5099ac24
FG
47 // didnt write <Self as Foo>::Assoc<3>. If we did then another match
48 // arm would handle this.
49 //
50 // I believe this match arm is only needed for GAT but I am not 100% sure - BoxyUwU
51 Node::Ty(hir_ty @ Ty { kind: TyKind::Path(QPath::TypeRelative(_, segment)), .. }) => {
52 // Find the Item containing the associated type so we can create an ItemCtxt.
53 // Using the ItemCtxt convert the HIR for the unresolved assoc type into a
54 // ty which is a fully resolved projection.
55 // For the code example above, this would mean converting Self::Assoc<3>
9c376795 56 // into a ty::Alias(ty::Projection, <Self as Foo>::Assoc<3>)
9ffffee4 57 let item_def_id = tcx
5099ac24 58 .hir()
9ffffee4
FG
59 .parent_owner_iter(hir_id)
60 .find(|(_, node)| matches!(node, OwnerNode::Item(_)))
61 .unwrap()
62 .0
353b0b11 63 .def_id;
9ffffee4 64 let item_ctxt = &ItemCtxt::new(tcx, item_def_id) as &dyn crate::astconv::AstConv<'_>;
5099ac24
FG
65 let ty = item_ctxt.ast_ty_to_ty(hir_ty);
66
67 // Iterate through the generics of the projection to find the one that corresponds to
f2b60f7d
FG
68 // the def_id that this query was called with. We filter to only type and const args here
69 // as a precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't
5099ac24 70 // but it can't hurt to be safe ^^
9c376795
FG
71 if let ty::Alias(ty::Projection, projection) = ty.kind() {
72 let generics = tcx.generics_of(projection.def_id);
5099ac24
FG
73
74 let arg_index = segment
3dfed10e
XL
75 .args
76 .and_then(|args| {
77 args.args
78 .iter()
5099ac24 79 .filter(|arg| arg.is_ty_or_const())
f2b60f7d 80 .position(|arg| arg.hir_id() == hir_id)
3dfed10e
XL
81 })
82 .unwrap_or_else(|| {
83 bug!("no arg matching AnonConst in segment");
84 });
85
5099ac24
FG
86 (generics, arg_index)
87 } else {
88 // I dont think it's possible to reach this but I'm not 100% sure - BoxyUwU
89 tcx.sess.delay_span_bug(
90 tcx.def_span(def_id),
91 "unexpected non-GAT usage of an anon const",
92 );
93 return None;
3dfed10e 94 }
5099ac24
FG
95 }
96 Node::Expr(&Expr {
97 kind:
98 ExprKind::MethodCall(segment, ..) | ExprKind::Path(QPath::TypeRelative(_, segment)),
99 ..
100 }) => {
064997fb 101 let body_owner = tcx.hir().enclosing_body_owner(hir_id);
5099ac24
FG
102 let tables = tcx.typeck(body_owner);
103 // This may fail in case the method/path does not actually exist.
104 // As there is no relevant param for `def_id`, we simply return
105 // `None` here.
106 let type_dependent_def = tables.type_dependent_def_id(parent_node_id)?;
107 let idx = segment
108 .args
109 .and_then(|args| {
110 args.args
111 .iter()
112 .filter(|arg| arg.is_ty_or_const())
f2b60f7d 113 .position(|arg| arg.hir_id() == hir_id)
5099ac24
FG
114 })
115 .unwrap_or_else(|| {
116 bug!("no arg matching AnonConst in segment");
117 });
3dfed10e 118
5099ac24
FG
119 (tcx.generics_of(type_dependent_def), idx)
120 }
121
122 Node::Ty(&Ty { kind: TyKind::Path(_), .. })
123 | Node::Expr(&Expr { kind: ExprKind::Path(_) | ExprKind::Struct(..), .. })
124 | Node::TraitRef(..)
125 | Node::Pat(_) => {
126 let path = match parent_node {
127 Node::Ty(&Ty { kind: TyKind::Path(QPath::Resolved(_, path)), .. })
128 | Node::TraitRef(&TraitRef { path, .. }) => &*path,
129 Node::Expr(&Expr {
130 kind:
131 ExprKind::Path(QPath::Resolved(_, path))
132 | ExprKind::Struct(&QPath::Resolved(_, path), ..),
133 ..
134 }) => {
064997fb 135 let body_owner = tcx.hir().enclosing_body_owner(hir_id);
5099ac24
FG
136 let _tables = tcx.typeck(body_owner);
137 &*path
138 }
139 Node::Pat(pat) => {
140 if let Some(path) = get_path_containing_arg_in_pat(pat, hir_id) {
141 path
142 } else {
1b1a35ee
XL
143 tcx.sess.delay_span_bug(
144 tcx.def_span(def_id),
5099ac24 145 &format!("unable to find const parent for {} in pat {:?}", hir_id, pat),
1b1a35ee
XL
146 );
147 return None;
148 }
5099ac24
FG
149 }
150 _ => {
151 tcx.sess.delay_span_bug(
152 tcx.def_span(def_id),
153 &format!("unexpected const parent path {:?}", parent_node),
154 );
155 return None;
156 }
157 };
3dfed10e 158
5099ac24
FG
159 // We've encountered an `AnonConst` in some path, so we need to
160 // figure out which generic parameter it corresponds to and return
161 // the relevant type.
923072b8
FG
162 let Some((arg_index, segment)) = path.segments.iter().find_map(|seg| {
163 let args = seg.args?;
164 args.args
165 .iter()
166 .filter(|arg| arg.is_ty_or_const())
f2b60f7d 167 .position(|arg| arg.hir_id() == hir_id)
923072b8 168 .map(|index| (index, seg)).or_else(|| args.bindings
3dfed10e 169 .iter()
923072b8
FG
170 .filter_map(TypeBinding::opt_const)
171 .position(|ct| ct.hir_id == hir_id)
172 .map(|idx| (idx, seg)))
173 }) else {
174 tcx.sess.delay_span_bug(
175 tcx.def_span(def_id),
176 "no arg matching AnonConst in path",
177 );
178 return None;
5099ac24
FG
179 };
180
f2b60f7d 181 let generics = match tcx.res_generics_def_id(segment.res) {
5099ac24
FG
182 Some(def_id) => tcx.generics_of(def_id),
183 None => {
184 tcx.sess.delay_span_bug(
185 tcx.def_span(def_id),
f2b60f7d 186 &format!("unexpected anon const res {:?} in path: {:?}", segment.res, path),
5099ac24
FG
187 );
188 return None;
189 }
190 };
3dfed10e 191
5099ac24
FG
192 (generics, arg_index)
193 }
194 _ => return None,
195 };
196
197 debug!(?parent_node);
198 debug!(?generics, ?arg_idx);
199 generics
200 .params
201 .iter()
202 .filter(|param| param.kind.is_ty_or_const())
203 .nth(match generics.has_self && generics.parent.is_none() {
204 true => arg_idx + 1,
205 false => arg_idx,
206 })
207 .and_then(|param| match param.kind {
208 ty::GenericParamDefKind::Const { .. } => {
209 debug!(?param);
210 Some(param.def_id)
3dfed10e
XL
211 }
212 _ => None,
5099ac24 213 })
3dfed10e
XL
214}
215
5869c6ff
XL
216fn get_path_containing_arg_in_pat<'hir>(
217 pat: &'hir hir::Pat<'hir>,
218 arg_id: HirId,
219) -> Option<&'hir hir::Path<'hir>> {
220 use hir::*;
221
222 let is_arg_in_path = |p: &hir::Path<'_>| {
223 p.segments
224 .iter()
225 .filter_map(|seg| seg.args)
226 .flat_map(|args| args.args)
f2b60f7d 227 .any(|arg| arg.hir_id() == arg_id)
5869c6ff
XL
228 };
229 let mut arg_path = None;
230 pat.walk(|pat| match pat.kind {
231 PatKind::Struct(QPath::Resolved(_, path), _, _)
232 | PatKind::TupleStruct(QPath::Resolved(_, path), _, _)
233 | PatKind::Path(QPath::Resolved(_, path))
234 if is_arg_in_path(path) =>
235 {
236 arg_path = Some(path);
237 false
238 }
239 _ => true,
240 });
241 arg_path
242}
243
353b0b11
FG
244pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty<'_>> {
245 // If we are computing `type_of` the synthesized associated type for an RPITIT in the impl
246 // side, use `collect_return_position_impl_trait_in_trait_tys` to infer the value of the
247 // associated type in the impl.
248 if let Some(ImplTraitInTraitData::Impl { fn_def_id, .. }) =
249 tcx.opt_rpitit_info(def_id.to_def_id())
250 {
251 match tcx.collect_return_position_impl_trait_in_trait_tys(fn_def_id) {
252 Ok(map) => {
253 let assoc_item = tcx.associated_item(def_id);
254 return ty::EarlyBinder(map[&assoc_item.trait_item_def_id.unwrap()]);
255 }
256 Err(_) => {
257 return ty::EarlyBinder(tcx.ty_error_with_message(
258 DUMMY_SP,
259 "Could not collect return position impl trait in trait tys",
260 ));
261 }
262 }
263 }
264
74b04a01
XL
265 use rustc_hir::*;
266
3dfed10e 267 let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
74b04a01 268
353b0b11 269 let icx = ItemCtxt::new(tcx, def_id);
74b04a01 270
9ffffee4 271 let output = match tcx.hir().get(hir_id) {
74b04a01 272 Node::TraitItem(item) => match item.kind {
ba9703b0 273 TraitItemKind::Fn(..) => {
353b0b11 274 let substs = InternalSubsts::identity_for_item(tcx, def_id);
3dfed10e 275 tcx.mk_fn_def(def_id.to_def_id(), substs)
74b04a01 276 }
c295e0f8 277 TraitItemKind::Const(ty, body_id) => body_id
74b04a01 278 .and_then(|body_id| {
353b0b11
FG
279 is_suggestable_infer_ty(ty).then(|| {
280 infer_placeholder_type(
281 tcx, def_id, body_id, ty.span, item.ident, "constant",
282 )
283 })
74b04a01
XL
284 })
285 .unwrap_or_else(|| icx.to_ty(ty)),
c295e0f8 286 TraitItemKind::Type(_, Some(ty)) => icx.to_ty(ty),
74b04a01
XL
287 TraitItemKind::Type(_, None) => {
288 span_bug!(item.span, "associated type missing default");
289 }
290 },
291
292 Node::ImplItem(item) => match item.kind {
ba9703b0 293 ImplItemKind::Fn(..) => {
353b0b11 294 let substs = InternalSubsts::identity_for_item(tcx, def_id);
3dfed10e 295 tcx.mk_fn_def(def_id.to_def_id(), substs)
74b04a01 296 }
c295e0f8 297 ImplItemKind::Const(ty, body_id) => {
74b04a01 298 if is_suggestable_infer_ty(ty) {
136023e0 299 infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident, "constant")
74b04a01
XL
300 } else {
301 icx.to_ty(ty)
302 }
303 }
2b03887a 304 ImplItemKind::Type(ty) => {
5099ac24 305 if tcx.impl_trait_ref(tcx.hir().get_parent_item(hir_id)).is_none() {
6a06907d 306 check_feature_inherent_assoc_ty(tcx, item.span);
74b04a01
XL
307 }
308
309 icx.to_ty(ty)
310 }
311 },
312
313 Node::Item(item) => {
314 match item.kind {
c295e0f8 315 ItemKind::Static(ty, .., body_id) => {
74b04a01 316 if is_suggestable_infer_ty(ty) {
136023e0
XL
317 infer_placeholder_type(
318 tcx,
319 def_id,
320 body_id,
321 ty.span,
322 item.ident,
323 "static variable",
324 )
325 } else {
326 icx.to_ty(ty)
327 }
328 }
c295e0f8 329 ItemKind::Const(ty, body_id) => {
136023e0
XL
330 if is_suggestable_infer_ty(ty) {
331 infer_placeholder_type(
332 tcx, def_id, body_id, ty.span, item.ident, "constant",
333 )
74b04a01
XL
334 } else {
335 icx.to_ty(ty)
336 }
337 }
04454e1e 338 ItemKind::TyAlias(self_ty, _) => icx.to_ty(self_ty),
353b0b11
FG
339 ItemKind::Impl(hir::Impl { self_ty, .. }) => match self_ty.find_self_aliases() {
340 spans if spans.len() > 0 => {
341 let guar = tcx.sess.emit_err(crate::errors::SelfInImplSelf {
342 span: spans.into(),
343 note: (),
344 });
345 tcx.ty_error(guar)
2b03887a 346 }
353b0b11 347 _ => icx.to_ty(*self_ty),
2b03887a 348 },
74b04a01 349 ItemKind::Fn(..) => {
353b0b11 350 let substs = InternalSubsts::identity_for_item(tcx, def_id);
3dfed10e 351 tcx.mk_fn_def(def_id.to_def_id(), substs)
74b04a01
XL
352 }
353 ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => {
354 let def = tcx.adt_def(def_id);
353b0b11 355 let substs = InternalSubsts::identity_for_item(tcx, def_id);
74b04a01
XL
356 tcx.mk_adt(def, substs)
357 }
a2a8927a 358 ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
064997fb 359 find_opaque_ty_constraints_for_tait(tcx, def_id)
74b04a01
XL
360 }
361 // Opaque types desugared from `impl Trait`.
f2b60f7d
FG
362 ItemKind::OpaqueTy(OpaqueTy {
363 origin:
364 hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner),
365 in_trait,
366 ..
367 }) => {
353b0b11
FG
368 if in_trait && !tcx.impl_defaultness(owner).has_value() {
369 span_bug!(
370 tcx.def_span(def_id),
371 "tried to get type of this RPITIT with no definition"
372 );
f2b60f7d 373 }
2b03887a 374 find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
74b04a01
XL
375 }
376 ItemKind::Trait(..)
377 | ItemKind::TraitAlias(..)
94222f64 378 | ItemKind::Macro(..)
74b04a01 379 | ItemKind::Mod(..)
fc512014 380 | ItemKind::ForeignMod { .. }
74b04a01
XL
381 | ItemKind::GlobalAsm(..)
382 | ItemKind::ExternCrate(..)
383 | ItemKind::Use(..) => {
384 span_bug!(
385 item.span,
386 "compute_type_of_item: unexpected item type: {:?}",
387 item.kind
388 );
389 }
390 }
391 }
392
393 Node::ForeignItem(foreign_item) => match foreign_item.kind {
394 ForeignItemKind::Fn(..) => {
353b0b11 395 let substs = InternalSubsts::identity_for_item(tcx, def_id);
3dfed10e 396 tcx.mk_fn_def(def_id.to_def_id(), substs)
74b04a01 397 }
c295e0f8 398 ForeignItemKind::Static(t, _) => icx.to_ty(t),
3dfed10e 399 ForeignItemKind::Type => tcx.mk_foreign(def_id.to_def_id()),
74b04a01
XL
400 },
401
9c376795 402 Node::Ctor(def) | Node::Variant(Variant { data: def, .. }) => match def {
74b04a01 403 VariantData::Unit(..) | VariantData::Struct(..) => {
9ffffee4 404 tcx.type_of(tcx.hir().get_parent_item(hir_id)).subst_identity()
74b04a01
XL
405 }
406 VariantData::Tuple(..) => {
353b0b11 407 let substs = InternalSubsts::identity_for_item(tcx, def_id);
3dfed10e 408 tcx.mk_fn_def(def_id.to_def_id(), substs)
74b04a01
XL
409 }
410 },
411
c295e0f8 412 Node::Field(field) => icx.to_ty(field.ty),
74b04a01 413
f2b60f7d
FG
414 Node::Expr(&Expr { kind: ExprKind::Closure { .. }, .. }) => {
415 tcx.typeck(def_id).node_type(hir_id)
416 }
74b04a01 417
94222f64
XL
418 Node::AnonConst(_) if let Some(param) = tcx.opt_const_param_of(def_id) => {
419 // We defer to `type_of` of the corresponding parameter
420 // for generic arguments.
9ffffee4 421 tcx.type_of(param).subst_identity()
94222f64 422 }
3dfed10e 423
94222f64 424 Node::AnonConst(_) => {
9c376795 425 let parent_node = tcx.hir().get_parent(hir_id);
74b04a01 426 match parent_node {
9c376795
FG
427 Node::Ty(Ty { kind: TyKind::Array(_, constant), .. })
428 | Node::Expr(Expr { kind: ExprKind::Repeat(_, constant), .. })
a2a8927a 429 if constant.hir_id() == hir_id =>
74b04a01
XL
430 {
431 tcx.types.usize
432 }
9c376795 433 Node::Ty(Ty { kind: TyKind::Typeof(e), .. }) if e.hir_id == hir_id => {
cdc7bbd5
XL
434 tcx.typeck(def_id).node_type(e.hir_id)
435 }
74b04a01 436
9c376795 437 Node::Expr(Expr { kind: ExprKind::ConstBlock(anon_const), .. })
29967ef6
XL
438 if anon_const.hir_id == hir_id =>
439 {
353b0b11 440 let substs = InternalSubsts::identity_for_item(tcx, def_id);
3c0e092e 441 substs.as_inline_const().ty()
29967ef6
XL
442 }
443
17df50a5
XL
444 Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
445 | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
446 if asm.operands.iter().any(|(op, _op_sp)| match op {
04454e1e 447 hir::InlineAsmOperand::Const { anon_const }
f2b60f7d
FG
448 | hir::InlineAsmOperand::SymFn { anon_const } => {
449 anon_const.hir_id == hir_id
450 }
cdc7bbd5
XL
451 _ => false,
452 }) =>
453 {
454 tcx.typeck(def_id).node_type(hir_id)
455 }
456
9c376795 457 Node::Variant(Variant { disr_expr: Some(e), .. }) if e.hir_id == hir_id => {
f2b60f7d
FG
458 tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx)
459 }
460
353b0b11
FG
461 Node::TypeBinding(TypeBinding {
462 hir_id: binding_id,
463 kind: TypeBindingKind::Equality { term: Term::Const(e) },
464 ident,
465 ..
466 }) if let Node::TraitRef(trait_ref) = tcx.hir().get_parent(*binding_id)
f2b60f7d
FG
467 && e.hir_id == hir_id =>
468 {
469 let Some(trait_def_id) = trait_ref.trait_def_id() else {
9ffffee4 470 return ty::EarlyBinder(tcx.ty_error_with_message(DUMMY_SP, "Could not find trait"));
f2b60f7d
FG
471 };
472 let assoc_items = tcx.associated_items(trait_def_id);
473 let assoc_item = assoc_items.find_by_name_and_kind(
474 tcx,
9c376795 475 *ident,
f2b60f7d
FG
476 ty::AssocKind::Const,
477 def_id.to_def_id(),
478 );
479 if let Some(assoc_item) = assoc_item {
353b0b11
FG
480 tcx.type_of(assoc_item.def_id)
481 .no_bound_vars()
482 .expect("const parameter types cannot be generic")
f2b60f7d
FG
483 } else {
484 // FIXME(associated_const_equality): add a useful error message here.
485 tcx.ty_error_with_message(
486 DUMMY_SP,
487 "Could not find associated const on trait",
488 )
489 }
490 }
74b04a01 491
353b0b11
FG
492 Node::TypeBinding(TypeBinding {
493 hir_id: binding_id,
494 gen_args,
495 kind,
496 ident,
497 ..
498 }) if let Node::TraitRef(trait_ref) = tcx.hir().get_parent(*binding_id)
f2b60f7d
FG
499 && let Some((idx, _)) =
500 gen_args.args.iter().enumerate().find(|(_, arg)| {
501 if let GenericArg::Const(ct) = arg {
502 ct.value.hir_id == hir_id
503 } else {
504 false
505 }
506 }) =>
5099ac24 507 {
f2b60f7d 508 let Some(trait_def_id) = trait_ref.trait_def_id() else {
9ffffee4 509 return ty::EarlyBinder(tcx.ty_error_with_message(DUMMY_SP, "Could not find trait"));
f2b60f7d
FG
510 };
511 let assoc_items = tcx.associated_items(trait_def_id);
512 let assoc_item = assoc_items.find_by_name_and_kind(
513 tcx,
9c376795 514 *ident,
f2b60f7d
FG
515 match kind {
516 // I think `<A: T>` type bindings requires that `A` is a type
517 TypeBindingKind::Constraint { .. }
518 | TypeBindingKind::Equality { term: Term::Ty(..) } => {
519 ty::AssocKind::Type
520 }
521 TypeBindingKind::Equality { term: Term::Const(..) } => {
522 ty::AssocKind::Const
523 }
524 },
525 def_id.to_def_id(),
526 );
353b0b11
FG
527 if let Some(assoc_item) = assoc_item
528 && let param = &tcx.generics_of(assoc_item.def_id).params[idx]
529 && matches!(param.kind, ty::GenericParamDefKind::Const { .. })
2b03887a 530 {
353b0b11
FG
531 tcx.type_of(param.def_id)
532 .no_bound_vars()
533 .expect("const parameter types cannot be generic")
f2b60f7d
FG
534 } else {
535 // FIXME(associated_const_equality): add a useful error message here.
536 tcx.ty_error_with_message(
537 DUMMY_SP,
353b0b11 538 "Could not find const param on associated item",
f2b60f7d
FG
539 )
540 }
5099ac24
FG
541 }
542
cdc7bbd5 543 Node::GenericParam(&GenericParam {
487cf647 544 def_id: param_def_id,
cdc7bbd5
XL
545 kind: GenericParamKind::Const { default: Some(ct), .. },
546 ..
9ffffee4 547 }) if ct.hir_id == hir_id => tcx.type_of(param_def_id).subst_identity(),
cdc7bbd5 548
f2b60f7d 549 x => tcx.ty_error_with_message(
f035d41b 550 DUMMY_SP,
5099ac24 551 &format!("unexpected const parent in type_of(): {x:?}"),
f035d41b 552 ),
74b04a01
XL
553 }
554 }
555
556 Node::GenericParam(param) => match &param.kind {
3dfed10e
XL
557 GenericParamKind::Type { default: Some(ty), .. }
558 | GenericParamKind::Const { ty, .. } => icx.to_ty(ty),
74b04a01
XL
559 x => bug!("unexpected non-type Node::GenericParam: {:?}", x),
560 },
561
562 x => {
136023e0 563 bug!("unexpected sort of node in type_of(): {:?}", x);
74b04a01 564 }
9ffffee4
FG
565 };
566 ty::EarlyBinder(output)
74b04a01
XL
567}
568
136023e0 569#[instrument(skip(tcx), level = "debug")]
c295e0f8
XL
570/// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions
571/// laid for "higher-order pattern unification".
572/// This ensures that inference is tractable.
573/// In particular, definitions of opaque types can only use other generics as arguments,
574/// and they cannot repeat an argument. Example:
575///
04454e1e 576/// ```ignore (illustrative)
c295e0f8
XL
577/// type Foo<A, B> = impl Bar<A, B>;
578///
579/// // Okay -- `Foo` is applied to two distinct, generic types.
580/// fn a<T, U>() -> Foo<T, U> { .. }
581///
582/// // Not okay -- `Foo` is applied to `T` twice.
583/// fn b<T>() -> Foo<T, T> { .. }
584///
585/// // Not okay -- `Foo` is applied to a non-generic type.
586/// fn b<T>() -> Foo<T, u32> { .. }
587/// ```
588///
064997fb 589fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
74b04a01
XL
590 use rustc_hir::{Expr, ImplItem, Item, TraitItem};
591
74b04a01
XL
592 struct ConstraintLocator<'tcx> {
593 tcx: TyCtxt<'tcx>,
136023e0
XL
594
595 /// def_id of the opaque type whose defining uses are being checked
064997fb 596 def_id: LocalDefId,
136023e0
XL
597
598 /// as we walk the defining uses, we are checking that all of them
599 /// define the same hidden type. This variable is set to `Some`
600 /// with the first type that we find, and then later types are
601 /// checked against it (we also carry the span of that first
602 /// type).
5e7ed085 603 found: Option<ty::OpaqueHiddenType<'tcx>>,
2b03887a
FG
604
605 /// In the presence of dead code, typeck may figure out a hidden type
353b0b11 606 /// while borrowck will not. We collect these cases here and check at
2b03887a
FG
607 /// the end that we actually found a type that matches (modulo regions).
608 typeck_types: Vec<ty::OpaqueHiddenType<'tcx>>,
74b04a01
XL
609 }
610
611 impl ConstraintLocator<'_> {
136023e0 612 #[instrument(skip(self), level = "debug")]
064997fb 613 fn check(&mut self, item_def_id: LocalDefId) {
74b04a01 614 // Don't try to check items that cannot possibly constrain the type.
064997fb 615 if !self.tcx.has_typeck_results(item_def_id) {
136023e0 616 debug!("no constraint: no typeck results");
74b04a01
XL
617 return;
618 }
619 // Calling `mir_borrowck` can lead to cycle errors through
620 // const-checking, avoid calling it if we don't have to.
5e7ed085
FG
621 // ```rust
622 // type Foo = impl Fn() -> usize; // when computing type for this
623 // const fn bar() -> Foo {
624 // || 0usize
625 // }
626 // const BAZR: Foo = bar(); // we would mir-borrowck this, causing cycles
627 // // because we again need to reveal `Foo` so we can check whether the
628 // // constant does not contain interior mutability.
629 // ```
064997fb 630 let tables = self.tcx.typeck(item_def_id);
9ffffee4
FG
631 if let Some(guar) = tables.tainted_by_errors {
632 self.found =
633 Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: self.tcx.ty_error(guar) });
5e7ed085
FG
634 return;
635 }
2b03887a 636 let Some(&typeck_hidden_ty) = tables.concrete_opaque_types.get(&self.def_id) else {
136023e0 637 debug!("no constraints in typeck results");
74b04a01 638 return;
2b03887a
FG
639 };
640 if self.typeck_types.iter().all(|prev| prev.ty != typeck_hidden_ty.ty) {
641 self.typeck_types.push(typeck_hidden_ty);
74b04a01 642 }
2b03887a 643
74b04a01 644 // Use borrowck to get the type with unerased regions.
064997fb 645 let concrete_opaque_types = &self.tcx.mir_borrowck(item_def_id).concrete_opaque_types;
136023e0 646 debug!(?concrete_opaque_types);
064997fb 647 if let Some(&concrete_type) = concrete_opaque_types.get(&self.def_id) {
04454e1e 648 debug!(?concrete_type, "found constraint");
2b03887a
FG
649 if let Some(prev) = &mut self.found {
650 if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() {
9ffffee4
FG
651 let guar = prev.report_mismatch(&concrete_type, self.tcx);
652 prev.ty = self.tcx.ty_error(guar);
74b04a01
XL
653 }
654 } else {
5e7ed085 655 self.found = Some(concrete_type);
74b04a01 656 }
74b04a01
XL
657 }
658 }
659 }
660
661 impl<'tcx> intravisit::Visitor<'tcx> for ConstraintLocator<'tcx> {
5099ac24 662 type NestedFilter = nested_filter::All;
74b04a01 663
5099ac24
FG
664 fn nested_visit_map(&mut self) -> Self::Map {
665 self.tcx.hir()
74b04a01
XL
666 }
667 fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
487cf647
FG
668 if let hir::ExprKind::Closure(closure) = ex.kind {
669 self.check(closure.def_id);
74b04a01
XL
670 }
671 intravisit::walk_expr(self, ex);
672 }
673 fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
2b03887a 674 trace!(?it.owner_id);
74b04a01 675 // The opaque type itself or its children are not within its reveal scope.
2b03887a
FG
676 if it.owner_id.def_id != self.def_id {
677 self.check(it.owner_id.def_id);
74b04a01
XL
678 intravisit::walk_item(self, it);
679 }
680 }
681 fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
2b03887a 682 trace!(?it.owner_id);
74b04a01 683 // The opaque type itself or its children are not within its reveal scope.
2b03887a
FG
684 if it.owner_id.def_id != self.def_id {
685 self.check(it.owner_id.def_id);
74b04a01
XL
686 intravisit::walk_impl_item(self, it);
687 }
688 }
689 fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
2b03887a
FG
690 trace!(?it.owner_id);
691 self.check(it.owner_id.def_id);
74b04a01
XL
692 intravisit::walk_trait_item(self, it);
693 }
694 }
695
3dfed10e 696 let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
74b04a01 697 let scope = tcx.hir().get_defining_scope(hir_id);
9c376795 698 let mut locator = ConstraintLocator { def_id, tcx, found: None, typeck_types: vec![] };
74b04a01 699
5e7ed085 700 debug!(?scope);
74b04a01
XL
701
702 if scope == hir::CRATE_HIR_ID {
c295e0f8 703 tcx.hir().walk_toplevel_module(&mut locator);
74b04a01 704 } else {
5e7ed085 705 trace!("scope={:#?}", tcx.hir().get(scope));
74b04a01
XL
706 match tcx.hir().get(scope) {
707 // We explicitly call `visit_*` methods, instead of using `intravisit::walk_*` methods
708 // This allows our visitor to process the defining item itself, causing
709 // it to pick up any 'sibling' defining uses.
710 //
711 // For example, this code:
712 // ```
713 // fn foo() {
714 // type Blah = impl Debug;
715 // let my_closure = || -> Blah { true };
716 // }
717 // ```
718 //
719 // requires us to explicitly process `foo()` in order
720 // to notice the defining usage of `Blah`.
c295e0f8
XL
721 Node::Item(it) => locator.visit_item(it),
722 Node::ImplItem(it) => locator.visit_impl_item(it),
723 Node::TraitItem(it) => locator.visit_trait_item(it),
74b04a01
XL
724 other => bug!("{:?} is not a valid scope for an opaque type item", other),
725 }
726 }
727
2b03887a 728 let Some(hidden) = locator.found else {
487cf647 729 let reported = tcx.sess.emit_err(UnconstrainedOpaqueType {
2b03887a
FG
730 span: tcx.def_span(def_id),
731 name: tcx.item_name(tcx.local_parent(def_id).to_def_id()),
732 what: match tcx.hir().get(scope) {
733 _ if scope == hir::CRATE_HIR_ID => "module",
734 Node::Item(hir::Item { kind: hir::ItemKind::Mod(_), .. }) => "module",
735 Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }) => "impl",
736 _ => "item",
737 },
738 });
9ffffee4 739 return tcx.ty_error(reported);
2b03887a
FG
740 };
741
742 // Only check against typeck if we didn't already error
743 if !hidden.ty.references_error() {
744 for concrete_type in locator.typeck_types {
745 if tcx.erase_regions(concrete_type.ty) != tcx.erase_regions(hidden.ty)
746 && !(concrete_type, hidden).references_error()
747 {
748 hidden.report_mismatch(&concrete_type, tcx);
749 }
74b04a01
XL
750 }
751 }
2b03887a
FG
752
753 hidden.ty
74b04a01
XL
754}
755
064997fb
FG
756fn find_opaque_ty_constraints_for_rpit(
757 tcx: TyCtxt<'_>,
758 def_id: LocalDefId,
759 owner_def_id: LocalDefId,
760) -> Ty<'_> {
761 use rustc_hir::{Expr, ImplItem, Item, TraitItem};
762
763 struct ConstraintChecker<'tcx> {
764 tcx: TyCtxt<'tcx>,
765
766 /// def_id of the opaque type whose defining uses are being checked
767 def_id: LocalDefId,
768
769 found: ty::OpaqueHiddenType<'tcx>,
770 }
771
772 impl ConstraintChecker<'_> {
773 #[instrument(skip(self), level = "debug")]
774 fn check(&self, def_id: LocalDefId) {
775 // Use borrowck to get the type with unerased regions.
776 let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types;
777 debug!(?concrete_opaque_types);
353b0b11 778 for (&def_id, &concrete_type) in concrete_opaque_types {
064997fb
FG
779 if def_id != self.def_id {
780 // Ignore constraints for other opaque types.
781 continue;
782 }
783
784 debug!(?concrete_type, "found constraint");
785
786 if concrete_type.ty != self.found.ty
787 && !(concrete_type, self.found).references_error()
788 {
789 self.found.report_mismatch(&concrete_type, self.tcx);
790 }
791 }
792 }
793 }
794
795 impl<'tcx> intravisit::Visitor<'tcx> for ConstraintChecker<'tcx> {
796 type NestedFilter = nested_filter::OnlyBodies;
797
798 fn nested_visit_map(&mut self) -> Self::Map {
799 self.tcx.hir()
800 }
801 fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
487cf647
FG
802 if let hir::ExprKind::Closure(closure) = ex.kind {
803 self.check(closure.def_id);
064997fb
FG
804 }
805 intravisit::walk_expr(self, ex);
806 }
807 fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
2b03887a 808 trace!(?it.owner_id);
064997fb 809 // The opaque type itself or its children are not within its reveal scope.
2b03887a
FG
810 if it.owner_id.def_id != self.def_id {
811 self.check(it.owner_id.def_id);
064997fb
FG
812 intravisit::walk_item(self, it);
813 }
814 }
815 fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
2b03887a 816 trace!(?it.owner_id);
064997fb 817 // The opaque type itself or its children are not within its reveal scope.
2b03887a
FG
818 if it.owner_id.def_id != self.def_id {
819 self.check(it.owner_id.def_id);
064997fb
FG
820 intravisit::walk_impl_item(self, it);
821 }
822 }
823 fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
2b03887a
FG
824 trace!(?it.owner_id);
825 self.check(it.owner_id.def_id);
064997fb
FG
826 intravisit::walk_trait_item(self, it);
827 }
828 }
829
830 let concrete = tcx.mir_borrowck(owner_def_id).concrete_opaque_types.get(&def_id).copied();
831
832 if let Some(concrete) = concrete {
833 let scope = tcx.hir().local_def_id_to_hir_id(owner_def_id);
834 debug!(?scope);
9c376795 835 let mut locator = ConstraintChecker { def_id, tcx, found: concrete };
064997fb
FG
836
837 match tcx.hir().get(scope) {
838 Node::Item(it) => intravisit::walk_item(&mut locator, it),
839 Node::ImplItem(it) => intravisit::walk_impl_item(&mut locator, it),
840 Node::TraitItem(it) => intravisit::walk_trait_item(&mut locator, it),
841 other => bug!("{:?} is not a valid scope for an opaque type item", other),
842 }
843 }
844
845 concrete.map(|concrete| concrete.ty).unwrap_or_else(|| {
846 let table = tcx.typeck(owner_def_id);
9ffffee4 847 if let Some(guar) = table.tainted_by_errors {
064997fb
FG
848 // Some error in the
849 // owner fn prevented us from populating
850 // the `concrete_opaque_types` table.
9ffffee4 851 tcx.ty_error(guar)
064997fb 852 } else {
2b03887a
FG
853 table.concrete_opaque_types.get(&def_id).map(|ty| ty.ty).unwrap_or_else(|| {
854 // We failed to resolve the opaque type or it
855 // resolves to itself. We interpret this as the
856 // no values of the hidden type ever being constructed,
857 // so we can just make the hidden type be `!`.
858 // For backwards compatibility reasons, we fall back to
859 // `()` until we the diverging default is changed.
860 tcx.mk_diverging_default()
861 })
064997fb
FG
862 }
863 })
864}
865
136023e0
XL
866fn infer_placeholder_type<'a>(
867 tcx: TyCtxt<'a>,
f9f354fc 868 def_id: LocalDefId,
74b04a01
XL
869 body_id: hir::BodyId,
870 span: Span,
871 item_ident: Ident,
136023e0
XL
872 kind: &'static str,
873) -> Ty<'a> {
3dfed10e 874 let ty = tcx.diagnostic_only_typeck(def_id).node_type(body_id.hir_id);
74b04a01
XL
875
876 // If this came from a free `const` or `static mut?` item,
877 // then the user may have written e.g. `const A = 42;`.
878 // In this case, the parser has stashed a diagnostic for
879 // us to improve in typeck so we do that now.
880 match tcx.sess.diagnostic().steal_diagnostic(span, StashKey::ItemNoType) {
881 Some(mut err) => {
dc3f5686 882 if !ty.references_error() {
f2b60f7d
FG
883 // Only suggest adding `:` if it was missing (and suggested by parsing diagnostic)
884 let colon = if span == item_ident.span.shrink_to_hi() { ":" } else { "" };
885
dc3f5686
XL
886 // The parser provided a sub-optimal `HasPlaceholders` suggestion for the type.
887 // We are typeck and have the real type, so remove that and suggest the actual type.
5099ac24
FG
888 // FIXME(eddyb) this looks like it should be functionality on `Diagnostic`.
889 if let Ok(suggestions) = &mut err.suggestions {
890 suggestions.clear();
891 }
dc3f5686 892
9ffffee4 893 if let Some(ty) = ty.make_suggestable(tcx, false) {
dc3f5686
XL
894 err.span_suggestion(
895 span,
896 &format!("provide a type for the {item}", item = kind),
9ffffee4 897 format!("{colon} {ty}"),
dc3f5686
XL
898 Applicability::MachineApplicable,
899 );
900 } else {
9c376795 901 with_forced_trimmed_paths!(err.span_note(
dc3f5686 902 tcx.hir().body(body_id).value.span,
9c376795
FG
903 &format!("however, the inferred type `{ty}` cannot be named"),
904 ));
dc3f5686 905 }
136023e0
XL
906 }
907
dc3f5686 908 err.emit();
74b04a01
XL
909 }
910 None => {
5099ac24 911 let mut diag = bad_placeholder(tcx, vec![span], kind);
6a06907d
XL
912
913 if !ty.references_error() {
9ffffee4 914 if let Some(ty) = ty.make_suggestable(tcx, false) {
136023e0
XL
915 diag.span_suggestion(
916 span,
917 "replace with the correct type",
9ffffee4
FG
918 ty,
919 Applicability::MachineApplicable,
136023e0
XL
920 );
921 } else {
9c376795 922 with_forced_trimmed_paths!(diag.span_note(
136023e0 923 tcx.hir().body(body_id).value.span,
9c376795
FG
924 &format!("however, the inferred type `{ty}` cannot be named"),
925 ));
136023e0 926 }
74b04a01 927 }
6a06907d 928
74b04a01
XL
929 diag.emit();
930 }
931 }
932
ba9703b0 933 // Typeck doesn't expect erased regions to be returned from `type_of`.
064997fb 934 tcx.fold_regions(ty, |r, _| match *r {
ba9703b0
XL
935 ty::ReErased => tcx.lifetimes.re_static,
936 _ => r,
937 })
74b04a01
XL
938}
939
6a06907d
XL
940fn check_feature_inherent_assoc_ty(tcx: TyCtxt<'_>, span: Span) {
941 if !tcx.features().inherent_associated_types {
942 use rustc_session::parse::feature_err;
943 use rustc_span::symbol::sym;
944 feature_err(
945 &tcx.sess.parse_sess,
946 sym::inherent_associated_types,
947 span,
948 "inherent associated types are unstable",
949 )
950 .emit();
951 }
74b04a01 952}