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