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