Skip to main content

rustc_hir_analysis/
lib.rs

1/*!
2
3# typeck
4
5The type checker is responsible for:
6
71. Determining the type of each expression.
82. Resolving methods and traits.
93. Guaranteeing that most type rules are met. ("Most?", you say, "why most?"
10   Well, dear reader, read on.)
11
12The main entry point is [`check_crate()`]. Type checking operates in
13several major phases:
14
151. The collect phase first passes over all items and determines their
16   type, without examining their "innards".
17
182. Variance inference then runs to compute the variance of each parameter.
19
203. Coherence checks for overlapping or orphaned impls.
21
224. Finally, the check phase then checks function bodies and so forth.
23   Within the check phase, we check each function body one at a time
24   (bodies of function expressions are checked as part of the
25   containing function). Inference is used to supply types wherever
26   they are unknown. The actual checking of a function itself has
27   several phases (check, regionck, writeback), as discussed in the
28   documentation for the [`check`] module.
29
30The type checker is defined into various submodules which are documented
31independently:
32
33- hir_ty_lowering: lowers type-system entities from the [HIR][hir] to the
34  [`rustc_middle::ty`] representation.
35
36- collect: computes the types of each top-level item and enters them into
37  the `tcx.types` table for later use.
38
39- coherence: enforces coherence rules, builds some tables.
40
41- variance: variance inference
42
43- outlives: outlives inference
44
45- check: walks over function bodies and type checks them, inferring types for
46  local variables, type parameters, etc as necessary.
47
48- infer: finds the types to use for each type variable such that
49  all subtyping and assignment constraints are met. In essence, the check
50  module specifies the constraints, and the infer module solves them.
51
52## Note
53
54This API is completely unstable and subject to change.
55
56*/
57
58// tidy-alphabetical-start
59#![feature(default_field_values)]
60#![feature(gen_blocks)]
61#![feature(iter_intersperse)]
62#![feature(never_type)]
63#![feature(option_into_flat_iter)]
64#![feature(slice_partition_dedup)]
65#![feature(try_blocks)]
66#![feature(unwrap_infallible)]
67// tidy-alphabetical-end
68
69// These are used by Clippy.
70pub mod check;
71
72pub mod autoderef;
73mod check_unused;
74mod coherence;
75mod collect;
76mod constrained_generic_params;
77pub mod delegation;
78pub mod diagnostics;
79pub mod hir_ty_lowering;
80pub mod hir_wf_check;
81mod impl_wf_check;
82mod outlives;
83mod variance;
84
85pub use diagnostics::NoVariantNamed;
86use rustc_abi::{CVariadicStatus, ExternAbi};
87use rustc_hir as hir;
88use rustc_hir::def::DefKind;
89use rustc_middle::mir::interpret::GlobalId;
90use rustc_middle::query::Providers;
91use rustc_middle::ty::{Const, Ty, TyCtxt};
92use rustc_middle::{middle, ty};
93use rustc_session::errors::feature_err;
94use rustc_span::{ErrorGuaranteed, Span};
95use rustc_trait_selection::traits;
96
97pub use crate::collect::suggest_impl_trait;
98use crate::hir_ty_lowering::HirTyLowerer;
99
100fn check_c_variadic_abi(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: ExternAbi, span: Span) {
101    if !decl.c_variadic() {
102        // Not even a variadic function.
103        return;
104    }
105
106    match abi.supports_c_variadic() {
107        CVariadicStatus::Stable => {}
108        CVariadicStatus::NotSupported => {
109            tcx.dcx()
110                .create_err(diagnostics::VariadicFunctionCompatibleConvention {
111                    span,
112                    convention: &::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}", abi))
    })format!("{abi}"),
113                })
114                .emit();
115        }
116        CVariadicStatus::Unstable { feature } => {
117            if !tcx.features().enabled(feature) {
118                feature_err(
119                    &tcx.sess,
120                    feature,
121                    span,
122                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("C-variadic functions with the {0} calling convention are unstable",
                abi))
    })format!("C-variadic functions with the {abi} calling convention are unstable"),
