-// ignore-tidy-filelength
-
//! "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
use rustc::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc::mir::mono::Linkage;
use rustc::session::parse::feature_err;
-use rustc::traits;
use rustc::ty::query::Providers;
-use rustc::ty::subst::GenericArgKind;
use rustc::ty::subst::{InternalSubsts, Subst};
use rustc::ty::util::Discr;
use rustc::ty::util::IntTypeExt;
-use rustc::ty::{self, AdtKind, Const, DefIdTree, ToPolyTraitRef, Ty, TyCtxt, WithConstness};
-use rustc::ty::{ReprOptions, ToPredicate};
+use rustc::ty::{self, AdtKind, Const, ToPolyTraitRef, Ty, TyCtxt};
+use rustc::ty::{ReprOptions, ToPredicate, WithConstness};
use rustc_attr::{list_contains_name, mark_used, InlineAttr, OptimizeAttr};
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{struct_span_err, Applicability, StashKey};
+use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use syntax::ast;
use syntax::ast::{Ident, MetaItemKind};
+mod type_of;
+
struct OnlySelfBounds(bool);
///////////////////////////////////////////////////////////////////////////
pub fn provide(providers: &mut Providers<'_>) {
*providers = Providers {
- type_of,
+ type_of: type_of::type_of,
generics_of,
predicates_of,
predicates_defined_on,
Some(self.item_def_id)
}
- fn default_constness_for_trait_bounds(&self) -> ast::Constness {
+ fn default_constness_for_trait_bounds(&self) -> hir::Constness {
if let Some(fn_like) = FnLikeNode::from_node(self.node()) {
fn_like.constness()
} else {
- ast::Constness::NotConst
+ hir::Constness::NotConst
}
}
})
}
-fn report_assoc_ty_on_inherent_impl(tcx: TyCtxt<'_>, span: Span) {
- struct_span_err!(
- tcx.sess,
- span,
- E0202,
- "associated types are not yet supported in inherent impls (see #8995)"
- )
- .emit();
-}
-
-fn infer_placeholder_type(
- tcx: TyCtxt<'_>,
- def_id: DefId,
- body_id: hir::BodyId,
- span: Span,
- item_ident: Ident,
-) -> Ty<'_> {
- let ty = tcx.diagnostic_only_typeck_tables_of(def_id).node_type(body_id.hir_id);
-
- // If this came from a free `const` or `static mut?` item,
- // then the user may have written e.g. `const A = 42;`.
- // In this case, the parser has stashed a diagnostic for
- // us to improve in typeck so we do that now.
- match tcx.sess.diagnostic().steal_diagnostic(span, StashKey::ItemNoType) {
- Some(mut err) => {
- // The parser provided a sub-optimal `HasPlaceholders` suggestion for the type.
- // We are typeck and have the real type, so remove that and suggest the actual type.
- err.suggestions.clear();
- err.span_suggestion(
- span,
- "provide a type for the item",
- format!("{}: {}", item_ident, ty),
- Applicability::MachineApplicable,
- )
- .emit();
- }
- None => {
- let mut diag = bad_placeholder_type(tcx, vec![span]);
- if ty != tcx.types.err {
- diag.span_suggestion(
- span,
- "replace `_` with the correct type",
- ty.to_string(),
- Applicability::MaybeIncorrect,
- );
- }
- diag.emit();
- }
- }
-
- ty
-}
-
-fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
- use rustc_hir::*;
-
- let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
-
- let icx = ItemCtxt::new(tcx, def_id);
-
- match tcx.hir().get(hir_id) {
- Node::TraitItem(item) => match item.kind {
- TraitItemKind::Method(..) => {
- let substs = InternalSubsts::identity_for_item(tcx, def_id);
- tcx.mk_fn_def(def_id, substs)
- }
- TraitItemKind::Const(ref ty, body_id) => body_id
- .and_then(|body_id| {
- if is_suggestable_infer_ty(ty) {
- Some(infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident))
- } else {
- None
- }
- })
- .unwrap_or_else(|| icx.to_ty(ty)),
- TraitItemKind::Type(_, Some(ref ty)) => icx.to_ty(ty),
- TraitItemKind::Type(_, None) => {
- span_bug!(item.span, "associated type missing default");
- }
- },
-
- Node::ImplItem(item) => match item.kind {
- ImplItemKind::Method(..) => {
- let substs = InternalSubsts::identity_for_item(tcx, def_id);
- tcx.mk_fn_def(def_id, substs)
- }
- ImplItemKind::Const(ref ty, body_id) => {
- if is_suggestable_infer_ty(ty) {
- infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident)
- } else {
- icx.to_ty(ty)
- }
- }
- ImplItemKind::OpaqueTy(_) => {
- if tcx.impl_trait_ref(tcx.hir().get_parent_did(hir_id)).is_none() {
- report_assoc_ty_on_inherent_impl(tcx, item.span);
- }
-
- find_opaque_ty_constraints(tcx, def_id)
- }
- ImplItemKind::TyAlias(ref ty) => {
- if tcx.impl_trait_ref(tcx.hir().get_parent_did(hir_id)).is_none() {
- report_assoc_ty_on_inherent_impl(tcx, item.span);
- }
-
- icx.to_ty(ty)
- }
- },
-
- Node::Item(item) => {
- match item.kind {
- ItemKind::Static(ref ty, .., body_id) | ItemKind::Const(ref ty, body_id) => {
- if is_suggestable_infer_ty(ty) {
- infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident)
- } else {
- icx.to_ty(ty)
- }
- }
- ItemKind::TyAlias(ref self_ty, _) | ItemKind::Impl { ref self_ty, .. } => {
- icx.to_ty(self_ty)
- }
- ItemKind::Fn(..) => {
- let substs = InternalSubsts::identity_for_item(tcx, def_id);
- tcx.mk_fn_def(def_id, substs)
- }
- ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => {
- let def = tcx.adt_def(def_id);
- let substs = InternalSubsts::identity_for_item(tcx, def_id);
- tcx.mk_adt(def, substs)
- }
- ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: None, .. }) => {
- find_opaque_ty_constraints(tcx, def_id)
- }
- // Opaque types desugared from `impl Trait`.
- ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(owner), .. }) => {
- tcx.typeck_tables_of(owner)
- .concrete_opaque_types
- .get(&def_id)
- .map(|opaque| opaque.concrete_type)
- .unwrap_or_else(|| {
- // This can occur if some error in the
- // owner fn prevented us from populating
- // the `concrete_opaque_types` table.
- tcx.sess.delay_span_bug(
- DUMMY_SP,
- &format!(
- "owner {:?} has no opaque type for {:?} in its tables",
- owner, def_id,
- ),
- );
- tcx.types.err
- })
- }
- ItemKind::Trait(..)
- | ItemKind::TraitAlias(..)
- | ItemKind::Mod(..)
- | ItemKind::ForeignMod(..)
- | ItemKind::GlobalAsm(..)
- | ItemKind::ExternCrate(..)
- | ItemKind::Use(..) => {
- span_bug!(
- item.span,
- "compute_type_of_item: unexpected item type: {:?}",
- item.kind
- );
- }
- }
- }
-
- Node::ForeignItem(foreign_item) => match foreign_item.kind {
- ForeignItemKind::Fn(..) => {
- let substs = InternalSubsts::identity_for_item(tcx, def_id);
- tcx.mk_fn_def(def_id, substs)
- }
- ForeignItemKind::Static(ref t, _) => icx.to_ty(t),
- ForeignItemKind::Type => tcx.mk_foreign(def_id),
- },
-
- Node::Ctor(&ref def) | Node::Variant(hir::Variant { data: ref def, .. }) => match *def {
- VariantData::Unit(..) | VariantData::Struct(..) => {
- tcx.type_of(tcx.hir().get_parent_did(hir_id))
- }
- VariantData::Tuple(..) => {
- let substs = InternalSubsts::identity_for_item(tcx, def_id);
- tcx.mk_fn_def(def_id, substs)
- }
- },
-
- Node::Field(field) => icx.to_ty(&field.ty),
-
- Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(.., gen), .. }) => {
- if gen.is_some() {
- return tcx.typeck_tables_of(def_id).node_type(hir_id);
- }
-
- let substs = InternalSubsts::identity_for_item(tcx, def_id);
- tcx.mk_closure(def_id, substs)
- }
-
- Node::AnonConst(_) => {
- let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
- match parent_node {
- Node::Ty(&hir::Ty { kind: hir::TyKind::Array(_, ref constant), .. })
- | Node::Ty(&hir::Ty { kind: hir::TyKind::Typeof(ref constant), .. })
- | Node::Expr(&hir::Expr { kind: ExprKind::Repeat(_, ref constant), .. })
- if constant.hir_id == hir_id =>
- {
- tcx.types.usize
- }
-
- Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => {
- tcx.adt_def(tcx.hir().get_parent_did(hir_id)).repr.discr_type().to_ty(tcx)
- }
-
- Node::Ty(&hir::Ty { kind: hir::TyKind::Path(_), .. })
- | Node::Expr(&hir::Expr { kind: ExprKind::Struct(..), .. })
- | Node::Expr(&hir::Expr { kind: ExprKind::Path(_), .. })
- | Node::TraitRef(..) => {
- let path = match parent_node {
- Node::Ty(&hir::Ty {
- kind: hir::TyKind::Path(QPath::Resolved(_, ref path)),
- ..
- })
- | Node::Expr(&hir::Expr {
- kind: ExprKind::Path(QPath::Resolved(_, ref path)),
- ..
- }) => Some(&**path),
- Node::Expr(&hir::Expr { kind: ExprKind::Struct(ref path, ..), .. }) => {
- if let QPath::Resolved(_, ref path) = **path {
- Some(&**path)
- } else {
- None
- }
- }
- Node::TraitRef(&hir::TraitRef { ref path, .. }) => Some(&**path),
- _ => None,
- };
-
- if let Some(path) = path {
- let arg_index = path
- .segments
- .iter()
- .filter_map(|seg| seg.args.as_ref())
- .map(|generic_args| generic_args.args.as_ref())
- .find_map(|args| {
- args.iter()
- .filter(|arg| arg.is_const())
- .enumerate()
- .filter(|(_, arg)| arg.id() == hir_id)
- .map(|(index, _)| index)
- .next()
- })
- .unwrap_or_else(|| {
- bug!("no arg matching AnonConst in path");
- });
-
- // We've encountered an `AnonConst` in some path, so we need to
- // figure out which generic parameter it corresponds to and return
- // the relevant type.
- let generics = match path.res {
- Res::Def(DefKind::Ctor(..), def_id) => {
- tcx.generics_of(tcx.parent(def_id).unwrap())
- }
- Res::Def(_, def_id) => tcx.generics_of(def_id),
- Res::Err => return tcx.types.err,
- res => {
- tcx.sess.delay_span_bug(
- DUMMY_SP,
- &format!("unexpected const parent path def {:?}", res,),
- );
- return tcx.types.err;
- }
- };
-
- generics
- .params
- .iter()
- .filter(|param| {
- if let ty::GenericParamDefKind::Const = param.kind {
- true
- } else {
- false
- }
- })
- .nth(arg_index)
- .map(|param| tcx.type_of(param.def_id))
- // This is no generic parameter associated with the arg. This is
- // probably from an extra arg where one is not needed.
- .unwrap_or(tcx.types.err)
- } else {
- tcx.sess.delay_span_bug(
- DUMMY_SP,
- &format!("unexpected const parent path {:?}", parent_node,),
- );
- return tcx.types.err;
- }
- }
-
- x => {
- tcx.sess.delay_span_bug(
- DUMMY_SP,
- &format!("unexpected const parent in type_of_def_id(): {:?}", x),
- );
- tcx.types.err
- }
- }
- }
-
- Node::GenericParam(param) => match ¶m.kind {
- hir::GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty),
- hir::GenericParamKind::Const { ty: ref hir_ty, .. } => {
- let ty = icx.to_ty(hir_ty);
- if !tcx.features().const_compare_raw_pointers {
- let err = match ty.peel_refs().kind {
- ty::FnPtr(_) => Some("function pointers"),
- ty::RawPtr(_) => Some("raw pointers"),
- _ => None,
- };
- if let Some(unsupported_type) = err {
- feature_err(
- &tcx.sess.parse_sess,
- sym::const_compare_raw_pointers,
- hir_ty.span,
- &format!(
- "using {} as const generic parameters is unstable",
- unsupported_type
- ),
- )
- .emit();
- };
- }
- if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty)
- .is_some()
- {
- struct_span_err!(
- tcx.sess,
- hir_ty.span,
- E0741,
- "the types of const generic parameters must derive `PartialEq` and `Eq`",
- )
- .span_label(
- hir_ty.span,
- format!("`{}` doesn't derive both `PartialEq` and `Eq`", ty),
- )
- .emit();
- }
- ty
- }
- x => bug!("unexpected non-type Node::GenericParam: {:?}", x),
- },
-
- x => {
- bug!("unexpected sort of node in type_of_def_id(): {:?}", x);
- }
- }
-}
-
-fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
- use rustc_hir::{ImplItem, Item, TraitItem};
-
- debug!("find_opaque_ty_constraints({:?})", def_id);
-
- struct ConstraintLocator<'tcx> {
- tcx: TyCtxt<'tcx>,
- def_id: DefId,
- // (first found type span, actual type, mapping from the opaque type's generic
- // parameters to the concrete type's generic parameters)
- //
- // The mapping is an index for each use site of a generic parameter in the concrete type
- //
- // The indices index into the generic parameters on the opaque type.
- found: Option<(Span, Ty<'tcx>, Vec<usize>)>,
- }
-
- impl ConstraintLocator<'tcx> {
- fn check(&mut self, def_id: DefId) {
- // Don't try to check items that cannot possibly constrain the type.
- if !self.tcx.has_typeck_tables(def_id) {
- debug!(
- "find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`: no tables",
- self.def_id, def_id,
- );
- return;
- }
- let ty = self.tcx.typeck_tables_of(def_id).concrete_opaque_types.get(&self.def_id);
- if let Some(ty::ResolvedOpaqueTy { concrete_type, substs }) = ty {
- debug!(
- "find_opaque_ty_constraints: found constraint for `{:?}` at `{:?}`: {:?}",
- self.def_id, def_id, ty,
- );
-
- // FIXME(oli-obk): trace the actual span from inference to improve errors.
- let span = self.tcx.def_span(def_id);
- // used to quickly look up the position of a generic parameter
- let mut index_map: FxHashMap<ty::ParamTy, usize> = FxHashMap::default();
- // Skipping binder is ok, since we only use this to find generic parameters and
- // their positions.
- for (idx, subst) in substs.iter().enumerate() {
- if let GenericArgKind::Type(ty) = subst.unpack() {
- if let ty::Param(p) = ty.kind {
- if index_map.insert(p, idx).is_some() {
- // There was already an entry for `p`, meaning a generic parameter
- // was used twice.
- self.tcx.sess.span_err(
- span,
- &format!(
- "defining opaque type use restricts opaque \
- type by using the generic parameter `{}` twice",
- p,
- ),
- );
- return;
- }
- } else {
- self.tcx.sess.delay_span_bug(
- span,
- &format!(
- "non-defining opaque ty use in defining scope: {:?}, {:?}",
- concrete_type, substs,
- ),
- );
- }
- }
- }
- // Compute the index within the opaque type for each generic parameter used in
- // the concrete type.
- let indices = concrete_type
- .subst(self.tcx, substs)
- .walk()
- .filter_map(|t| match &t.kind {
- ty::Param(p) => Some(*index_map.get(p).unwrap()),
- _ => None,
- })
- .collect();
- let is_param = |ty: Ty<'_>| match ty.kind {
- ty::Param(_) => true,
- _ => false,
- };
- let bad_substs: Vec<_> = substs
- .iter()
- .enumerate()
- .filter_map(|(i, k)| {
- if let GenericArgKind::Type(ty) = k.unpack() { Some((i, ty)) } else { None }
- })
- .filter(|(_, ty)| !is_param(ty))
- .collect();
-
- if !bad_substs.is_empty() {
- let identity_substs = InternalSubsts::identity_for_item(self.tcx, self.def_id);
- for (i, bad_subst) in bad_substs {
- self.tcx.sess.span_err(
- span,
- &format!(
- "defining opaque type use does not fully define opaque type: \
- generic parameter `{}` is specified as concrete type `{}`",
- identity_substs.type_at(i),
- bad_subst
- ),
- );
- }
- } else if let Some((prev_span, prev_ty, ref prev_indices)) = self.found {
- let mut ty = concrete_type.walk().fuse();
- let mut p_ty = prev_ty.walk().fuse();
- let iter_eq = (&mut ty).zip(&mut p_ty).all(|(t, p)| match (&t.kind, &p.kind) {
- // Type parameters are equal to any other type parameter for the purpose of
- // concrete type equality, as it is possible to obtain the same type just
- // by passing matching parameters to a function.
- (ty::Param(_), ty::Param(_)) => true,
- _ => t == p,
- });
- if !iter_eq || ty.next().is_some() || p_ty.next().is_some() {
- debug!("find_opaque_ty_constraints: span={:?}", span);
- // Found different concrete types for the opaque type.
- let mut err = self.tcx.sess.struct_span_err(
- span,
- "concrete type differs from previous defining opaque type use",
- );
- err.span_label(
- span,
- format!("expected `{}`, got `{}`", prev_ty, concrete_type),
- );
- err.span_note(prev_span, "previous use here");
- err.emit();
- } else if indices != *prev_indices {
- // Found "same" concrete types, but the generic parameter order differs.
- let mut err = self.tcx.sess.struct_span_err(
- span,
- "concrete type's generic parameters differ from previous defining use",
- );
- use std::fmt::Write;
- let mut s = String::new();
- write!(s, "expected [").unwrap();
- let list = |s: &mut String, indices: &Vec<usize>| {
- let mut indices = indices.iter().cloned();
- if let Some(first) = indices.next() {
- write!(s, "`{}`", substs[first]).unwrap();
- for i in indices {
- write!(s, ", `{}`", substs[i]).unwrap();
- }
- }
- };
- list(&mut s, prev_indices);
- write!(s, "], got [").unwrap();
- list(&mut s, &indices);
- write!(s, "]").unwrap();
- err.span_label(span, s);
- err.span_note(prev_span, "previous use here");
- err.emit();
- }
- } else {
- self.found = Some((span, concrete_type, indices));
- }
- } else {
- debug!(
- "find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`",
- self.def_id, def_id,
- );
- }
- }
- }
-
- impl<'tcx> intravisit::Visitor<'tcx> for ConstraintLocator<'tcx> {
- type Map = Map<'tcx>;
-
- fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<'_, Self::Map> {
- intravisit::NestedVisitorMap::All(&self.tcx.hir())
- }
- fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
- debug!("find_existential_constraints: visiting {:?}", it);
- let def_id = self.tcx.hir().local_def_id(it.hir_id);
- // The opaque type itself or its children are not within its reveal scope.
- if def_id != self.def_id {
- self.check(def_id);
- intravisit::walk_item(self, it);
- }
- }
- fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
- debug!("find_existential_constraints: visiting {:?}", it);
- let def_id = self.tcx.hir().local_def_id(it.hir_id);
- // The opaque type itself or its children are not within its reveal scope.
- if def_id != self.def_id {
- self.check(def_id);
- intravisit::walk_impl_item(self, it);
- }
- }
- fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
- debug!("find_existential_constraints: visiting {:?}", it);
- let def_id = self.tcx.hir().local_def_id(it.hir_id);
- self.check(def_id);
- intravisit::walk_trait_item(self, it);
- }
- }
-
- let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
- let scope = tcx.hir().get_defining_scope(hir_id);
- let mut locator = ConstraintLocator { def_id, tcx, found: None };
-
- debug!("find_opaque_ty_constraints: scope={:?}", scope);
-
- if scope == hir::CRATE_HIR_ID {
- intravisit::walk_crate(&mut locator, tcx.hir().krate());
- } else {
- debug!("find_opaque_ty_constraints: scope={:?}", tcx.hir().get(scope));
- match tcx.hir().get(scope) {
- // We explicitly call `visit_*` methods, instead of using `intravisit::walk_*` methods
- // This allows our visitor to process the defining item itself, causing
- // it to pick up any 'sibling' defining uses.
- //
- // For example, this code:
- // ```
- // fn foo() {
- // type Blah = impl Debug;
- // let my_closure = || -> Blah { true };
- // }
- // ```
- //
- // requires us to explicitly process `foo()` in order
- // to notice the defining usage of `Blah`.
- Node::Item(ref it) => locator.visit_item(it),
- Node::ImplItem(ref it) => locator.visit_impl_item(it),
- Node::TraitItem(ref it) => locator.visit_trait_item(it),
- other => bug!("{:?} is not a valid scope for an opaque type item", other),
- }
- }
-
- match locator.found {
- Some((_, ty, _)) => ty,
- None => {
- let span = tcx.def_span(def_id);
- tcx.sess.span_err(span, "could not find defining uses");
- tcx.types.err
- }
- }
-}
-
fn are_suggestable_generic_args(generic_args: &[hir::GenericArg<'_>]) -> bool {
generic_args
.iter()
match bound {
&hir::GenericBound::Trait(ref poly_trait_ref, modifier) => {
let constness = match modifier {
- hir::TraitBoundModifier::MaybeConst => ast::Constness::NotConst,
+ hir::TraitBoundModifier::MaybeConst => hir::Constness::NotConst,
hir::TraitBoundModifier::None => constness,
hir::TraitBoundModifier::Maybe => bug!("this wasn't handled"),
};
astconv: &dyn AstConv<'tcx>,
param_ty: Ty<'tcx>,
bound: &'tcx hir::GenericBound<'tcx>,
- constness: ast::Constness,
+ constness: hir::Constness,
) -> Vec<(ty::Predicate<'tcx>, Span)> {
match *bound {
hir::GenericBound::Trait(ref tr, modifier) => {
let constness = match modifier {
hir::TraitBoundModifier::Maybe => return vec![],
- hir::TraitBoundModifier::MaybeConst => ast::Constness::NotConst,
+ hir::TraitBoundModifier::MaybeConst => hir::Constness::NotConst,
hir::TraitBoundModifier::None => constness,
};