rust/compiler/rustc_hir_analysis/src/collect.rs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1490 lines
55 KiB
Rust
Raw Normal View History

//! "Collection" is the process of determining the type and other external
//! details of each item in Rust. Collection is specifically concerned
//! with *inter-procedural* things -- for example, for a function
//! definition, collection will figure out the type and signature of the
//! function, but it will not visit the *body* of the function in any way,
//! nor examine type annotations on local variables (that's the job of
//! type *checking*).
//!
//! Collecting is ultimately defined by a bundle of queries that
//! inquire after various facts about the items in the crate (e.g.,
//! `type_of`, `generics_of`, `predicates_of`, etc). See the `provide` function
//! for the full set.
//!
//! At present, however, we do run collection across all items in the
//! crate as a kind of pass. This should eventually be factored away.
use crate::astconv::AstConv;
2019-09-28 16:24:05 +00:00
use crate::check::intrinsic::intrinsic_operation_unsafety;
use crate::errors;
2022-12-27 23:56:46 +00:00
use hir::def::DefKind;
use rustc_data_structures::captures::Captures;
2022-09-29 09:31:46 +00:00
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{GenericParamKind, Node};
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
2022-12-27 23:56:46 +00:00
use rustc_infer::traits::ObligationCause;
use rustc_middle::hir::nested_filter;
use rustc_middle::query::Providers;
2022-09-29 09:31:46 +00:00
use rustc_middle::ty::util::{Discr, IntTypeExt};
2022-12-27 21:44:39 +00:00
use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, ToPredicate, Ty, TyCtxt};
2020-04-19 11:00:18 +00:00
use rustc_span::symbol::{kw, sym, Ident, Symbol};
2022-09-29 09:31:46 +00:00
use rustc_span::Span;
use rustc_target::spec::abi;
use rustc_trait_selection::infer::InferCtxtExt;
2020-04-05 22:33:33 +00:00
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
use rustc_trait_selection::traits::ObligationCtxt;
2021-03-08 23:32:41 +00:00
use std::iter;
2022-09-29 09:31:46 +00:00
mod generics_of;
2020-06-23 17:18:06 +00:00
mod item_bounds;
2022-09-29 09:31:46 +00:00
mod predicates_of;
2023-02-06 18:38:52 +00:00
mod resolve_bound_vars;
2020-01-17 21:15:03 +00:00
mod type_of;
///////////////////////////////////////////////////////////////////////////
// Main entry point
2020-06-27 11:09:54 +00:00
fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
tcx.hir().visit_item_likes_in_module(module_def_id, &mut CollectItemTypesVisitor { tcx });
}
pub fn provide(providers: &mut Providers) {
2023-02-06 18:38:52 +00:00
resolve_bound_vars::provide(providers);
*providers = Providers {
2020-01-17 21:15:03 +00:00
type_of: type_of::type_of,
2020-06-23 17:18:06 +00:00
item_bounds: item_bounds::item_bounds,
2020-06-24 18:13:44 +00:00
explicit_item_bounds: item_bounds::explicit_item_bounds,
2022-09-29 09:31:46 +00:00
generics_of: generics_of::generics_of,
predicates_of: predicates_of::predicates_of,
predicates_defined_on,
2022-09-29 09:31:46 +00:00
explicit_predicates_of: predicates_of::explicit_predicates_of,
super_predicates_of: predicates_of::super_predicates_of,
implied_predicates_of: predicates_of::implied_predicates_of,
super_predicates_that_define_assoc_item:
predicates_of::super_predicates_that_define_assoc_item,
2022-09-29 09:31:46 +00:00
trait_explicit_predicates_and_bounds: predicates_of::trait_explicit_predicates_and_bounds,
type_param_predicates: predicates_of::type_param_predicates,
trait_def,
adt_def,
fn_sig,
impl_trait_ref,
impl_polarity,
2020-01-26 01:09:23 +00:00
generator_kind,
2018-06-06 20:13:52 +00:00
collect_mod_item_types,
is_type_alias_impl_trait,
..*providers
};
}
///////////////////////////////////////////////////////////////////////////
/// Context specific to some particular item. This is what implements
2022-08-08 04:16:47 +00:00
/// [`AstConv`].
///
2022-08-08 04:16:47 +00:00
/// # `ItemCtxt` vs `FnCtxt`
///
2022-08-08 04:16:47 +00:00
/// `ItemCtxt` is primarily used to type-check item signatures and lower them
/// from HIR to their [`ty::Ty`] representation, which is exposed using [`AstConv`].
/// It's also used for the bodies of items like structs where the body (the fields)
/// are just signatures.
///
2022-10-20 21:47:49 +00:00
/// This is in contrast to `FnCtxt`, which is used to type-check bodies of
2022-08-08 04:16:47 +00:00
/// functions, closures, and `const`s -- anywhere that expressions and statements show up.
///
/// An important thing to note is that `ItemCtxt` does no inference -- it has no [`InferCtxt`] --
/// while `FnCtxt` does do inference.
///
/// [`InferCtxt`]: rustc_infer::infer::InferCtxt
///
/// # Trait predicates
///
/// `ItemCtxt` has information about the predicates that are defined
/// on the trait. Unfortunately, this predicate information is
/// available in various different forms at various points in the
/// process. So we can't just store a pointer to e.g., the AST or the
/// parsed ty form, we have to be more flexible. To this end, the
/// `ItemCtxt` is parameterized by a `DefId` that it uses to satisfy
/// `get_type_parameter_bounds` requests, drawing the information from
/// the AST (`hir::Generics`), recursively.
pub struct ItemCtxt<'tcx> {
2019-06-13 21:48:52 +00:00
tcx: TyCtxt<'tcx>,
2023-03-13 19:06:41 +00:00
item_def_id: LocalDefId,
}
///////////////////////////////////////////////////////////////////////////
2019-12-30 19:45:48 +00:00
#[derive(Default)]
pub(crate) struct HirPlaceholderCollector(pub(crate) Vec<Span>);
impl<'v> Visitor<'v> for HirPlaceholderCollector {
fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
if let hir::TyKind::Infer = t.kind {
self.0.push(t.span);
}
intravisit::walk_ty(self, t)
}
2021-04-24 21:41:57 +00:00
fn visit_generic_arg(&mut self, generic_arg: &'v hir::GenericArg<'v>) {
match generic_arg {
hir::GenericArg::Infer(inf) => {
self.0.push(inf.span);
2021-04-26 18:19:23 +00:00
intravisit::walk_inf(self, inf);
2021-04-24 21:41:57 +00:00
}
hir::GenericArg::Type(t) => self.visit_ty(t),
_ => {}
}
}
fn visit_array_length(&mut self, length: &'v hir::ArrayLen) {
if let &hir::ArrayLen::Infer(_, span) = length {
self.0.push(span);
}
intravisit::walk_array_len(self, length)
}
}
struct CollectItemTypesVisitor<'tcx> {
2019-06-13 21:48:52 +00:00
tcx: TyCtxt<'tcx>,
}
2019-12-30 19:45:48 +00:00
/// If there are any placeholder types (`_`), emit an error explaining that this is not allowed
/// and suggest adding type parameters in the appropriate place, taking into consideration any and
/// all already existing generic type parameters to avoid suggesting a name that is already in use.
pub(crate) fn placeholder_type_error<'tcx>(
tcx: TyCtxt<'tcx>,
generics: Option<&hir::Generics<'_>>,
placeholder_types: Vec<Span>,
suggest: bool,
hir_ty: Option<&hir::Ty<'_>>,
2021-06-18 23:01:37 +00:00
kind: &'static str,
) {
2019-12-26 22:01:45 +00:00
if placeholder_types.is_empty() {
return;
}
placeholder_type_error_diag(tcx, generics, placeholder_types, vec![], suggest, hir_ty, kind)
.emit();
}
pub(crate) fn placeholder_type_error_diag<'tcx>(
tcx: TyCtxt<'tcx>,
generics: Option<&hir::Generics<'_>>,
placeholder_types: Vec<Span>,
additional_spans: Vec<Span>,
suggest: bool,
hir_ty: Option<&hir::Ty<'_>>,
kind: &'static str,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
if placeholder_types.is_empty() {
return bad_placeholder(tcx, additional_spans, kind);
}
let params = generics.map(|g| g.params).unwrap_or_default();
let type_name = params.next_type_param_name(None);
2019-12-26 22:01:45 +00:00
let mut sugg: Vec<_> =
placeholder_types.iter().map(|sp| (*sp, (*type_name).to_string())).collect();
if let Some(generics) = generics {
if let Some(arg) = params.iter().find(|arg| {
matches!(arg.name, hir::ParamName::Plain(Ident { name: kw::Underscore, .. }))
}) {
// Account for `_` already present in cases like `struct S<_>(_);` and suggest
// `struct S<T>(T);` instead of `struct S<_, T>(T);`.
sugg.push((arg.span, (*type_name).to_string()));
} else if let Some(span) = generics.span_for_param_suggestion() {
// Account for bounds, we want `fn foo<T: E, K>(_: K)` not `fn foo<T, K: E>(_: K)`.
sugg.push((span, format!(", {}", type_name)));
} else {
sugg.push((generics.span, format!("<{}>", type_name)));
}
2019-12-26 22:01:45 +00:00
}
let mut err =
bad_placeholder(tcx, placeholder_types.into_iter().chain(additional_spans).collect(), kind);
2021-02-09 08:42:08 +00:00
// Suggest, but only if it is not a function in const or static
2019-12-26 22:01:45 +00:00
if suggest {
let mut is_fn = false;
let mut is_const_or_static = false;
2022-02-26 10:43:47 +00:00
if let Some(hir_ty) = hir_ty && let hir::TyKind::BareFn(_) = hir_ty.kind {
is_fn = true;
// Check if parent is const or static
2023-01-03 07:31:04 +00:00
let parent_id = tcx.hir().parent_id(hir_ty.hir_id);
2022-02-26 10:43:47 +00:00
let parent_node = tcx.hir().get(parent_id);
is_const_or_static = matches!(
parent_node,
Node::Item(&hir::Item {
kind: hir::ItemKind::Const(..) | hir::ItemKind::Static(..),
..
}) | Node::TraitItem(&hir::TraitItem {
kind: hir::TraitItemKind::Const(..),
..
}) | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. })
);
}
// if function is wrapped around a const or static,
// then don't show the suggestion
if !(is_fn && is_const_or_static) {
err.multipart_suggestion(
"use type parameters instead",
sugg,
Applicability::HasPlaceholders,
);
}
}
err
}
fn reject_placeholder_type_signatures_in_item<'tcx>(
tcx: TyCtxt<'tcx>,
item: &'tcx hir::Item<'tcx>,
) {
let (generics, suggest) = match &item.kind {
hir::ItemKind::Union(_, generics)
| hir::ItemKind::Enum(_, generics)
| hir::ItemKind::TraitAlias(generics, _)
| hir::ItemKind::Trait(_, _, generics, ..)
| hir::ItemKind::Impl(hir::Impl { generics, .. })
| hir::ItemKind::Struct(_, generics) => (generics, true),
hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. })
| hir::ItemKind::TyAlias(_, generics) => (generics, false),
2019-12-27 23:45:39 +00:00
// `static`, `fn` and `const` are handled elsewhere to suggest appropriate type.
_ => return,
};
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_item(item);
placeholder_type_error(tcx, Some(generics), visitor.0, suggest, None, item.kind.descr());
}
2021-12-14 01:45:08 +00:00
impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
type NestedFilter = nested_filter::OnlyBodies;
2020-01-07 16:25:33 +00:00
fn nested_visit_map(&mut self) -> Self::Map {
self.tcx.hir()
}
2019-11-28 18:28:50 +00:00
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
convert_item(self.tcx, item.item_id());
reject_placeholder_type_signatures_in_item(self.tcx, item);
intravisit::walk_item(self, item);
}
2019-12-01 15:08:58 +00:00
fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
2019-12-01 16:10:12 +00:00
for param in generics.params {
2018-05-25 23:27:54 +00:00
match param.kind {
hir::GenericParamKind::Lifetime { .. } => {}
2018-08-19 16:34:21 +00:00
hir::GenericParamKind::Type { default: Some(_), .. } => {
self.tcx.ensure().type_of(param.def_id);
2018-05-25 23:27:54 +00:00
}
2018-05-27 20:54:10 +00:00
hir::GenericParamKind::Type { .. } => {}
2020-12-30 15:34:53 +00:00
hir::GenericParamKind::Const { default, .. } => {
self.tcx.ensure().type_of(param.def_id);
2020-12-30 15:34:53 +00:00
if let Some(default) = default {
2021-03-03 06:38:02 +00:00
// need to store default and type of default
2022-11-06 19:17:57 +00:00
self.tcx.ensure().type_of(default.def_id);
self.tcx.ensure().const_param_default(param.def_id);
2020-12-30 15:34:53 +00:00
}
}
}
}
intravisit::walk_generics(self, generics);
}
2019-11-30 14:08:22 +00:00
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
2022-11-06 13:29:21 +00:00
if let hir::ExprKind::Closure(closure) = expr.kind {
self.tcx.ensure().generics_of(closure.def_id);
self.tcx.ensure().codegen_fn_attrs(closure.def_id);
// We do not call `type_of` for closures here as that
// depends on typecheck and would therefore hide
// any further errors in case one typeck fails.
2016-11-12 21:20:02 +00:00
}
intravisit::walk_expr(self, expr);
}
2019-11-28 20:47:10 +00:00
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
convert_trait_item(self.tcx, trait_item.trait_item_id());
intravisit::walk_trait_item(self, trait_item);
}
2019-11-28 21:16:44 +00:00
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
convert_impl_item(self.tcx, impl_item.impl_item_id());
intravisit::walk_impl_item(self, impl_item);
}
}
///////////////////////////////////////////////////////////////////////////
// Utility types and common code for the above passes.
fn bad_placeholder<'tcx>(
2019-12-27 12:15:48 +00:00
tcx: TyCtxt<'tcx>,
mut spans: Vec<Span>,
2021-06-18 23:01:37 +00:00
kind: &'static str,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
2021-06-18 23:01:37 +00:00
let kind = if kind.ends_with('s') { format!("{}es", kind) } else { format!("{}s", kind) };
2019-12-27 12:15:48 +00:00
spans.sort();
tcx.sess.create_err(errors::PlaceholderNotAllowedItemSignatures { spans, kind })
}
2021-12-14 01:45:08 +00:00
impl<'tcx> ItemCtxt<'tcx> {
2023-03-13 19:06:41 +00:00
pub fn new(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId) -> ItemCtxt<'tcx> {
2018-08-19 16:34:21 +00:00
ItemCtxt { tcx, item_def_id }
}
2021-02-10 01:05:18 +00:00
pub fn to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
self.astconv().ast_ty_to_ty(ast_ty)
}
pub fn hir_id(&self) -> hir::HirId {
2023-03-13 19:06:41 +00:00
self.tcx.hir().local_def_id_to_hir_id(self.item_def_id)
}
pub fn node(&self) -> hir::Node<'tcx> {
self.tcx.hir().get(self.hir_id())
}
}
2021-12-14 01:45:08 +00:00
impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
2019-06-13 21:48:52 +00:00
fn tcx(&self) -> TyCtxt<'tcx> {
2018-08-19 16:34:21 +00:00
self.tcx
}
2022-10-31 16:19:36 +00:00
fn item_def_id(&self) -> DefId {
2023-03-13 19:06:41 +00:00
self.item_def_id.to_def_id()
}
fn get_type_parameter_bounds(
&self,
span: Span,
2023-03-13 19:06:41 +00:00
def_id: LocalDefId,
assoc_name: Ident,
) -> ty::GenericPredicates<'tcx> {
2023-03-13 19:06:41 +00:00
self.tcx.at(span).type_param_predicates((self.item_def_id, def_id, assoc_name))
}
2019-06-06 00:55:34 +00:00
fn re_infer(&self, _: Option<&ty::GenericParamDef>, _: Span) -> Option<ty::Region<'tcx>> {
None
}
fn allow_ty_infer(&self) -> bool {
false
}
2019-06-06 00:55:34 +00:00
fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
2022-01-05 10:42:08 +00:00
self.tcx().ty_error_with_message(span, "bad placeholder type")
}
fn ct_infer(&self, ty: Ty<'tcx>, _: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> {
2022-06-27 13:55:03 +00:00
let ty = self.tcx.fold_regions(ty, |r, _| match *r {
// This is never reached in practice. If it ever is reached,
// `ReErased` should be changed to `ReStatic`, and any other region
// left alone.
r => bug!("unexpected region: {r:?}"),
});
2022-01-05 10:42:08 +00:00
self.tcx().const_error_with_message(ty, span, "bad placeholder constant")
2019-06-06 00:55:09 +00:00
}
2018-08-19 16:34:21 +00:00
fn projected_ty_from_poly_trait_ref(
&self,
span: Span,
item_def_id: DefId,
2019-12-01 15:08:58 +00:00
item_segment: &hir::PathSegment<'_>,
2018-08-19 16:34:21 +00:00
poly_trait_ref: ty::PolyTraitRef<'tcx>,
) -> Ty<'tcx> {
if let Some(trait_ref) = poly_trait_ref.no_bound_vars() {
let item_substs = self.astconv().create_substs_for_associated_item(
span,
item_def_id,
item_segment,
trait_ref.substs,
);
self.tcx().mk_projection(item_def_id, item_substs)
} else {
2019-06-17 22:40:24 +00:00
// There are no late-bound regions; we can just ignore the binder.
let (mut mpart_sugg, mut inferred_sugg) = (None, None);
let mut bound = String::new();
match self.node() {
hir::Node::Field(_) | hir::Node::Ctor(_) | hir::Node::Variant(_) => {
let item = self
.tcx
.hir()
.expect_item(self.tcx.hir().get_parent_item(self.hir_id()).def_id);
match &item.kind {
hir::ItemKind::Enum(_, generics)
| hir::ItemKind::Struct(_, generics)
| hir::ItemKind::Union(_, generics) => {
let lt_name = get_new_lifetime_name(self.tcx, poly_trait_ref, generics);
let (lt_sp, sugg) = match generics.params {
[] => (generics.span, format!("<{}>", lt_name)),
[bound, ..] => {
(bound.span.shrink_to_lo(), format!("{}, ", lt_name))
}
};
mpart_sugg = Some(errors::AssociatedTypeTraitUninferredGenericParamsMultipartSuggestion {
fspan: lt_sp,
first: sugg,
sspan: span.with_hi(item_segment.ident.span.lo()),
second: format!(
"{}::",
// Replace the existing lifetimes with a new named lifetime.
self.tcx.replace_late_bound_regions_uncached(
poly_trait_ref,
|_| {
ty::Region::new_early_bound(self.tcx, ty::EarlyBoundRegion {
def_id: item_def_id,
index: 0,
name: Symbol::intern(&lt_name),
})
}
),
),
});
}
_ => {}
}
}
hir::Node::Item(hir::Item {
kind:
hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) | hir::ItemKind::Union(..),
..
}) => {}
hir::Node::Item(_)
| hir::Node::ForeignItem(_)
| hir::Node::TraitItem(_)
| hir::Node::ImplItem(_) => {
inferred_sugg = Some(span.with_hi(item_segment.ident.span.lo()));
bound = format!(
"{}::",
// Erase named lt, we want `<A as B<'_>::C`, not `<A as B<'a>::C`.
self.tcx.anonymize_bound_vars(poly_trait_ref).skip_binder(),
);
}
_ => {}
}
self.tcx().ty_error(self.tcx().sess.emit_err(
errors::AssociatedTypeTraitUninferredGenericParams {
span,
inferred_sugg,
bound,
mpart_sugg,
},
))
}
}
2022-10-29 13:19:57 +00:00
fn probe_adt(&self, _span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>> {
// FIXME(#103640): Should we handle the case where `ty` is a projection?
ty.ty_adt_def()
}
fn set_tainted_by_errors(&self, _: ErrorGuaranteed) {
2019-06-17 22:40:24 +00:00
// There's no obvious place to track this, so just let it go.
}
fn record_ty(&self, _hir_id: hir::HirId, _ty: Ty<'tcx>, _span: Span) {
2019-06-17 22:40:24 +00:00
// There's no place to record types from signatures?
}
fn infcx(&self) -> Option<&InferCtxt<'tcx>> {
None
}
}
/// Synthesize a new lifetime name that doesn't clash with any of the lifetimes already present.
fn get_new_lifetime_name<'tcx>(
tcx: TyCtxt<'tcx>,
poly_trait_ref: ty::PolyTraitRef<'tcx>,
generics: &hir::Generics<'tcx>,
) -> String {
let existing_lifetimes = tcx
.collect_referenced_late_bound_regions(&poly_trait_ref)
.into_iter()
.filter_map(|lt| {
if let ty::BoundRegionKind::BrNamed(_, name) = lt {
Some(name.as_str().to_string())
} else {
None
}
})
.chain(generics.params.iter().filter_map(|param| {
if let hir::GenericParamKind::Lifetime { .. } = &param.kind {
Some(param.name.ident().as_str().to_string())
} else {
None
}
}))
.collect::<FxHashSet<String>>();
let a_to_z_repeat_n = |n| {
(b'a'..=b'z').map(move |c| {
let mut s = '\''.to_string();
s.extend(std::iter::repeat(char::from(c)).take(n));
s
})
};
// If all single char lifetime names are present, we wrap around and double the chars.
(1..).flat_map(a_to_z_repeat_n).find(|lt| !existing_lifetimes.contains(lt.as_str())).unwrap()
}
fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
let it = tcx.hir().item(item_id);
debug!("convert: item {} with id {}", it.ident, it.hir_id());
let def_id = item_id.owner_id.def_id;
match &it.kind {
// These don't define types.
2018-08-19 16:34:21 +00:00
hir::ItemKind::ExternCrate(_)
| hir::ItemKind::Use(..)
| hir::ItemKind::Macro(..)
2018-08-19 16:34:21 +00:00
| hir::ItemKind::Mod(_)
| hir::ItemKind::GlobalAsm(_) => {}
2020-11-11 21:40:09 +00:00
hir::ItemKind::ForeignMod { items, .. } => {
for item in *items {
2020-11-11 20:57:54 +00:00
let item = tcx.hir().foreign_item(item.id);
tcx.ensure().generics_of(item.owner_id);
tcx.ensure().type_of(item.owner_id);
tcx.ensure().predicates_of(item.owner_id);
match item.kind {
hir::ForeignItemKind::Fn(..) => {
tcx.ensure().codegen_fn_attrs(item.owner_id);
tcx.ensure().fn_sig(item.owner_id)
}
hir::ForeignItemKind::Static(..) => {
tcx.ensure().codegen_fn_attrs(item.owner_id);
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_foreign_item(item);
2021-06-18 23:01:37 +00:00
placeholder_type_error(
tcx,
None,
visitor.0,
false,
None,
"static variable",
);
}
_ => (),
}
}
}
2022-10-30 09:17:16 +00:00
hir::ItemKind::Enum(..) => {
2020-05-01 09:32:20 +00:00
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().predicates_of(def_id);
2022-10-30 09:17:16 +00:00
convert_enum_variant_types(tcx, def_id.to_def_id());
2018-08-19 16:34:21 +00:00
}
hir::ItemKind::Impl { .. } => {
2020-05-01 09:32:20 +00:00
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().impl_trait_ref(def_id);
tcx.ensure().predicates_of(def_id);
2018-08-19 16:34:21 +00:00
}
2018-07-11 15:36:06 +00:00
hir::ItemKind::Trait(..) => {
2020-05-01 09:32:20 +00:00
tcx.ensure().generics_of(def_id);
tcx.ensure().trait_def(def_id);
tcx.at(it.span).super_predicates_of(def_id);
2020-05-01 09:32:20 +00:00
tcx.ensure().predicates_of(def_id);
2018-08-19 16:34:21 +00:00
}
2018-07-11 15:36:06 +00:00
hir::ItemKind::TraitAlias(..) => {
2020-05-01 09:32:20 +00:00
tcx.ensure().generics_of(def_id);
tcx.at(it.span).implied_predicates_of(def_id);
tcx.at(it.span).super_predicates_of(def_id);
2020-05-01 09:32:20 +00:00
tcx.ensure().predicates_of(def_id);
2018-08-19 16:34:21 +00:00
}
hir::ItemKind::Struct(struct_def, _) | hir::ItemKind::Union(struct_def, _) => {
2020-05-01 09:32:20 +00:00
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().predicates_of(def_id);
for f in struct_def.fields() {
tcx.ensure().generics_of(f.def_id);
tcx.ensure().type_of(f.def_id);
tcx.ensure().predicates_of(f.def_id);
}
if let Some(ctor_def_id) = struct_def.ctor_def_id() {
2022-10-30 09:17:16 +00:00
convert_variant_ctor(tcx, ctor_def_id);
}
2018-08-19 16:34:21 +00:00
}
2018-07-03 17:38:14 +00:00
// Don't call `type_of` on opaque types, since that depends on type
// checking function bodies. `check_item_type` ensures that it's called
// instead.
hir::ItemKind::OpaqueTy(..) => {
tcx.ensure().generics_of(def_id);
tcx.ensure().predicates_of(def_id);
2020-09-07 09:01:45 +00:00
tcx.ensure().explicit_item_bounds(def_id);
tcx.ensure().item_bounds(def_id);
}
hir::ItemKind::TyAlias(..) => {
2020-05-01 09:32:20 +00:00
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().predicates_of(def_id);
}
hir::ItemKind::Static(ty, ..) | hir::ItemKind::Const(ty, ..) => {
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().predicates_of(def_id);
if !is_suggestable_infer_ty(ty) {
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_item(it);
placeholder_type_error(tcx, None, visitor.0, false, None, it.kind.descr());
}
}
hir::ItemKind::Fn(..) => {
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().predicates_of(def_id);
tcx.ensure().fn_sig(def_id);
tcx.ensure().codegen_fn_attrs(def_id);
}
}
}
fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
let trait_item = tcx.hir().trait_item(trait_item_id);
let def_id = trait_item_id.owner_id;
tcx.ensure().generics_of(def_id);
match trait_item.kind {
2020-03-03 18:46:22 +00:00
hir::TraitItemKind::Fn(..) => {
tcx.ensure().codegen_fn_attrs(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().fn_sig(def_id);
}
hir::TraitItemKind::Const(.., Some(_)) => {
tcx.ensure().type_of(def_id);
}
hir::TraitItemKind::Const(hir_ty, _) => {
tcx.ensure().type_of(def_id);
// Account for `const C: _;`.
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_trait_item(trait_item);
if !tcx.sess.diagnostic().has_stashed_diagnostic(hir_ty.span, StashKey::ItemNoType) {
placeholder_type_error(tcx, None, visitor.0, false, None, "constant");
}
}
hir::TraitItemKind::Type(_, Some(_)) => {
tcx.ensure().item_bounds(def_id);
tcx.ensure().type_of(def_id);
// Account for `type T = _;`.
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_trait_item(trait_item);
placeholder_type_error(tcx, None, visitor.0, false, None, "associated type");
}
hir::TraitItemKind::Type(_, None) => {
tcx.ensure().item_bounds(def_id);
// #74612: Visit and try to find bad placeholders
// even if there is no concrete type.
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_trait_item(trait_item);
placeholder_type_error(tcx, None, visitor.0, false, None, "associated type");
}
};
tcx.ensure().predicates_of(def_id);
}
fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
let def_id = impl_item_id.owner_id;
2020-05-01 09:32:20 +00:00
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().predicates_of(def_id);
let impl_item = tcx.hir().impl_item(impl_item_id);
match impl_item.kind {
2020-03-05 15:57:34 +00:00
hir::ImplItemKind::Fn(..) => {
tcx.ensure().codegen_fn_attrs(def_id);
2020-05-01 09:32:20 +00:00
tcx.ensure().fn_sig(def_id);
}
hir::ImplItemKind::Type(_) => {
// Account for `type T = _;`
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_impl_item(impl_item);
placeholder_type_error(tcx, None, visitor.0, false, None, "associated type");
}
hir::ImplItemKind::Const(..) => {}
}
}
2022-10-30 09:17:16 +00:00
fn convert_variant_ctor(tcx: TyCtxt<'_>, def_id: LocalDefId) {
2020-05-01 09:32:20 +00:00
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().predicates_of(def_id);
}
2022-10-30 09:17:16 +00:00
fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
let def = tcx.adt_def(def_id);
let repr_type = def.repr().discr_type();
let initial = repr_type.initial_discriminant(tcx);
let mut prev_discr = None::<Discr<'_>>;
// fill the discriminant values and field types
2022-10-30 09:17:16 +00:00
for variant in def.variants() {
2018-01-25 15:44:45 +00:00
let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr(tcx));
2018-08-19 16:34:21 +00:00
prev_discr = Some(
2022-10-30 09:17:16 +00:00
if let ty::VariantDiscr::Explicit(const_def_id) = variant.discr {
def.eval_explicit_discr(tcx, const_def_id)
2018-08-19 16:34:21 +00:00
} else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) {
Some(discr)
} else {
2022-10-30 09:17:16 +00:00
let span = tcx.def_span(variant.def_id);
tcx.sess.emit_err(errors::EnumDiscriminantOverflowed {
span,
discr: prev_discr.unwrap().to_string(),
item_name: tcx.item_name(variant.def_id),
wrapped_discr: wrapped_discr.to_string(),
});
2018-08-19 16:34:21 +00:00
None
}
.unwrap_or(wrapped_discr),
);
2022-10-30 09:17:16 +00:00
for f in &variant.fields {
tcx.ensure().generics_of(f.did);
tcx.ensure().type_of(f.did);
tcx.ensure().predicates_of(f.did);
}
// Convert the ctor, if any. This also registers the variant as
// an item.
if let Some(ctor_def_id) = variant.ctor_def_id() {
2022-10-30 09:17:16 +00:00
convert_variant_ctor(tcx, ctor_def_id.expect_local());
}
}
}
2019-06-21 21:49:03 +00:00
fn convert_variant(
tcx: TyCtxt<'_>,
variant_did: Option<LocalDefId>,
ident: Ident,
2018-08-19 16:34:21 +00:00
discr: ty::VariantDiscr,
2019-11-29 08:26:18 +00:00
def: &hir::VariantData<'_>,
adt_kind: ty::AdtKind,
parent_did: LocalDefId,
2018-08-19 16:34:21 +00:00
) -> ty::VariantDef {
2020-04-19 11:00:18 +00:00
let mut seen_fields: FxHashMap<Ident, Span> = Default::default();
2018-08-19 16:34:21 +00:00
let fields = def
.fields()
.iter()
.map(|f| {
let dup_span = seen_fields.get(&f.ident.normalize_to_macros_2_0()).cloned();
2018-08-19 16:34:21 +00:00
if let Some(prev_span) = dup_span {
tcx.sess.emit_err(errors::FieldAlreadyDeclared {
field_name: f.ident,
span: f.span,
prev_span,
});
2018-08-19 16:34:21 +00:00
} else {
seen_fields.insert(f.ident.normalize_to_macros_2_0(), f.span);
2018-08-19 16:34:21 +00:00
}
ty::FieldDef {
did: f.def_id.to_def_id(),
name: f.ident.name,
vis: tcx.visibility(f.def_id),
}
2018-08-19 16:34:21 +00:00
})
.collect();
let recovered = match def {
hir::VariantData::Struct(_, r) => *r,
_ => false,
};
ty::VariantDef::new(
ident.name,
variant_did.map(LocalDefId::to_def_id),
def.ctor().map(|(kind, _, def_id)| (kind, def_id.to_def_id())),
discr,
fields,
adt_kind,
parent_did.to_def_id(),
recovered,
2023-03-13 18:54:05 +00:00
adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, sym::non_exhaustive)
|| variant_did
.is_some_and(|variant_did| tcx.has_attr(variant_did, sym::non_exhaustive)),
)
}
2023-03-13 18:54:05 +00:00
fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
use rustc_hir::*;
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let Node::Item(item) = tcx.hir().get(hir_id) else {
bug!();
};
let repr = tcx.repr_options_of_def(def_id.to_def_id());
let (kind, variants) = match &item.kind {
ItemKind::Enum(def, _) => {
let mut distance_from_explicit = 0;
let variants = def
.variants
.iter()
.map(|v| {
let discr = if let Some(e) = &v.disr_expr {
distance_from_explicit = 0;
2022-11-06 19:17:57 +00:00
ty::VariantDiscr::Explicit(e.def_id.to_def_id())
} else {
ty::VariantDiscr::Relative(distance_from_explicit)
};
distance_from_explicit += 1;
2019-08-14 00:40:21 +00:00
convert_variant(
tcx,
Some(v.def_id),
2019-08-14 00:40:21 +00:00
v.ident,
discr,
&v.data,
AdtKind::Enum,
def_id,
)
})
.collect();
(AdtKind::Enum, variants)
}
ItemKind::Struct(def, _) | ItemKind::Union(def, _) => {
let adt_kind = match item.kind {
ItemKind::Struct(..) => AdtKind::Struct,
_ => AdtKind::Union,
};
let variants = std::iter::once(convert_variant(
tcx,
None,
item.ident,
ty::VariantDiscr::Relative(0),
def,
adt_kind,
def_id,
))
.collect();
(adt_kind, variants)
}
2018-08-19 16:34:21 +00:00
_ => bug!(),
};
Rename many interner functions. (This is a large commit. The changes to `compiler/rustc_middle/src/ty/context.rs` are the most important ones.) The current naming scheme is a mess, with a mix of `_intern_`, `intern_` and `mk_` prefixes, with little consistency. In particular, in many cases it's easy to use an iterator interner when a (preferable) slice interner is available. The guiding principles of the new naming system: - No `_intern_` prefixes. - The `intern_` prefix is for internal operations. - The `mk_` prefix is for external operations. - For cases where there is a slice interner and an iterator interner, the former is `mk_foo` and the latter is `mk_foo_from_iter`. Also, `slice_interners!` and `direct_interners!` can now be `pub` or non-`pub`, which helps enforce the internal/external operations division. It's not perfect, but I think it's a clear improvement. The following lists show everything that was renamed. slice_interners - const_list - mk_const_list -> mk_const_list_from_iter - intern_const_list -> mk_const_list - substs - mk_substs -> mk_substs_from_iter - intern_substs -> mk_substs - check_substs -> check_and_mk_substs (this is a weird one) - canonical_var_infos - intern_canonical_var_infos -> mk_canonical_var_infos - poly_existential_predicates - mk_poly_existential_predicates -> mk_poly_existential_predicates_from_iter - intern_poly_existential_predicates -> mk_poly_existential_predicates - _intern_poly_existential_predicates -> intern_poly_existential_predicates - predicates - mk_predicates -> mk_predicates_from_iter - intern_predicates -> mk_predicates - _intern_predicates -> intern_predicates - projs - intern_projs -> mk_projs - place_elems - mk_place_elems -> mk_place_elems_from_iter - intern_place_elems -> mk_place_elems - bound_variable_kinds - mk_bound_variable_kinds -> mk_bound_variable_kinds_from_iter - intern_bound_variable_kinds -> mk_bound_variable_kinds direct_interners - region - intern_region (unchanged) - const - mk_const_internal -> intern_const - const_allocation - intern_const_alloc -> mk_const_alloc - layout - intern_layout -> mk_layout - adt_def - intern_adt_def -> mk_adt_def_from_data (unusual case, hard to avoid) - alloc_adt_def(!) -> mk_adt_def - external_constraints - intern_external_constraints -> mk_external_constraints Other - type_list - mk_type_list -> mk_type_list_from_iter - intern_type_list -> mk_type_list - tup - mk_tup -> mk_tup_from_iter - intern_tup -> mk_tup
2023-02-17 03:33:08 +00:00
tcx.mk_adt_def(def_id.to_def_id(), kind, variants, repr)
}
2023-03-13 18:54:05 +00:00
fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
let item = tcx.hir().expect_item(def_id);
let (is_auto, unsafety, items) = match item.kind {
hir::ItemKind::Trait(is_auto, unsafety, .., items) => {
(is_auto == hir::IsAuto::Yes, unsafety, items)
}
hir::ItemKind::TraitAlias(..) => (false, hir::Unsafety::Normal, &[][..]),
_ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"),
};
2013-12-19 00:05:47 +00:00
let paren_sugar = tcx.has_attr(def_id, sym::rustc_paren_sugar);
2018-02-14 15:11:02 +00:00
if paren_sugar && !tcx.features().unboxed_closures {
tcx.sess.emit_err(errors::ParenSugarAttribute { span: item.span });
}
let is_marker = tcx.has_attr(def_id, sym::marker);
2023-02-14 09:17:19 +00:00
let rustc_coinductive = tcx.has_attr(def_id, sym::rustc_coinductive);
let skip_array_during_method_dispatch =
tcx.has_attr(def_id, sym::rustc_skip_array_during_method_dispatch);
2023-02-14 09:17:19 +00:00
let specialization_kind = if tcx.has_attr(def_id, sym::rustc_unsafe_specialization_marker) {
ty::trait_def::TraitSpecializationKind::Marker
} else if tcx.has_attr(def_id, sym::rustc_specialization_trait) {
ty::trait_def::TraitSpecializationKind::AlwaysApplicable
} else {
ty::trait_def::TraitSpecializationKind::None
};
let must_implement_one_of = tcx
2022-05-02 07:31:56 +00:00
.get_attr(def_id, sym::rustc_must_implement_one_of)
// Check that there are at least 2 arguments of `#[rustc_must_implement_one_of]`
// and that they are all identifiers
.and_then(|attr| match attr.meta_item_list() {
Some(items) if items.len() < 2 => {
tcx.sess.emit_err(errors::MustImplementOneOfAttribute { span: attr.span });
None
}
Some(items) => items
.into_iter()
.map(|item| item.ident().ok_or(item.span()))
.collect::<Result<Box<[_]>, _>>()
.map_err(|span| {
tcx.sess.emit_err(errors::MustBeNameOfAssociatedFunction { span });
})
.ok()
.zip(Some(attr.span)),
// Error is reported by `rustc_attr!`
None => None,
})
// Check that all arguments of `#[rustc_must_implement_one_of]` reference
// functions in the trait with default implementations
.and_then(|(list, attr_span)| {
let errors = list.iter().filter_map(|ident| {
let item = items.iter().find(|item| item.ident == *ident);
match item {
Some(item) if matches!(item.kind, hir::AssocItemKind::Fn { .. }) => {
if !tcx.defaultness(item.id.owner_id).has_value() {
tcx.sess.emit_err(errors::FunctionNotHaveDefaultImplementation {
span: item.span,
note_span: attr_span,
});
return Some(());
}
return None;
}
Some(item) => {
tcx.sess.emit_err(errors::MustImplementNotFunction {
span: item.span,
span_note: errors::MustImplementNotFunctionSpanNote { span: attr_span },
note: errors::MustImplementNotFunctionNote {},
});
}
None => {
tcx.sess.emit_err(errors::FunctionNotFoundInTrait { span: ident.span });
}
}
Some(())
});
(errors.count() == 0).then_some(list)
})
// Check for duplicates
.and_then(|list| {
let mut set: FxHashMap<Symbol, Span> = FxHashMap::default();
let mut no_dups = true;
for ident in &*list {
if let Some(dup) = set.insert(ident.name, ident.span) {
tcx.sess
.emit_err(errors::FunctionNamesDuplicated { spans: vec![dup, ident.span] });
no_dups = false;
}
}
no_dups.then_some(list)
});
2023-06-02 05:54:52 +00:00
let do_not_implement_via_object = tcx.has_attr(def_id, sym::rustc_do_not_implement_via_object);
let deny_explicit_impl = tcx.has_attr(def_id, sym::rustc_deny_explicit_impl);
2023-02-14 09:17:19 +00:00
ty::TraitDef {
2023-03-13 18:54:05 +00:00
def_id: def_id.to_def_id(),
unsafety,
paren_sugar,
2023-02-14 09:17:19 +00:00
has_auto_impl: is_auto,
is_marker,
2023-02-14 09:17:19 +00:00
is_coinductive: rustc_coinductive || is_auto,
skip_array_during_method_dispatch,
2023-02-14 09:17:19 +00:00
specialization_kind,
must_implement_one_of,
implement_via_object,
deny_explicit_impl,
2023-02-14 09:17:19 +00:00
}
}
fn are_suggestable_generic_args(generic_args: &[hir::GenericArg<'_>]) -> bool {
2021-04-24 21:41:57 +00:00
generic_args.iter().any(|arg| match arg {
hir::GenericArg::Type(ty) => is_suggestable_infer_ty(ty),
hir::GenericArg::Infer(_) => true,
_ => false,
})
}
2020-03-06 11:13:55 +00:00
/// Whether `ty` is a type with `_` placeholders that can be inferred. Used in diagnostics only to
2019-12-27 23:45:39 +00:00
/// use inference to provide suggestions for the appropriate type if possible.
fn is_suggestable_infer_ty(ty: &hir::Ty<'_>) -> bool {
debug!(?ty);
use hir::TyKind::*;
match &ty.kind {
Infer => true,
Slice(ty) => is_suggestable_infer_ty(ty),
Array(ty, length) => {
is_suggestable_infer_ty(ty) || matches!(length, hir::ArrayLen::Infer(_, _))
}
Tup(tys) => tys.iter().any(is_suggestable_infer_ty),
Ptr(mut_ty) | Ref(_, mut_ty) => is_suggestable_infer_ty(mut_ty.ty),
2022-09-06 15:37:00 +00:00
OpaqueDef(_, generic_args, _) => are_suggestable_generic_args(generic_args),
Path(hir::QPath::TypeRelative(ty, segment)) => {
is_suggestable_infer_ty(ty) || are_suggestable_generic_args(segment.args().args)
}
Path(hir::QPath::Resolved(ty_opt, hir::Path { segments, .. })) => {
ty_opt.is_some_and(is_suggestable_infer_ty)
|| segments.iter().any(|segment| are_suggestable_generic_args(segment.args().args))
}
_ => false,
}
}
2021-12-14 01:45:08 +00:00
pub fn get_infer_ret_ty<'hir>(output: &'hir hir::FnRetTy<'hir>) -> Option<&'hir hir::Ty<'hir>> {
2021-09-30 17:38:50 +00:00
if let hir::FnRetTy::Return(ty) = output {
2019-12-27 23:45:39 +00:00
if is_suggestable_infer_ty(ty) {
2021-09-30 17:38:50 +00:00
return Some(&*ty);
}
}
None
}
2022-06-26 04:10:07 +00:00
#[instrument(level = "debug", skip(tcx))]
2023-03-13 18:54:05 +00:00
fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<'_>> {
use rustc_hir::Node::*;
use rustc_hir::*;
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
2023-03-13 19:06:41 +00:00
let icx = ItemCtxt::new(tcx, def_id);
let output = match tcx.hir().get(hir_id) {
2018-08-22 22:05:26 +00:00
TraitItem(hir::TraitItem {
2020-03-05 15:57:34 +00:00
kind: TraitItemKind::Fn(sig, TraitFn::Provided(_)),
generics,
2018-08-19 16:34:21 +00:00
..
})
| Item(hir::Item { kind: ItemKind::Fn(sig, generics, _), .. }) => {
infer_return_ty_for_fn_sig(tcx, sig, generics, def_id, &icx)
}
ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => {
// Do not try to infer the return type for a impl method coming from a trait
if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) =
2023-01-03 17:30:35 +00:00
tcx.hir().get_parent(hir_id)
&& i.of_trait.is_some()
{
icx.astconv().ty_of_fn(
hir_id,
sig.header.unsafety,
sig.header.abi,
2021-09-30 17:38:50 +00:00
sig.decl,
Some(generics),
None,
)
} else {
infer_return_ty_for_fn_sig(tcx, sig, generics, def_id, &icx)
2019-12-22 22:42:04 +00:00
}
}
TraitItem(hir::TraitItem {
Use smaller def span for functions Currently, the def span of a funtion encompasses the entire function signature and body. However, this is usually unnecessarily verbose - when we are pointing at an entire function in a diagnostic, we almost always want to point at the signature. The actual contents of the body tends to be irrelevant to the diagnostic we are emitting, and just takes up additional screen space. This commit changes the `def_span` of all function items (freestanding functions, `impl`-block methods, and `trait`-block methods) to be the span of the signature. For example, the function ```rust pub fn foo<T>(val: T) -> T { val } ``` now has a `def_span` corresponding to `pub fn foo<T>(val: T) -> T` (everything before the opening curly brace). Trait methods without a body have a `def_span` which includes the trailing semicolon. For example: ```rust trait Foo { fn bar(); }``` the function definition `Foo::bar` has a `def_span` of `fn bar();` This makes our diagnostic output much shorter, and emphasizes information that is relevant to whatever diagnostic we are reporting. We continue to use the full span (including the body) in a few of places: * MIR building uses the full span when building source scopes. * 'Outlives suggestions' use the full span to sort the diagnostics being emitted. * The `#[rustc_on_unimplemented(enclosing_scope="in this scope")]` attribute points the entire scope body. * The 'unconditional recursion' lint uses the full span to show additional context for the recursive call. All of these cases work only with local items, so we don't need to add anything extra to crate metadata.
2020-08-12 21:02:14 +00:00
kind: TraitItemKind::Fn(FnSig { header, decl, span: _ }, _),
generics,
..
}) => {
icx.astconv().ty_of_fn(hir_id, header.unsafety, header.abi, decl, Some(generics), None)
}
2018-08-19 16:34:21 +00:00
ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(fn_decl, _, _), .. }) => {
let abi = tcx.hir().get_foreign_abi(hir_id);
2023-03-13 19:06:41 +00:00
compute_sig_of_foreign_fn_decl(tcx, def_id, fn_decl, abi)
}
Ctor(data) | Variant(hir::Variant { data, .. }) if data.ctor().is_some() => {
let ty = tcx.type_of(tcx.hir().get_parent_item(hir_id)).subst_identity();
let inputs = data.fields().iter().map(|f| tcx.type_of(f.def_id).subst_identity());
ty::Binder::dummy(tcx.mk_fn_sig(
inputs,
ty,
false,
hir::Unsafety::Normal,
abi::Abi::Rust,
))
}
Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => {
// Closure signatures are not like other function
// signatures and cannot be accessed through `fn_sig`. For
// example, a closure signature excludes the `self`
// argument. In any case they are embedded within the
// closure type as part of the `ClosureSubsts`.
//
// To get the signature of a closure, you should use the
// `sig` method on the `ClosureSubsts`:
//
// substs.as_closure().sig(def_id, tcx)
bug!(
"to get the signature of a closure, use `substs.as_closure().sig()` not `fn_sig()`",
);
}
x => {
bug!("unexpected sort of node in fn_sig(): {:?}", x);
}
};
2023-05-29 11:46:10 +00:00
ty::EarlyBinder::bind(output)
}
fn infer_return_ty_for_fn_sig<'tcx>(
tcx: TyCtxt<'tcx>,
sig: &hir::FnSig<'_>,
generics: &hir::Generics<'_>,
def_id: LocalDefId,
icx: &ItemCtxt<'tcx>,
) -> ty::PolyFnSig<'tcx> {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
match get_infer_ret_ty(&sig.decl.output) {
Some(ty) => {
let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id];
// Typeck doesn't expect erased regions to be returned from `type_of`.
2022-06-27 13:55:03 +00:00
let fn_sig = tcx.fold_regions(fn_sig, |r, _| match *r {
ty::ReErased => tcx.lifetimes.re_static,
_ => r,
});
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_ty(ty);
let mut diag = bad_placeholder(tcx, visitor.0, "return type");
2022-12-27 23:56:46 +00:00
let ret_ty = fn_sig.output();
// Don't leak types into signatures unless they're nameable!
// For example, if a function returns itself, we don't want that
// recursive function definition to leak out into the fn sig.
let mut should_recover = false;
if let Some(ret_ty) = ret_ty.make_suggestable(tcx, false) {
diag.span_suggestion(
ty.span,
"replace with the correct return type",
ret_ty,
Applicability::MachineApplicable,
);
should_recover = true;
2023-03-22 09:36:30 +00:00
} else if let Some(sugg) = suggest_impl_trait(tcx, ret_ty, ty.span, def_id) {
2022-12-27 23:56:46 +00:00
diag.span_suggestion(
ty.span,
"replace with an appropriate return type",
sugg,
Applicability::MachineApplicable,
);
} else if ret_ty.is_closure() {
diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound");
2023-01-04 00:26:53 +00:00
}
// Also note how `Fn` traits work just in case!
if ret_ty.is_closure() {
diag.note(
"for more information on `Fn` traits and closure types, see \
https://doc.rust-lang.org/book/ch13-01-closures.html",
);
}
let guar = diag.emit();
if should_recover {
ty::Binder::dummy(fn_sig)
} else {
ty::Binder::dummy(tcx.mk_fn_sig(
fn_sig.inputs().iter().copied(),
tcx.ty_error(guar),
fn_sig.c_variadic,
fn_sig.unsafety,
fn_sig.abi,
))
}
}
None => icx.astconv().ty_of_fn(
hir_id,
sig.header.unsafety,
sig.header.abi,
sig.decl,
Some(generics),
None,
),
}
}
2022-12-27 23:56:46 +00:00
fn suggest_impl_trait<'tcx>(
tcx: TyCtxt<'tcx>,
ret_ty: Ty<'tcx>,
span: Span,
def_id: LocalDefId,
2022-12-27 23:56:46 +00:00
) -> Option<String> {
let format_as_assoc: fn(_, _, _, _, _) -> _ =
|tcx: TyCtxt<'tcx>,
_: ty::SubstsRef<'tcx>,
trait_def_id: DefId,
assoc_item_def_id: DefId,
item_ty: Ty<'tcx>| {
let trait_name = tcx.item_name(trait_def_id);
let assoc_name = tcx.item_name(assoc_item_def_id);
Some(format!("impl {trait_name}<{assoc_name} = {item_ty}>"))
};
let format_as_parenthesized: fn(_, _, _, _, _) -> _ =
|tcx: TyCtxt<'tcx>,
substs: ty::SubstsRef<'tcx>,
trait_def_id: DefId,
_: DefId,
item_ty: Ty<'tcx>| {
let trait_name = tcx.item_name(trait_def_id);
let args_tuple = substs.type_at(1);
let ty::Tuple(types) = *args_tuple.kind() else { return None; };
let types = types.make_suggestable(tcx, false)?;
2022-12-27 23:56:46 +00:00
let maybe_ret =
if item_ty.is_unit() { String::new() } else { format!(" -> {item_ty}") };
Some(format!(
"impl {trait_name}({}){maybe_ret}",
types.iter().map(|ty| ty.to_string()).collect::<Vec<_>>().join(", ")
))
};
for (trait_def_id, assoc_item_def_id, formatter) in [
(
tcx.get_diagnostic_item(sym::Iterator),
tcx.get_diagnostic_item(sym::IteratorItem),
format_as_assoc,
),
(
tcx.lang_items().future_trait(),
tcx.get_diagnostic_item(sym::FutureOutput),
format_as_assoc,
),
(tcx.lang_items().fn_trait(), tcx.lang_items().fn_once_output(), format_as_parenthesized),
(
tcx.lang_items().fn_mut_trait(),
tcx.lang_items().fn_once_output(),
format_as_parenthesized,
),
(
tcx.lang_items().fn_once_trait(),
tcx.lang_items().fn_once_output(),
format_as_parenthesized,
),
] {
let Some(trait_def_id) = trait_def_id else { continue; };
let Some(assoc_item_def_id) = assoc_item_def_id else { continue; };
if tcx.def_kind(assoc_item_def_id) != DefKind::AssocTy {
continue;
}
let param_env = tcx.param_env(def_id);
let infcx = tcx.infer_ctxt().build();
let substs = ty::InternalSubsts::for_item(tcx, trait_def_id, |param, _| {
if param.index == 0 { ret_ty.into() } else { infcx.var_for_def(span, param) }
});
if !infcx.type_implements_trait(trait_def_id, substs, param_env).must_apply_modulo_regions()
{
continue;
}
let ocx = ObligationCtxt::new_in_snapshot(&infcx);
let item_ty = ocx.normalize(
&ObligationCause::misc(span, def_id),
2022-12-27 23:56:46 +00:00
param_env,
tcx.mk_projection(assoc_item_def_id, substs),
);
// FIXME(compiler-errors): We may benefit from resolving regions here.
if ocx.select_where_possible().is_empty()
&& let item_ty = infcx.resolve_vars_if_possible(item_ty)
&& let Some(item_ty) = item_ty.make_suggestable(tcx, false)
2022-12-27 23:56:46 +00:00
&& let Some(sugg) = formatter(tcx, infcx.resolve_vars_if_possible(substs), trait_def_id, assoc_item_def_id, item_ty)
{
return Some(sugg);
}
}
None
}
2023-03-13 18:54:05 +00:00
fn impl_trait_ref(
tcx: TyCtxt<'_>,
def_id: LocalDefId,
) -> Option<ty::EarlyBinder<ty::TraitRef<'_>>> {
2023-03-13 19:06:41 +00:00
let icx = ItemCtxt::new(tcx, def_id);
2023-03-13 18:54:05 +00:00
let impl_ = tcx.hir().expect_item(def_id).expect_impl();
impl_
.of_trait
.as_ref()
.map(|ast_trait_ref| {
let selfty = tcx.type_of(def_id).subst_identity();
icx.astconv().instantiate_mono_trait_ref(
ast_trait_ref,
selfty,
check_impl_constness(tcx, impl_.constness, ast_trait_ref),
)
})
2023-05-29 11:46:10 +00:00
.map(ty::EarlyBinder::bind)
}
fn check_impl_constness(
tcx: TyCtxt<'_>,
constness: hir::Constness,
ast_trait_ref: &hir::TraitRef<'_>,
) -> ty::BoundConstness {
match constness {
hir::Constness::Const => {
if let Some(trait_def_id) = ast_trait_ref.trait_def_id() && !tcx.has_attr(trait_def_id, sym::const_trait) {
let trait_name = tcx.item_name(trait_def_id).to_string();
tcx.sess.emit_err(errors::ConstImplForNonConstTrait {
trait_ref_span: ast_trait_ref.path.span,
trait_name,
local_trait_span: trait_def_id.as_local().map(|_| tcx.def_span(trait_def_id).shrink_to_lo()),
marking: (),
adding: (),
});
ty::BoundConstness::NotConst
} else {
ty::BoundConstness::ConstIfConst
}
},
hir::Constness::NotConst => ty::BoundConstness::NotConst,
}
}
2023-03-13 18:54:05 +00:00
fn impl_polarity(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::ImplPolarity {
let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl);
2023-03-13 18:54:05 +00:00
let item = tcx.hir().expect_item(def_id);
2019-09-26 16:51:36 +00:00
match &item.kind {
hir::ItemKind::Impl(hir::Impl {
polarity: hir::ImplPolarity::Negative(span),
of_trait,
..
}) => {
if is_rustc_reservation {
let span = span.to(of_trait.as_ref().map_or(*span, |t| t.path.span));
tcx.sess.span_err(span, "reservation impls can't be negative");
}
ty::ImplPolarity::Negative
}
hir::ItemKind::Impl(hir::Impl {
polarity: hir::ImplPolarity::Positive,
of_trait: None,
..
}) => {
if is_rustc_reservation {
tcx.sess.span_err(item.span, "reservation impls can't be inherent");
}
ty::ImplPolarity::Positive
}
hir::ItemKind::Impl(hir::Impl {
polarity: hir::ImplPolarity::Positive,
of_trait: Some(_),
..
}) => {
if is_rustc_reservation {
ty::ImplPolarity::Reservation
} else {
ty::ImplPolarity::Positive
}
}
item => bug!("impl_polarity: {:?} not an impl", item),
}
}
/// Returns the early-bound lifetimes declared in this generics
2019-02-08 13:53:55 +00:00
/// listing. For anything other than fns/methods, this is just all
/// the lifetimes that are declared. For fns or methods, we have to
/// screen out those that do not appear in any where-clauses etc using
/// `resolve_lifetime::early_bound_lifetimes`.
fn early_bound_lifetimes_from_generics<'a, 'tcx: 'a>(
2019-06-13 21:48:52 +00:00
tcx: TyCtxt<'tcx>,
2019-12-01 15:08:58 +00:00
generics: &'a hir::Generics<'a>,
) -> impl Iterator<Item = &'a hir::GenericParam<'a>> + Captures<'tcx> {
2018-08-19 16:34:21 +00:00
generics.params.iter().filter(move |param| match param.kind {
GenericParamKind::Lifetime { .. } => !tcx.is_late_bound(param.hir_id),
2018-08-19 16:34:21 +00:00
_ => false,
})
}
2019-02-08 13:53:55 +00:00
/// Returns a list of type predicates for the definition with ID `def_id`, including inferred
/// lifetime constraints. This includes all predicates returned by `explicit_predicates_of`, plus
/// inferred constraints concerning which regions outlive other regions.
2022-06-26 04:10:07 +00:00
#[instrument(level = "debug", skip(tcx))]
fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
let mut result = tcx.explicit_predicates_of(def_id);
debug!("predicates_defined_on: explicit_predicates_of({:?}) = {:?}", def_id, result,);
let inferred_outlives = tcx.inferred_outlives_of(def_id);
if !inferred_outlives.is_empty() {
debug!(
"predicates_defined_on: inferred_outlives_of({:?}) = {:?}",
def_id, inferred_outlives,
);
let inferred_outlives_iter =
inferred_outlives.iter().map(|(clause, span)| ((*clause).to_predicate(tcx), *span));
if result.predicates.is_empty() {
result.predicates = tcx.arena.alloc_from_iter(inferred_outlives_iter);
} else {
result.predicates = tcx.arena.alloc_from_iter(
result.predicates.into_iter().copied().chain(inferred_outlives_iter),
);
}
2017-09-26 04:36:38 +00:00
}
2019-01-04 13:27:55 +00:00
debug!("predicates_defined_on({:?}) = {:?}", def_id, result);
result
2017-09-23 18:55:40 +00:00
}
fn compute_sig_of_foreign_fn_decl<'tcx>(
2019-06-13 21:48:52 +00:00
tcx: TyCtxt<'tcx>,
2023-03-13 19:06:41 +00:00
def_id: LocalDefId,
2019-12-01 15:08:58 +00:00
decl: &'tcx hir::FnDecl<'tcx>,
2018-08-19 16:34:21 +00:00
abi: abi::Abi,
) -> ty::PolyFnSig<'tcx> {
let unsafety = if abi == abi::Abi::RustIntrinsic {
2023-03-13 19:06:41 +00:00
intrinsic_operation_unsafety(tcx, def_id.to_def_id())
} else {
hir::Unsafety::Unsafe
};
2023-03-13 19:06:41 +00:00
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let fty =
ItemCtxt::new(tcx, def_id).astconv().ty_of_fn(hir_id, unsafety, abi, decl, None, None);
// Feature gate SIMD types in FFI, since I am not sure that the
// ABIs are handled at all correctly. -huonw
2018-08-19 16:34:21 +00:00
if abi != abi::Abi::RustIntrinsic
&& abi != abi::Abi::PlatformIntrinsic
&& !tcx.features().simd_ffi
{
2019-12-01 15:08:58 +00:00
let check = |ast_ty: &hir::Ty<'_>, ty: Ty<'_>| {
if ty.is_simd() {
let snip = tcx
.sess
.source_map()
.span_to_snippet(ast_ty.span)
2021-02-23 22:02:05 +00:00
.map_or_else(|_| String::new(), |s| format!(" `{}`", s));
tcx.sess.emit_err(errors::SIMDFFIHighlyExperimental { span: ast_ty.span, snip });
}
};
2021-03-08 23:32:41 +00:00
for (input, ty) in iter::zip(decl.inputs, fty.inputs().skip_binder()) {
2022-01-25 03:13:38 +00:00
check(input, *ty)
}
if let hir::FnRetTy::Return(ty) = decl.output {
2021-09-30 17:38:50 +00:00
check(ty, fty.output().skip_binder())
}
}
fty
}
2023-03-13 18:54:05 +00:00
fn generator_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<hir::GeneratorKind> {
match tcx.hir().get_by_def_id(def_id) {
Node::Expr(&rustc_hir::Expr {
kind: rustc_hir::ExprKind::Closure(&rustc_hir::Closure { body, .. }),
2020-02-08 22:33:50 +00:00
..
2023-03-13 18:54:05 +00:00
}) => tcx.hir().body(body).generator_kind(),
_ => None,
2020-01-26 01:09:23 +00:00
}
}
2023-03-13 18:54:05 +00:00
fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
match tcx.hir().get_by_def_id(def_id) {
Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(opaque), .. }) => {
matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. })
}
2023-03-13 18:54:05 +00:00
_ => bug!("tried getting opaque_ty_origin for non-opaque: {:?}", def_id),
}
}