123                )
124                .emit();
125            }
126        }
127    }
128}
129
130/// Adds query implementations to the [Providers] vtable, see [`rustc_middle::query`]
131pub fn provide(providers: &mut Providers) {
132    collect::provide(providers);
133    coherence::provide(providers);
134    check::provide(providers);
135    *providers = Providers {
136        check_unused_traits: check_unused::check_unused_traits,
137        diagnostic_hir_wf_check: hir_wf_check::diagnostic_hir_wf_check,
138        inferred_outlives_crate: outlives::inferred_outlives_crate,
139        inferred_outlives_of: outlives::inferred_outlives_of,
140        inherit_sig_for_delegation_item: delegation::inherit_sig_for_delegation_item,
141        delegation_user_specified_args: delegation::delegation_user_specified_args,
142        enforce_impl_non_lifetime_params_are_constrained:
143            impl_wf_check::enforce_impl_non_lifetime_params_are_constrained,
144        crate_variances: variance::crate_variances,
145        variances_of: variance::variances_of,
146        ..*providers
147    };
148}
149
150pub fn check_crate(tcx: TyCtxt<'_>) {
151    let _prof_timer = tcx.sess.timer("type_check_crate");
152
153    tcx.sess.time("coherence_checking", || {
154        // When discarding query call results, use an explicit type to indicate
155        // what we are intending to discard, to help future type-based refactoring.
156        type R = Result<(), ErrorGuaranteed>;
157
158        let _: R = tcx.ensure_result().check_type_wf(());
159
160        for &trait_def_id in tcx.all_local_trait_impls(()).keys() {
161            let _: R = tcx.ensure_result().coherent_trait(trait_def_id);
162        }
163        // these queries are executed for side-effects (error reporting):
164        let _: R = tcx.ensure_result().crate_inherent_impls_validity_check(());
165        let _: R = tcx.ensure_result().crate_inherent_impls_overlap_check(());
166    });
167
168    tcx.par_hir_body_owners(|item_def_id| {
169        let def_kind = tcx.def_kind(item_def_id);
170        // Make sure we evaluate all static and (non-associated) const items, even if unused.
171        // If any of these fail to evaluate, we do not want this crate to pass compilation.
172        match def_kind {
173            DefKind::Static { .. } => {
174                tcx.ensure_ok().eval_static_initializer(item_def_id);
175                check::maybe_check_static_with_link_section(tcx, item_def_id);
176            }
177            DefKind::Const { .. }
178                if !tcx.generics_of(item_def_id).own_requires_monomorphization()
179                    && !tcx.is_type_const(item_def_id) =>
180            {
181                // FIXME(generic_const_items): Passing empty instead of identity args is fishy but
182                //                             seems to be fine for now. Revisit this!
183                let instance = ty::Instance::new_raw(item_def_id.into(), ty::GenericArgs::empty());
184                let cid = GlobalId { instance, promoted: None };
185                let typing_env = ty::TypingEnv::fully_monomorphized();
186                tcx.ensure_ok().eval_to_const_value_raw(typing_env.as_query_input(cid));
187            }
188            _ => (),
189        }
190        // Skip `AnonConst`s and type system `InlineConst`s because we feed their `type_of` in
191        // `feed_anon_const_type`.
192        // Also skip items for which typeck forwards to parent typeck.
193        if !(def_kind == DefKind::AnonConst
194            && tcx.anon_const_kind(item_def_id) != ty::AnonConstKind::NonTypeSystemInline
195            || tcx.is_typeck_child(item_def_id.to_def_id()))
196        {
197            tcx.ensure_ok().typeck(item_def_id);
198        }
199        // Ensure we generate the new `DefId` before finishing `check_crate`.
200        // Afterwards we freeze the list of `DefId`s.
201        if tcx.needs_coroutine_by_move_body_def_id(item_def_id.to_def_id()) {
202            tcx.ensure_done().coroutine_by_move_body_def_id(item_def_id);
203        }
204    });
205
206    if tcx.features().rustc_attrs() {
207        tcx.sess.time("dumping_rustc_attr_data", || {
208            outlives::dump::inferred_outlives(tcx);
209            variance::dump::variances(tcx);
210            collect::dump::generics(tcx);
211            collect::dump::opaque_hidden_types(tcx);
212            collect::dump::predicates_and_item_bounds(tcx);
213            collect::dump::def_parents(tcx);
214            collect::dump::vtables(tcx);
215        });
216    }
217
218    tcx.ensure_ok().check_unused_traits(());
219}
220
221/// Lower a [`hir::Ty`] to a [`Ty`].
222///
223/// <div class="warning">
224///
225/// This function is **quasi-deprecated**. It can cause ICEs if called inside of a body
226/// (of a function or constant) and especially if it contains inferred types (`_`).
227///
228/// It's used in rustdoc and Clippy.
229///
230/// </div>
231pub fn lower_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
232    // In case there are any projections, etc., find the "environment"
233    // def-ID that will be used to determine the traits/predicates in
234    // scope. This is derived from the enclosing item-like thing.
235    let env_def_id = tcx.hir_get_parent_item(hir_ty.hir_id);
236    collect::ItemCtxt::new(tcx, env_def_id.def_id)
237        .lowerer()
238        .lower_ty_maybe_return_type_notation(hir_ty)
239}
240
241/// This is for rustdoc.
242// FIXME(const_generics): having special methods for rustdoc in `rustc_hir_analysis` is cursed
243pub fn lower_const_arg_for_rustdoc<'tcx>(
244    tcx: TyCtxt<'tcx>,
245    hir_ct: &hir::ConstArg<'tcx>,
246    ty: Ty<'tcx>,
247) -> Const<'tcx> {
248    let env_def_id = tcx.hir_get_parent_item(hir_ct.hir_id);
249    collect::ItemCtxt::new(tcx, env_def_id.def_id).lowerer().lower_const_arg(hir_ct, ty)
250}