rustc_hir_analysis/collect/
type_of.rs1use core::ops::ControlFlow;
2
3use rustc_errors::{Applicability, StashKey, Suggestions};
4use rustc_hir::def_id::{DefId, LocalDefId};
5use rustc_hir::intravisit::VisitorExt;
6use rustc_hir::{self as hir, AmbigArg, HirId};
7use rustc_middle::query::plumbing::CyclePlaceholder;
8use rustc_middle::ty::print::with_forced_trimmed_paths;
9use rustc_middle::ty::util::IntTypeExt;
10use rustc_middle::ty::{
11 self, DefiningScopeKind, IsSuggestable, Ty, TyCtxt, TypeVisitableExt, fold_regions,
12};
13use rustc_middle::{bug, span_bug};
14use rustc_span::{DUMMY_SP, Ident, Span};
15
16use super::{HirPlaceholderCollector, ItemCtxt, bad_placeholder};
17use crate::check::wfcheck::check_static_item;
18use crate::errors::TypeofReservedKeywordUsed;
19use crate::hir_ty_lowering::HirTyLowerer;
20
21mod opaque;
22
23fn anon_const_type_of<'tcx>(icx: &ItemCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
24 use hir::*;
25 use rustc_middle::ty::Ty;
26 let tcx = icx.tcx;
27 let hir_id = tcx.local_def_id_to_hir_id(def_id);
28
29 let node = tcx.hir_node(hir_id);
30 let Node::AnonConst(&AnonConst { span, .. }) = node else {
31 span_bug!(
32 tcx.def_span(def_id),
33 "expected anon const in `anon_const_type_of`, got {node:?}"
34 );
35 };
36
37 let parent_node_id = tcx.parent_hir_id(hir_id);
38 let parent_node = tcx.hir_node(parent_node_id);
39
40 match parent_node {
41 Node::ConstArg(&ConstArg {
43 hir_id: arg_hir_id,
44 kind: ConstArgKind::Anon(&AnonConst { hir_id: anon_hir_id, .. }),
45 ..
46 }) if anon_hir_id == hir_id => const_arg_anon_type_of(icx, arg_hir_id, span),
47
48 Node::Variant(Variant { disr_expr: Some(e), .. }) if e.hir_id == hir_id => {
49 tcx.adt_def(tcx.hir_get_parent_item(hir_id)).repr().discr_type().to_ty(tcx)
50 }
51 Node::Ty(&hir::Ty { kind: TyKind::Typeof(ref e), span, .. }) if e.hir_id == hir_id => {
54 let ty = tcx.typeck(def_id).node_type(tcx.local_def_id_to_hir_id(def_id));
55 let ty = fold_regions(tcx, ty, |r, _| {
56 if r.is_erased() { ty::Region::new_error_misc(tcx) } else { r }
57 });
58 let (ty, opt_sugg) = if let Some(ty) = ty.make_suggestable(tcx, false, None) {
59 (ty, Some((span, Applicability::MachineApplicable)))
60 } else {
61 (ty, None)
62 };
63 tcx.dcx().emit_err(TypeofReservedKeywordUsed { span, ty, opt_sugg });
64 return ty;
65 }
66
67 Node::Field(&hir::FieldDef { default: Some(c), def_id: field_def_id, .. })
68 if c.hir_id == hir_id =>
69 {
70 tcx.type_of(field_def_id).instantiate_identity()
71 }
72
73 _ => Ty::new_error_with_message(
74 tcx,
75 span,
76 format!("unexpected anon const parent in type_of(): {parent_node:?}"),
77 ),
78 }
79}
80
81fn const_arg_anon_type_of<'tcx>(icx: &ItemCtxt<'tcx>, arg_hir_id: HirId, span: Span) -> Ty<'tcx> {
82 use hir::*;
83 use rustc_middle::ty::Ty;
84
85 let tcx = icx.tcx;
86
87 match tcx.parent_hir_node(arg_hir_id) {
88 Node::Ty(&hir::Ty { kind: TyKind::Array(_, ref constant), .. })
91 | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
92 if constant.hir_id == arg_hir_id =>
93 {
94 tcx.types.usize
95 }
96
97 Node::TyPat(pat) => {
98 let node = match tcx.parent_hir_node(pat.hir_id) {
99 Node::TyPat(p) => tcx.parent_hir_node(p.hir_id),
101 other => other,
102 };
103 let hir::TyKind::Pat(ty, _) = node.expect_ty().kind else { bug!() };
104 icx.lower_ty(ty)
105 }
106
107 _ => Ty::new_error_with_message(
110 tcx,
111 span,
112 "`type_of` called on const argument's anon const before the const argument was lowered",
113 ),
114 }
115}
116
117pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, Ty<'_>> {
118 use rustc_hir::*;
119 use rustc_middle::ty::Ty;
120
121 match tcx.opt_rpitit_info(def_id.to_def_id()) {
125 Some(ty::ImplTraitInTraitData::Impl { fn_def_id }) => {
126 match tcx.collect_return_position_impl_trait_in_trait_tys(fn_def_id) {
127 Ok(map) => {
128 let trait_item_def_id = tcx.trait_item_of(def_id).unwrap();
129 return map[&trait_item_def_id];
130 }
131 Err(_) => {
132 return ty::EarlyBinder::bind(Ty::new_error_with_message(
133 tcx,
134 DUMMY_SP,
135 "Could not collect return position impl trait in trait tys",
136 ));
137 }
138 }
139 }
140 Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => {
142 return ty::EarlyBinder::bind(Ty::new_opaque(
143 tcx,
144 opaque_def_id,
145 ty::GenericArgs::identity_for_item(tcx, opaque_def_id),
146 ));
147 }
148 None => {}
149 }
150
151 let hir_id = tcx.local_def_id_to_hir_id(def_id);
152
153 let icx = ItemCtxt::new(tcx, def_id);
154
155 let output = match tcx.hir_node(hir_id) {
156 Node::TraitItem(item) => match item.kind {
157 TraitItemKind::Fn(..) => {
158 let args = ty::GenericArgs::identity_for_item(tcx, def_id);
159 Ty::new_fn_def(tcx, def_id.to_def_id(), args)
160 }
161 TraitItemKind::Const(ty, body_id) => body_id
162 .and_then(|body_id| {
163 ty.is_suggestable_infer_ty().then(|| {
164 infer_placeholder_type(
165 icx.lowerer(),
166 def_id,
167 body_id,
168 ty.span,
169 item.ident,
170 "associated constant",
171 )
172 })
173 })
174 .unwrap_or_else(|| icx.lower_ty(ty)),
175 TraitItemKind::Type(_, Some(ty)) => icx.lower_ty(ty),
176 TraitItemKind::Type(_, None) => {
177 span_bug!(item.span, "associated type missing default");
178 }
179 },
180
181 Node::ImplItem(item) => match item.kind {
182 ImplItemKind::Fn(..) => {
183 let args = ty::GenericArgs::identity_for_item(tcx, def_id);
184 Ty::new_fn_def(tcx, def_id.to_def_id(), args)
185 }
186 ImplItemKind::Const(ty, body_id) => {
187 if ty.is_suggestable_infer_ty() {
188 infer_placeholder_type(
189 icx.lowerer(),
190 def_id,
191 body_id,
192 ty.span,
193 item.ident,
194 "associated constant",
195 )
196 } else {
197 icx.lower_ty(ty)
198 }
199 }
200 ImplItemKind::Type(ty) => {
201 if let ImplItemImplKind::Inherent { .. } = item.impl_kind {
202 check_feature_inherent_assoc_ty(tcx, item.span);
203 }
204
205 icx.lower_ty(ty)
206 }
207 },
208
209 Node::Item(item) => match item.kind {
210 ItemKind::Static(_, ident, ty, body_id) => {
211 if ty.is_suggestable_infer_ty() {
212 infer_placeholder_type(
213 icx.lowerer(),
214 def_id,
215 body_id,
216 ty.span,
217 ident,
218 "static variable",
219 )
220 } else {
221 let ty = icx.lower_ty(ty);
222 match check_static_item(tcx, def_id, ty, false) {
227 Ok(()) => ty,
228 Err(guar) => Ty::new_error(tcx, guar),
229 }
230 }
231 }
232 ItemKind::Const(ident, _, ty, body_id) => {
233 if ty.is_suggestable_infer_ty() {
234 infer_placeholder_type(
235 icx.lowerer(),
236 def_id,
237 body_id,
238 ty.span,
239 ident,
240 "constant",
241 )
242 } else {
243 icx.lower_ty(ty)
244 }
245 }
246 ItemKind::TyAlias(_, _, self_ty) => icx.lower_ty(self_ty),
247 ItemKind::Impl(hir::Impl { self_ty, .. }) => match self_ty.find_self_aliases() {
248 spans if spans.len() > 0 => {
249 let guar = tcx
250 .dcx()
251 .emit_err(crate::errors::SelfInImplSelf { span: spans.into(), note: () });
252 Ty::new_error(tcx, guar)
253 }
254 _ => icx.lower_ty(self_ty),
255 },
256 ItemKind::Fn { .. } => {
257 let args = ty::GenericArgs::identity_for_item(tcx, def_id);
258 Ty::new_fn_def(tcx, def_id.to_def_id(), args)
259 }
260 ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => {
261 let def = tcx.adt_def(def_id);
262 let args = ty::GenericArgs::identity_for_item(tcx, def_id);
263 Ty::new_adt(tcx, def, args)
264 }
265 ItemKind::GlobalAsm { .. } => tcx.typeck(def_id).node_type(hir_id),
266 ItemKind::Trait(..)
267 | ItemKind::TraitAlias(..)
268 | ItemKind::Macro(..)
269 | ItemKind::Mod(..)
270 | ItemKind::ForeignMod { .. }
271 | ItemKind::ExternCrate(..)
272 | ItemKind::Use(..) => {
273 span_bug!(item.span, "compute_type_of_item: unexpected item type: {:?}", item.kind);
274 }
275 },
276
277 Node::OpaqueTy(..) => tcx.type_of_opaque(def_id).map_or_else(
278 |CyclePlaceholder(guar)| Ty::new_error(tcx, guar),
279 |ty| ty.instantiate_identity(),
280 ),
281
282 Node::ForeignItem(foreign_item) => match foreign_item.kind {
283 ForeignItemKind::Fn(..) => {
284 let args = ty::GenericArgs::identity_for_item(tcx, def_id);
285 Ty::new_fn_def(tcx, def_id.to_def_id(), args)
286 }
287 ForeignItemKind::Static(ty, _, _) => {
288 let ty = icx.lower_ty(ty);
289 match check_static_item(tcx, def_id, ty, false) {
294 Ok(()) => ty,
295 Err(guar) => Ty::new_error(tcx, guar),
296 }
297 }
298 ForeignItemKind::Type => Ty::new_foreign(tcx, def_id.to_def_id()),
299 },
300
301 Node::Ctor(def) | Node::Variant(Variant { data: def, .. }) => match def {
302 VariantData::Unit(..) | VariantData::Struct { .. } => {
303 tcx.type_of(tcx.hir_get_parent_item(hir_id)).instantiate_identity()
304 }
305 VariantData::Tuple(_, _, ctor) => {
306 let args = ty::GenericArgs::identity_for_item(tcx, def_id);
307 Ty::new_fn_def(tcx, ctor.to_def_id(), args)
308 }
309 },
310
311 Node::Field(field) => icx.lower_ty(field.ty),
312
313 Node::Expr(&Expr { kind: ExprKind::Closure { .. }, .. }) => {
314 tcx.typeck(def_id).node_type(hir_id)
315 }
316
317 Node::AnonConst(_) => anon_const_type_of(&icx, def_id),
318
319 Node::ConstBlock(_) => {
320 let args = ty::GenericArgs::identity_for_item(tcx, def_id.to_def_id());
321 args.as_inline_const().ty()
322 }
323
324 Node::GenericParam(param) => match ¶m.kind {
325 GenericParamKind::Type { default: Some(ty), .. }
326 | GenericParamKind::Const { ty, .. } => icx.lower_ty(ty),
327 x => bug!("unexpected non-type Node::GenericParam: {:?}", x),
328 },
329
330 x => {
331 bug!("unexpected sort of node in type_of(): {:?}", x);
332 }
333 };
334 if let Err(e) = icx.check_tainted_by_errors()
335 && !output.references_error()
336 {
337 ty::EarlyBinder::bind(Ty::new_error(tcx, e))
338 } else {
339 ty::EarlyBinder::bind(output)
340 }
341}
342
343pub(super) fn type_of_opaque(
344 tcx: TyCtxt<'_>,
345 def_id: DefId,
346) -> Result<ty::EarlyBinder<'_, Ty<'_>>, CyclePlaceholder> {
347 if let Some(def_id) = def_id.as_local() {
348 Ok(ty::EarlyBinder::bind(match tcx.hir_node_by_def_id(def_id).expect_opaque_ty().origin {
349 hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. } => {
350 opaque::find_opaque_ty_constraints_for_tait(
351 tcx,
352 def_id,
353 DefiningScopeKind::MirBorrowck,
354 )
355 }
356 hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true, .. } => {
357 opaque::find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
358 tcx,
359 def_id,
360 DefiningScopeKind::MirBorrowck,
361 )
362 }
363 hir::OpaqueTyOrigin::FnReturn { parent: owner, in_trait_or_impl }
365 | hir::OpaqueTyOrigin::AsyncFn { parent: owner, in_trait_or_impl } => {
366 if in_trait_or_impl == Some(hir::RpitContext::Trait)
367 && !tcx.defaultness(owner).has_value()
368 {
369 span_bug!(
370 tcx.def_span(def_id),
371 "tried to get type of this RPITIT with no definition"
372 );
373 }
374 opaque::find_opaque_ty_constraints_for_rpit(
375 tcx,
376 def_id,
377 owner,
378 DefiningScopeKind::MirBorrowck,
379 )
380 }
381 }))
382 } else {
383 Ok(tcx.type_of(def_id))
386 }
387}
388
389pub(super) fn type_of_opaque_hir_typeck(
390 tcx: TyCtxt<'_>,
391 def_id: LocalDefId,
392) -> ty::EarlyBinder<'_, Ty<'_>> {
393 ty::EarlyBinder::bind(match tcx.hir_node_by_def_id(def_id).expect_opaque_ty().origin {
394 hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. } => {
395 opaque::find_opaque_ty_constraints_for_tait(tcx, def_id, DefiningScopeKind::HirTypeck)
396 }
397 hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true, .. } => {
398 opaque::find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
399 tcx,
400 def_id,
401 DefiningScopeKind::HirTypeck,
402 )
403 }
404 hir::OpaqueTyOrigin::FnReturn { parent: owner, in_trait_or_impl }
406 | hir::OpaqueTyOrigin::AsyncFn { parent: owner, in_trait_or_impl } => {
407 if in_trait_or_impl == Some(hir::RpitContext::Trait)
408 && !tcx.defaultness(owner).has_value()
409 {
410 span_bug!(
411 tcx.def_span(def_id),
412 "tried to get type of this RPITIT with no definition"
413 );
414 }
415 opaque::find_opaque_ty_constraints_for_rpit(
416 tcx,
417 def_id,
418 owner,
419 DefiningScopeKind::HirTypeck,
420 )
421 }
422 })
423}
424
425fn infer_placeholder_type<'tcx>(
426 cx: &dyn HirTyLowerer<'tcx>,
427 def_id: LocalDefId,
428 body_id: hir::BodyId,
429 span: Span,
430 item_ident: Ident,
431 kind: &'static str,
432) -> Ty<'tcx> {
433 let tcx = cx.tcx();
434 let ty = tcx.typeck(def_id).node_type(body_id.hir_id);
435
436 let guar = cx
441 .dcx()
442 .try_steal_modify_and_emit_err(span, StashKey::ItemNoType, |err| {
443 if !ty.references_error() {
444 let colon = if span == item_ident.span.shrink_to_hi() { ":" } else { "" };
446
447 if let Suggestions::Enabled(suggestions) = &mut err.suggestions {
450 suggestions.clear();
451 }
452
453 if let Some(ty) = ty.make_suggestable(tcx, false, None) {
454 err.span_suggestion(
455 span,
456 format!("provide a type for the {kind}"),
457 format!("{colon} {ty}"),
458 Applicability::MachineApplicable,
459 );
460 } else {
461 with_forced_trimmed_paths!(err.span_note(
462 tcx.hir_body(body_id).value.span,
463 format!("however, the inferred type `{ty}` cannot be named"),
464 ));
465 }
466 }
467 })
468 .unwrap_or_else(|| {
469 let mut visitor = HirPlaceholderCollector::default();
470 let node = tcx.hir_node_by_def_id(def_id);
471 if let Some(ty) = node.ty() {
472 visitor.visit_ty_unambig(ty);
473 }
474 if visitor.spans.is_empty() {
476 visitor.spans.push(span);
477 }
478 let mut diag = bad_placeholder(cx, visitor.spans, kind);
479
480 if span.is_empty() && span.from_expansion() {
486 diag.primary_message("missing type for item");
488 } else if !ty.references_error() {
489 if let Some(ty) = ty.make_suggestable(tcx, false, None) {
490 diag.span_suggestion_verbose(
491 span,
492 "replace this with a fully-specified type",
493 ty,
494 Applicability::MachineApplicable,
495 );
496 } else {
497 with_forced_trimmed_paths!(diag.span_note(
498 tcx.hir_body(body_id).value.span,
499 format!("however, the inferred type `{ty}` cannot be named"),
500 ));
501 }
502 }
503
504 diag.emit()
505 });
506 Ty::new_error(tcx, guar)
507}
508
509fn check_feature_inherent_assoc_ty(tcx: TyCtxt<'_>, span: Span) {
510 if !tcx.features().inherent_associated_types() {
511 use rustc_session::parse::feature_err;
512 use rustc_span::sym;
513 feature_err(
514 &tcx.sess,
515 sym::inherent_associated_types,
516 span,
517 "inherent associated types are unstable",
518 )
519 .emit();
520 }
521}
522
523pub(crate) fn type_alias_is_lazy<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
524 use hir::intravisit::Visitor;
525 if tcx.features().lazy_type_alias() {
526 return true;
527 }
528 struct HasTait;
529 impl<'tcx> Visitor<'tcx> for HasTait {
530 type Result = ControlFlow<()>;
531 fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result {
532 if let hir::TyKind::OpaqueDef(..) = t.kind {
533 ControlFlow::Break(())
534 } else {
535 hir::intravisit::walk_ty(self, t)
536 }
537 }
538 }
539 HasTait.visit_ty_unambig(tcx.hir_expect_item(def_id).expect_ty_alias().2).is_break()
540}