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