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