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