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