summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_typeck/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--compiler/rustc_typeck/src/lib.rs579
1 files changed, 0 insertions, 579 deletions
diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs
deleted file mode 100644
index f98ae46c5..000000000
--- a/compiler/rustc_typeck/src/lib.rs
+++ /dev/null
@@ -1,579 +0,0 @@
-/*!
-
-# typeck
-
-The type checker is responsible for:
-
-1. Determining the type of each expression.
-2. Resolving methods and traits.
-3. Guaranteeing that most type rules are met. ("Most?", you say, "why most?"
- Well, dear reader, read on.)
-
-The main entry point is [`check_crate()`]. Type checking operates in
-several major phases:
-
-1. The collect phase first passes over all items and determines their
- type, without examining their "innards".
-
-2. Variance inference then runs to compute the variance of each parameter.
-
-3. Coherence checks for overlapping or orphaned impls.
-
-4. Finally, the check phase then checks function bodies and so forth.
- Within the check phase, we check each function body one at a time
- (bodies of function expressions are checked as part of the
- containing function). Inference is used to supply types wherever
- they are unknown. The actual checking of a function itself has
- several phases (check, regionck, writeback), as discussed in the
- documentation for the [`check`] module.
-
-The type checker is defined into various submodules which are documented
-independently:
-
-- astconv: converts the AST representation of types
- into the `ty` representation.
-
-- collect: computes the types of each top-level item and enters them into
- the `tcx.types` table for later use.
-
-- coherence: enforces coherence rules, builds some tables.
-
-- variance: variance inference
-
-- outlives: outlives inference
-
-- check: walks over function bodies and type checks them, inferring types for
- local variables, type parameters, etc as necessary.
-
-- infer: finds the types to use for each type variable such that
- all subtyping and assignment constraints are met. In essence, the check
- module specifies the constraints, and the infer module solves them.
-
-## Note
-
-This API is completely unstable and subject to change.
-
-*/
-
-#![allow(rustc::potential_query_instability)]
-#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(box_patterns)]
-#![feature(control_flow_enum)]
-#![feature(drain_filter)]
-#![feature(hash_drain_filter)]
-#![feature(if_let_guard)]
-#![feature(is_sorted)]
-#![feature(iter_intersperse)]
-#![feature(label_break_value)]
-#![feature(let_chains)]
-#![feature(let_else)]
-#![feature(min_specialization)]
-#![feature(never_type)]
-#![feature(once_cell)]
-#![feature(slice_partition_dedup)]
-#![feature(try_blocks)]
-#![feature(is_some_with)]
-#![recursion_limit = "256"]
-
-#[macro_use]
-extern crate tracing;
-
-#[macro_use]
-extern crate rustc_middle;
-
-// These are used by Clippy.
-pub mod check;
-pub mod expr_use_visitor;
-
-mod astconv;
-mod bounds;
-mod check_unused;
-mod coherence;
-mod collect;
-mod constrained_generic_params;
-mod errors;
-pub mod hir_wf_check;
-mod impl_wf_check;
-mod mem_categorization;
-mod outlives;
-mod structured_errors;
-mod variance;
-
-use rustc_errors::{struct_span_err, ErrorGuaranteed};
-use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
-use rustc_hir::{Node, CRATE_HIR_ID};
-use rustc_infer::infer::{InferOk, TyCtxtInferExt};
-use rustc_infer::traits::TraitEngineExt as _;
-use rustc_middle::middle;
-use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_middle::util;
-use rustc_session::config::EntryFnType;
-use rustc_span::{symbol::sym, Span, DUMMY_SP};
-use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::infer::InferCtxtExt;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
-use rustc_trait_selection::traits::{
- self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt as _,
-};
-
-use std::iter;
-
-use astconv::AstConv;
-use bounds::Bounds;
-
-fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) {
- match (decl.c_variadic, abi) {
- // The function has the correct calling convention, or isn't a "C-variadic" function.
- (false, _) | (true, Abi::C { .. }) | (true, Abi::Cdecl { .. }) => {}
- // The function is a "C-variadic" function with an incorrect calling convention.
- (true, _) => {
- let mut err = struct_span_err!(
- tcx.sess,
- span,
- E0045,
- "C-variadic function must have C or cdecl calling convention"
- );
- err.span_label(span, "C-variadics require C or cdecl calling convention").emit();
- }
- }
-}
-
-fn require_same_types<'tcx>(
- tcx: TyCtxt<'tcx>,
- cause: &ObligationCause<'tcx>,
- expected: Ty<'tcx>,
- actual: Ty<'tcx>,
-) -> bool {
- tcx.infer_ctxt().enter(|ref infcx| {
- let param_env = ty::ParamEnv::empty();
- let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
- match infcx.at(cause, param_env).eq(expected, actual) {
- Ok(InferOk { obligations, .. }) => {
- fulfill_cx.register_predicate_obligations(infcx, obligations);
- }
- Err(err) => {
- infcx.report_mismatched_types(cause, expected, actual, err).emit();
- return false;
- }
- }
-
- match fulfill_cx.select_all_or_error(infcx).as_slice() {
- [] => true,
- errors => {
- infcx.report_fulfillment_errors(errors, None, false);
- false
- }
- }
- })
-}
-
-fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
- let main_fnsig = tcx.fn_sig(main_def_id);
- let main_span = tcx.def_span(main_def_id);
-
- fn main_fn_diagnostics_hir_id(tcx: TyCtxt<'_>, def_id: DefId, sp: Span) -> hir::HirId {
- if let Some(local_def_id) = def_id.as_local() {
- let hir_id = tcx.hir().local_def_id_to_hir_id(local_def_id);
- let hir_type = tcx.type_of(local_def_id);
- if !matches!(hir_type.kind(), ty::FnDef(..)) {
- span_bug!(sp, "main has a non-function type: found `{}`", hir_type);
- }
- hir_id
- } else {
- CRATE_HIR_ID
- }
- }
-
- fn main_fn_generics_params_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
- if !def_id.is_local() {
- return None;
- }
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- match tcx.hir().find(hir_id) {
- Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, ref generics, _), .. })) => {
- if !generics.params.is_empty() {
- Some(generics.span)
- } else {
- None
- }
- }
- _ => {
- span_bug!(tcx.def_span(def_id), "main has a non-function type");
- }
- }
- }
-
- fn main_fn_where_clauses_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
- if !def_id.is_local() {
- return None;
- }
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- match tcx.hir().find(hir_id) {
- Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, ref generics, _), .. })) => {
- Some(generics.where_clause_span)
- }
- _ => {
- span_bug!(tcx.def_span(def_id), "main has a non-function type");
- }
- }
- }
-
- fn main_fn_asyncness_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
- if !def_id.is_local() {
- return None;
- }
- Some(tcx.def_span(def_id))
- }
-
- fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
- if !def_id.is_local() {
- return None;
- }
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- match tcx.hir().find(hir_id) {
- Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(ref fn_sig, _, _), .. })) => {
- Some(fn_sig.decl.output.span())
- }
- _ => {
- span_bug!(tcx.def_span(def_id), "main has a non-function type");
- }
- }
- }
-
- let mut error = false;
- let main_diagnostics_hir_id = main_fn_diagnostics_hir_id(tcx, main_def_id, main_span);
- let main_fn_generics = tcx.generics_of(main_def_id);
- let main_fn_predicates = tcx.predicates_of(main_def_id);
- if main_fn_generics.count() != 0 || !main_fnsig.bound_vars().is_empty() {
- let generics_param_span = main_fn_generics_params_span(tcx, main_def_id);
- let msg = "`main` function is not allowed to have generic \
- parameters";
- let mut diag =
- struct_span_err!(tcx.sess, generics_param_span.unwrap_or(main_span), E0131, "{}", msg);
- if let Some(generics_param_span) = generics_param_span {
- let label = "`main` cannot have generic parameters";
- diag.span_label(generics_param_span, label);
- }
- diag.emit();
- error = true;
- } else if !main_fn_predicates.predicates.is_empty() {
- // generics may bring in implicit predicates, so we skip this check if generics is present.
- let generics_where_clauses_span = main_fn_where_clauses_span(tcx, main_def_id);
- let mut diag = struct_span_err!(
- tcx.sess,
- generics_where_clauses_span.unwrap_or(main_span),
- E0646,
- "`main` function is not allowed to have a `where` clause"
- );
- if let Some(generics_where_clauses_span) = generics_where_clauses_span {
- diag.span_label(generics_where_clauses_span, "`main` cannot have a `where` clause");
- }
- diag.emit();
- error = true;
- }
-
- let main_asyncness = tcx.asyncness(main_def_id);
- if let hir::IsAsync::Async = main_asyncness {
- let mut diag = struct_span_err!(
- tcx.sess,
- main_span,
- E0752,
- "`main` function is not allowed to be `async`"
- );
- let asyncness_span = main_fn_asyncness_span(tcx, main_def_id);
- if let Some(asyncness_span) = asyncness_span {
- diag.span_label(asyncness_span, "`main` function is not allowed to be `async`");
- }
- diag.emit();
- error = true;
- }
-
- for attr in tcx.get_attrs(main_def_id, sym::track_caller) {
- tcx.sess
- .struct_span_err(attr.span, "`main` function is not allowed to be `#[track_caller]`")
- .span_label(main_span, "`main` function is not allowed to be `#[track_caller]`")
- .emit();
- error = true;
- }
-
- if error {
- return;
- }
-
- let expected_return_type;
- if let Some(term_id) = tcx.lang_items().termination() {
- let return_ty = main_fnsig.output();
- let return_ty_span = main_fn_return_type_span(tcx, main_def_id).unwrap_or(main_span);
- if !return_ty.bound_vars().is_empty() {
- let msg = "`main` function return type is not allowed to have generic \
- parameters";
- struct_span_err!(tcx.sess, return_ty_span, E0131, "{}", msg).emit();
- error = true;
- }
- let return_ty = return_ty.skip_binder();
- tcx.infer_ctxt().enter(|infcx| {
- let cause = traits::ObligationCause::new(
- return_ty_span,
- main_diagnostics_hir_id,
- ObligationCauseCode::MainFunctionType,
- );
- let mut fulfillment_cx = traits::FulfillmentContext::new();
- // normalize any potential projections in the return type, then add
- // any possible obligations to the fulfillment context.
- // HACK(ThePuzzlemaker) this feels symptomatic of a problem within
- // checking trait fulfillment, not this here. I'm not sure why it
- // works in the example in `fn test()` given in #88609? This also
- // probably isn't the best way to do this.
- let InferOk { value: norm_return_ty, obligations } = infcx
- .partially_normalize_associated_types_in(
- cause.clone(),
- ty::ParamEnv::empty(),
- return_ty,
- );
- fulfillment_cx.register_predicate_obligations(&infcx, obligations);
- fulfillment_cx.register_bound(
- &infcx,
- ty::ParamEnv::empty(),
- norm_return_ty,
- term_id,
- cause,
- );
- let errors = fulfillment_cx.select_all_or_error(&infcx);
- if !errors.is_empty() {
- infcx.report_fulfillment_errors(&errors, None, false);
- error = true;
- }
- });
- // now we can take the return type of the given main function
- expected_return_type = main_fnsig.output();
- } else {
- // standard () main return type
- expected_return_type = ty::Binder::dummy(tcx.mk_unit());
- }
-
- if error {
- return;
- }
-
- let se_ty = tcx.mk_fn_ptr(expected_return_type.map_bound(|expected_return_type| {
- tcx.mk_fn_sig(iter::empty(), expected_return_type, false, hir::Unsafety::Normal, Abi::Rust)
- }));
-
- require_same_types(
- tcx,
- &ObligationCause::new(
- main_span,
- main_diagnostics_hir_id,
- ObligationCauseCode::MainFunctionType,
- ),
- se_ty,
- tcx.mk_fn_ptr(main_fnsig),
- );
-}
-fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
- let start_def_id = start_def_id.expect_local();
- let start_id = tcx.hir().local_def_id_to_hir_id(start_def_id);
- let start_span = tcx.def_span(start_def_id);
- let start_t = tcx.type_of(start_def_id);
- match start_t.kind() {
- ty::FnDef(..) => {
- if let Some(Node::Item(it)) = tcx.hir().find(start_id) {
- if let hir::ItemKind::Fn(ref sig, ref generics, _) = it.kind {
- let mut error = false;
- if !generics.params.is_empty() {
- struct_span_err!(
- tcx.sess,
- generics.span,
- E0132,
- "start function is not allowed to have type parameters"
- )
- .span_label(generics.span, "start function cannot have type parameters")
- .emit();
- error = true;
- }
- if generics.has_where_clause_predicates {
- struct_span_err!(
- tcx.sess,
- generics.where_clause_span,
- E0647,
- "start function is not allowed to have a `where` clause"
- )
- .span_label(
- generics.where_clause_span,
- "start function cannot have a `where` clause",
- )
- .emit();
- error = true;
- }
- if let hir::IsAsync::Async = sig.header.asyncness {
- let span = tcx.def_span(it.def_id);
- struct_span_err!(
- tcx.sess,
- span,
- E0752,
- "`start` is not allowed to be `async`"
- )
- .span_label(span, "`start` is not allowed to be `async`")
- .emit();
- error = true;
- }
-
- let attrs = tcx.hir().attrs(start_id);
- for attr in attrs {
- if attr.has_name(sym::track_caller) {
- tcx.sess
- .struct_span_err(
- attr.span,
- "`start` is not allowed to be `#[track_caller]`",
- )
- .span_label(
- start_span,
- "`start` is not allowed to be `#[track_caller]`",
- )
- .emit();
- error = true;
- }
- }
-
- if error {
- return;
- }
- }
- }
-
- let se_ty = tcx.mk_fn_ptr(ty::Binder::dummy(tcx.mk_fn_sig(
- [tcx.types.isize, tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))].iter().cloned(),
- tcx.types.isize,
- false,
- hir::Unsafety::Normal,
- Abi::Rust,
- )));
-
- require_same_types(
- tcx,
- &ObligationCause::new(start_span, start_id, ObligationCauseCode::StartFunctionType),
- se_ty,
- tcx.mk_fn_ptr(tcx.fn_sig(start_def_id)),
- );
- }
- _ => {
- span_bug!(start_span, "start has a non-function type: found `{}`", start_t);
- }
- }
-}
-
-fn check_for_entry_fn(tcx: TyCtxt<'_>) {
- match tcx.entry_fn(()) {
- Some((def_id, EntryFnType::Main)) => check_main_fn_ty(tcx, def_id),
- Some((def_id, EntryFnType::Start)) => check_start_fn_ty(tcx, def_id),
- _ => {}
- }
-}
-
-pub fn provide(providers: &mut Providers) {
- collect::provide(providers);
- coherence::provide(providers);
- check::provide(providers);
- variance::provide(providers);
- outlives::provide(providers);
- impl_wf_check::provide(providers);
- hir_wf_check::provide(providers);
-}
-
-pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
- let _prof_timer = tcx.sess.timer("type_check_crate");
-
- // this ensures that later parts of type checking can assume that items
- // have valid types and not error
- // FIXME(matthewjasper) We shouldn't need to use `track_errors`.
- tcx.sess.track_errors(|| {
- tcx.sess.time("type_collecting", || {
- tcx.hir().for_each_module(|module| tcx.ensure().collect_mod_item_types(module))
- });
- })?;
-
- if tcx.features().rustc_attrs {
- tcx.sess.track_errors(|| {
- tcx.sess.time("outlives_testing", || outlives::test::test_inferred_outlives(tcx));
- })?;
- }
-
- tcx.sess.track_errors(|| {
- tcx.sess.time("impl_wf_inference", || {
- tcx.hir().for_each_module(|module| tcx.ensure().check_mod_impl_wf(module))
- });
- })?;
-
- tcx.sess.track_errors(|| {
- tcx.sess.time("coherence_checking", || {
- for &trait_def_id in tcx.all_local_trait_impls(()).keys() {
- tcx.ensure().coherent_trait(trait_def_id);
- }
-
- // these queries are executed for side-effects (error reporting):
- tcx.ensure().crate_inherent_impls(());
- tcx.ensure().crate_inherent_impls_overlap_check(());
- });
- })?;
-
- if tcx.features().rustc_attrs {
- tcx.sess.track_errors(|| {
- tcx.sess.time("variance_testing", || variance::test::test_variance(tcx));
- })?;
- }
-
- tcx.sess.track_errors(|| {
- tcx.sess.time("wf_checking", || {
- tcx.hir().par_for_each_module(|module| tcx.ensure().check_mod_type_wf(module))
- });
- })?;
-
- // NOTE: This is copy/pasted in librustdoc/core.rs and should be kept in sync.
- tcx.sess.time("item_types_checking", || {
- tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module))
- });
-
- tcx.sess.time("item_bodies_checking", || tcx.typeck_item_bodies(()));
-
- check_unused::check_crate(tcx);
- check_for_entry_fn(tcx);
-
- if let Some(reported) = tcx.sess.has_errors() { Err(reported) } else { Ok(()) }
-}
-
-/// A quasi-deprecated helper used in rustdoc and clippy to get
-/// the type from a HIR node.
-pub fn hir_ty_to_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> {
- // In case there are any projections, etc., find the "environment"
- // def-ID that will be used to determine the traits/predicates in
- // scope. This is derived from the enclosing item-like thing.
- let env_def_id = tcx.hir().get_parent_item(hir_ty.hir_id);
- let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id());
- <dyn AstConv<'_>>::ast_ty_to_ty(&item_cx, hir_ty)
-}
-
-pub fn hir_trait_to_predicates<'tcx>(
- tcx: TyCtxt<'tcx>,
- hir_trait: &hir::TraitRef<'_>,
- self_ty: Ty<'tcx>,
-) -> Bounds<'tcx> {
- // In case there are any projections, etc., find the "environment"
- // def-ID that will be used to determine the traits/predicates in
- // scope. This is derived from the enclosing item-like thing.
- let env_def_id = tcx.hir().get_parent_item(hir_trait.hir_ref_id);
- let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id());
- let mut bounds = Bounds::default();
- let _ = <dyn AstConv<'_>>::instantiate_poly_trait_ref(
- &item_cx,
- hir_trait,
- DUMMY_SP,
- ty::BoundConstness::NotConst,
- self_ty,
- &mut bounds,
- true,
- );
-
- bounds
-}