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