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(slice_partition_dedup)]
64#![feature(try_blocks)]
65#![feature(unwrap_infallible)]
66// tidy-alphabetical-end
67
68// These are used by Clippy.
69pub mod check;
70
71pub mod autoderef;
72mod check_unused;
73mod coherence;
74mod collect;
75mod constrained_generic_params;
76mod delegation;
77pub mod errors;
78pub mod hir_ty_lowering;
79pub mod hir_wf_check;
80mod impl_wf_check;
81mod outlives;
82mod variance;
83
84pub use errors::NoVariantNamed;
85use rustc_abi::{CVariadicStatus, ExternAbi};
86use rustc_hir as hir;
87use rustc_hir::def::DefKind;
88use rustc_hir::lints::DelayedLint;
89use rustc_lint::DecorateAttrLint;
90use rustc_middle::mir::interpret::GlobalId;
91use rustc_middle::query::Providers;
92use rustc_middle::ty::{Const, Ty, TyCtxt};
93use rustc_middle::{middle, ty};
94use rustc_session::parse::feature_err;
95use rustc_span::{ErrorGuaranteed, Span};
96use rustc_trait_selection::traits;
97
98pub use crate::collect::suggest_impl_trait;
99use crate::hir_ty_lowering::HirTyLowerer;
100
101fn check_c_variadic_abi(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: ExternAbi, span: Span) {
102    if !decl.c_variadic {
103        // Not even a variadic function.
104        return;
105    }
106
107    match abi.supports_c_variadic() {
108        CVariadicStatus::Stable => {}
109        CVariadicStatus::NotSupported => {
110            tcx.dcx()
111                .create_err(errors::VariadicFunctionCompatibleConvention {
112                    span,
113                    convention: &::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}", abi))
    })format!("{abi}"),
114                })
115                .emit();
116        }
117        CVariadicStatus::Unstable { feature } => {
118            if !tcx.features().enabled(feature) {
119                feature_err(
120                    &tcx.sess,
121                    feature,
122                    span,
123                    ::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"),
124                )
125                .emit();
126            }
127        }
128    }
129}
130
131/// Adds query implementations to the [Providers] vtable, see [`rustc_middle::query`]
132pub fn provide(providers: &mut Providers) {
133    collect::provide(providers);
134    coherence::provide(providers);
135    check::provide(providers);
136    *providers = Providers {
137        check_unused_traits: check_unused::check_unused_traits,
138        diagnostic_hir_wf_check: hir_wf_check::diagnostic_hir_wf_check,
139        inferred_outlives_crate: outlives::inferred_outlives_crate,
140        inferred_outlives_of: outlives::inferred_outlives_of,
141        inherit_sig_for_delegation_item: delegation::inherit_sig_for_delegation_item,
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 emit_delayed_lint(lint: &DelayedLint, tcx: TyCtxt<'_>) {
151    match lint {
152        DelayedLint::AttributeParsing(attribute_lint) => {
153            tcx.emit_node_span_lint(
154                attribute_lint.lint_id.lint,
155                attribute_lint.id,
156                attribute_lint.span,
157                DecorateAttrLint {
158                    sess: tcx.sess,
159                    tcx: Some(tcx),
160                    diagnostic: &attribute_lint.kind,
161                },
162            );
163        }
164    }
165}
166
167pub fn check_crate(tcx: TyCtxt<'_>) {
168    let _prof_timer = tcx.sess.timer("type_check_crate");
169
170    tcx.sess.time("coherence_checking", || {
171        // When discarding query call results, use an explicit type to indicate
172        // what we are intending to discard, to help future type-based refactoring.
173        type R = Result<(), ErrorGuaranteed>;
174
175        let _: R = tcx.ensure_result().check_type_wf(());
176
177        for &trait_def_id in tcx.all_local_trait_impls(()).keys() {
178            let _: R = tcx.ensure_result().coherent_trait(trait_def_id);
179        }
180        // these queries are executed for side-effects (error reporting):
181        let _: R = tcx.ensure_result().crate_inherent_impls_validity_check(());
182        let _: R = tcx.ensure_result().crate_inherent_impls_overlap_check(());
183    });
184
185    tcx.sess.time("emit_ast_lowering_delayed_lints", || {
186        // sanity check in debug mode that all lints are really noticed
187        // and we really will emit them all in the loop right below.
188        //
189        // during ast lowering, when creating items, foreign items, trait items and impl items
190        // we store in them whether they have any lints in their owner node that should be
191        // picked up by `hir_crate_items`. However, theoretically code can run between that
192        // boolean being inserted into the item and the owner node being created.
193        // We don't want any new lints to be emitted there
194        // (though honestly, you have to really try to manage to do that but still),
195        // but this check is there to catch that.
196        #[cfg(debug_assertions)]
197        {
198            // iterate over all owners
199            for owner_id in tcx.hir_crate_items(()).owners() {
200                // if it has delayed lints
201                if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) {
202                    if !delayed_lints.lints.is_empty() {
203                        // assert that delayed_lint_items also picked up this item to have lints
204                        if !tcx.hir_crate_items(()).delayed_lint_items().any(|i| i == owner_id) {
    ::core::panicking::panic("assertion failed: tcx.hir_crate_items(()).delayed_lint_items().any(|i| i == owner_id)")
};assert!(
205                            tcx.hir_crate_items(()).delayed_lint_items().any(|i| i == owner_id)
206                        );
207                    }
208                }
209            }
210        }
211
212        for owner_id in tcx.hir_crate_items(()).delayed_lint_items() {
213            if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) {
214                for lint in &delayed_lints.lints {
215                    emit_delayed_lint(lint, tcx);
216                }
217            }
218        }
219    });
220
221    tcx.par_hir_body_owners(|item_def_id| {
222        let def_kind = tcx.def_kind(item_def_id);
223        // Make sure we evaluate all static and (non-associated) const items, even if unused.
224        // If any of these fail to evaluate, we do not want this crate to pass compilation.
225        match def_kind {
226            DefKind::Static { .. } => {
227                tcx.ensure_ok().eval_static_initializer(item_def_id);
228                check::maybe_check_static_with_link_section(tcx, item_def_id);
229            }
230            DefKind::Const { .. }
231                if !tcx.generics_of(item_def_id).own_requires_monomorphization()
232                    && !tcx.is_type_const(item_def_id) =>
233            {
234                // FIXME(generic_const_items): Passing empty instead of identity args is fishy but
235                //                             seems to be fine for now. Revisit this!
236                let instance = ty::Instance::new_raw(item_def_id.into(), ty::GenericArgs::empty());
237                let cid = GlobalId { instance, promoted: None };
238                let typing_env = ty::TypingEnv::fully_monomorphized();
239                tcx.ensure_ok().eval_to_const_value_raw(typing_env.as_query_input(cid));
240            }
241            _ => (),
242        }
243        // Skip `AnonConst`s because we feed their `type_of`.
244        // Also skip items for which typeck forwards to parent typeck.
245        if !(#[allow(non_exhaustive_omitted_patterns)] match def_kind {
    DefKind::AnonConst => true,
    _ => false,
}matches!(def_kind, DefKind::AnonConst) || def_kind.is_typeck_child()) {
246            tcx.ensure_ok().typeck(item_def_id);
247        }
248        // Ensure we generate the new `DefId` before finishing `check_crate`.
249        // Afterwards we freeze the list of `DefId`s.
250        if tcx.needs_coroutine_by_move_body_def_id(item_def_id.to_def_id()) {
251            tcx.ensure_done().coroutine_by_move_body_def_id(item_def_id);
252        }
253    });
254
255    if tcx.features().rustc_attrs() {
256        tcx.sess.time("dumping_rustc_attr_data", || {
257            outlives::dump::inferred_outlives(tcx);
258            variance::dump::variances(tcx);
259            collect::dump::opaque_hidden_types(tcx);
260            collect::dump::predicates_and_item_bounds(tcx);
261            collect::dump::def_parents(tcx);
262            collect::dump::vtables(tcx);
263        });
264    }
265
266    tcx.ensure_ok().check_unused_traits(());
267}
268
269/// Lower a [`hir::Ty`] to a [`Ty`].
270///
271/// <div class="warning">
272///
273/// This function is **quasi-deprecated**. It can cause ICEs if called inside of a body
274/// (of a function or constant) and especially if it contains inferred types (`_`).
275///
276/// It's used in rustdoc and Clippy.
277///
278/// </div>
279pub fn lower_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
280    // In case there are any projections, etc., find the "environment"
281    // def-ID that will be used to determine the traits/predicates in
282    // scope. This is derived from the enclosing item-like thing.
283    let env_def_id = tcx.hir_get_parent_item(hir_ty.hir_id);
284    collect::ItemCtxt::new(tcx, env_def_id.def_id)
285        .lowerer()
286        .lower_ty_maybe_return_type_notation(hir_ty)
287}
288
289/// This is for rustdoc.
290// FIXME(const_generics): having special methods for rustdoc in `rustc_hir_analysis` is cursed
291pub fn lower_const_arg_for_rustdoc<'tcx>(
292    tcx: TyCtxt<'tcx>,
293    hir_ct: &hir::ConstArg<'tcx>,
294    ty: Ty<'tcx>,
295) -> Const<'tcx> {
296    let env_def_id = tcx.hir_get_parent_item(hir_ct.hir_id);
297    collect::ItemCtxt::new(tcx, env_def_id.def_id).lowerer().lower_const_arg(hir_ct, ty)
298}