Skip to content

Move some queries from rustc::ty to librustc_ty. #67780

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 16, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
@@ -3642,6 +3642,7 @@ dependencies = [
"rustc_span",
"rustc_target",
"rustc_traits",
"rustc_ty",
"rustc_typeck",
"serialize",
"smallvec 1.0.0",
@@ -3918,6 +3919,17 @@ dependencies = [
"syntax",
]

[[package]]
name = "rustc_ty"
version = "0.0.0"
dependencies = [
"log",
"rustc",
"rustc_data_structures",
"rustc_hir",
"rustc_span",
]

[[package]]
name = "rustc_typeck"
version = "0.0.0"
356 changes: 2 additions & 354 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
@@ -18,7 +18,6 @@ use crate::middle::resolve_lifetime::ObjectLifetimeDefault;
use crate::mir::interpret::ErrorHandled;
use crate::mir::GeneratorLayout;
use crate::mir::ReadOnlyBodyAndCache;
use crate::session::CrateDisambiguator;
use crate::session::DataTypeKind;
use crate::traits::{self, Reveal};
use crate::ty;
@@ -31,7 +30,6 @@ use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::svh::Svh;
use rustc_data_structures::sync::{self, par_iter, Lrc, ParallelIterator};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
@@ -2423,70 +2421,6 @@ impl<'tcx> AdtDef {
pub fn sized_constraint(&self, tcx: TyCtxt<'tcx>) -> &'tcx [Ty<'tcx>] {
tcx.adt_sized_constraint(self.did).0
}

fn sized_constraint_for_ty(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Vec<Ty<'tcx>> {
let result = match ty.kind {
Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..)
| FnPtr(_) | Array(..) | Closure(..) | Generator(..) | Never => vec![],

Str | Dynamic(..) | Slice(_) | Foreign(..) | Error | GeneratorWitness(..) => {
// these are never sized - return the target type
vec![ty]
}

Tuple(ref tys) => match tys.last() {
None => vec![],
Some(ty) => self.sized_constraint_for_ty(tcx, ty.expect_ty()),
},

Adt(adt, substs) => {
// recursive case
let adt_tys = adt.sized_constraint(tcx);
debug!("sized_constraint_for_ty({:?}) intermediate = {:?}", ty, adt_tys);
adt_tys
.iter()
.map(|ty| ty.subst(tcx, substs))
.flat_map(|ty| self.sized_constraint_for_ty(tcx, ty))
.collect()
}

Projection(..) | Opaque(..) => {
// must calculate explicitly.
// FIXME: consider special-casing always-Sized projections
vec![ty]
}

UnnormalizedProjection(..) => bug!("only used with chalk-engine"),

Param(..) => {
// perf hack: if there is a `T: Sized` bound, then
// we know that `T` is Sized and do not need to check
// it on the impl.

let sized_trait = match tcx.lang_items().sized_trait() {
Some(x) => x,
_ => return vec![ty],
};
let sized_predicate = Binder::dummy(TraitRef {
def_id: sized_trait,
substs: tcx.mk_substs_trait(ty, &[]),
})
.to_predicate();
let predicates = tcx.predicates_of(self.did).predicates;
if predicates.iter().any(|(p, _)| *p == sized_predicate) {
vec![]
} else {
vec![ty]
}
}

Placeholder(..) | Bound(..) | Infer(..) => {
bug!("unexpected type `{:?}` in sized_constraint_for_ty", ty)
}
};
debug!("sized_constraint_for_ty({:?}) = {:?}", ty, result);
result
}
}

impl<'tcx> FieldDef {
@@ -2742,57 +2676,6 @@ impl<'tcx> TyCtxt<'tcx> {
is_associated_item.then(|| self.associated_item(def_id))
}

fn associated_item_from_trait_item_ref(
self,
parent_def_id: DefId,
parent_vis: &hir::Visibility<'_>,
trait_item_ref: &hir::TraitItemRef,
) -> AssocItem {
let def_id = self.hir().local_def_id(trait_item_ref.id.hir_id);
let (kind, has_self) = match trait_item_ref.kind {
hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
hir::AssocItemKind::Method { has_self } => (ty::AssocKind::Method, has_self),
hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
hir::AssocItemKind::OpaqueTy => bug!("only impls can have opaque types"),
};

AssocItem {
ident: trait_item_ref.ident,
kind,
// Visibility of trait items is inherited from their traits.
vis: Visibility::from_hir(parent_vis, trait_item_ref.id.hir_id, self),
defaultness: trait_item_ref.defaultness,
def_id,
container: TraitContainer(parent_def_id),
method_has_self_argument: has_self,
}
}

fn associated_item_from_impl_item_ref(
self,
parent_def_id: DefId,
impl_item_ref: &hir::ImplItemRef<'_>,
) -> AssocItem {
let def_id = self.hir().local_def_id(impl_item_ref.id.hir_id);
let (kind, has_self) = match impl_item_ref.kind {
hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
hir::AssocItemKind::Method { has_self } => (ty::AssocKind::Method, has_self),
hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
hir::AssocItemKind::OpaqueTy => (ty::AssocKind::OpaqueTy, false),
};

AssocItem {
ident: impl_item_ref.ident,
kind,
// Visibility of trait impl items doesn't matter.
vis: ty::Visibility::from_hir(&impl_item_ref.vis, impl_item_ref.id.hir_id, self),
defaultness: impl_item_ref.defaultness,
def_id,
container: ImplContainer(parent_def_id),
method_has_self_argument: has_self,
}
}

pub fn field_index(self, hir_id: hir::HirId, tables: &TypeckTables<'_>) -> usize {
tables.field_indices().get(hir_id).cloned().expect("no index for a field")
}
@@ -3070,105 +2953,9 @@ impl Iterator for AssocItemsIterator<'_> {
}
}

fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> AssocItem {
let id = tcx.hir().as_local_hir_id(def_id).unwrap();
let parent_id = tcx.hir().get_parent_item(id);
let parent_def_id = tcx.hir().local_def_id(parent_id);
let parent_item = tcx.hir().expect_item(parent_id);
match parent_item.kind {
hir::ItemKind::Impl(.., ref impl_item_refs) => {
if let Some(impl_item_ref) = impl_item_refs.iter().find(|i| i.id.hir_id == id) {
let assoc_item =
tcx.associated_item_from_impl_item_ref(parent_def_id, impl_item_ref);
debug_assert_eq!(assoc_item.def_id, def_id);
return assoc_item;
}
}

hir::ItemKind::Trait(.., ref trait_item_refs) => {
if let Some(trait_item_ref) = trait_item_refs.iter().find(|i| i.id.hir_id == id) {
let assoc_item = tcx.associated_item_from_trait_item_ref(
parent_def_id,
&parent_item.vis,
trait_item_ref,
);
debug_assert_eq!(assoc_item.def_id, def_id);
return assoc_item;
}
}

_ => {}
}

span_bug!(
parent_item.span,
"unexpected parent of trait or impl item or item not found: {:?}",
parent_item.kind
)
}

#[derive(Clone, HashStable)]
pub struct AdtSizedConstraint<'tcx>(pub &'tcx [Ty<'tcx>]);

/// Calculates the `Sized` constraint.
///
/// In fact, there are only a few options for the types in the constraint:
/// - an obviously-unsized type
/// - a type parameter or projection whose Sizedness can't be known
/// - a tuple of type parameters or projections, if there are multiple
/// such.
/// - a Error, if a type contained itself. The representability
/// check should catch this case.
fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> AdtSizedConstraint<'_> {
let def = tcx.adt_def(def_id);

let result = tcx.mk_type_list(
def.variants
.iter()
.flat_map(|v| v.fields.last())
.flat_map(|f| def.sized_constraint_for_ty(tcx, tcx.type_of(f.did))),
);

debug!("adt_sized_constraint: {:?} => {:?}", def, result);

AdtSizedConstraint(result)
}

fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
let id = tcx.hir().as_local_hir_id(def_id).unwrap();
let item = tcx.hir().expect_item(id);
match item.kind {
hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter(
trait_item_refs
.iter()
.map(|trait_item_ref| trait_item_ref.id)
.map(|id| tcx.hir().local_def_id(id.hir_id)),
),
hir::ItemKind::Impl(.., ref impl_item_refs) => tcx.arena.alloc_from_iter(
impl_item_refs
.iter()
.map(|impl_item_ref| impl_item_ref.id)
.map(|id| tcx.hir().local_def_id(id.hir_id)),
),
hir::ItemKind::TraitAlias(..) => &[],
_ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
}
}

fn def_span(tcx: TyCtxt<'_>, def_id: DefId) -> Span {
tcx.hir().span_if_local(def_id).unwrap()
}

/// If the given `DefId` describes an item belonging to a trait,
/// returns the `DefId` of the trait that the trait item belongs to;
/// otherwise, returns `None`.
fn trait_of_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
tcx.opt_associated_item(def_id).and_then(|associated_item| match associated_item.container {
TraitContainer(def_id) => Some(def_id),
ImplContainer(_) => None,
})
}

/// Yields the parent function's `DefId` if `def_id` is an `impl Trait` definition.
pub fn is_impl_trait_defn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
if let Some(hir_id) = tcx.hir().as_local_hir_id(def_id) {
@@ -3181,151 +2968,12 @@ pub fn is_impl_trait_defn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
None
}

/// See `ParamEnv` struct definition for details.
fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ParamEnv<'_> {
// The param_env of an impl Trait type is its defining function's param_env
if let Some(parent) = is_impl_trait_defn(tcx, def_id) {
return param_env(tcx, parent);
}
// Compute the bounds on Self and the type parameters.

let InstantiatedPredicates { predicates } = tcx.predicates_of(def_id).instantiate_identity(tcx);

// Finally, we have to normalize the bounds in the environment, in
// case they contain any associated type projections. This process
// can yield errors if the put in illegal associated types, like
// `<i32 as Foo>::Bar` where `i32` does not implement `Foo`. We
// report these errors right here; this doesn't actually feel
// right to me, because constructing the environment feels like a
// kind of a "idempotent" action, but I'm not sure where would be
// a better place. In practice, we construct environments for
// every fn once during type checking, and we'll abort if there
// are any errors at that point, so after type checking you can be
// sure that this will succeed without errors anyway.

let unnormalized_env = ty::ParamEnv::new(
tcx.intern_predicates(&predicates),
traits::Reveal::UserFacing,
tcx.sess.opts.debugging_opts.chalk.then_some(def_id),
);

let body_id = tcx.hir().as_local_hir_id(def_id).map_or(hir::DUMMY_HIR_ID, |id| {
tcx.hir().maybe_body_owned_by(id).map_or(id, |body| body.hir_id)
});
let cause = traits::ObligationCause::misc(tcx.def_span(def_id), body_id);
traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause)
}

fn crate_disambiguator(tcx: TyCtxt<'_>, crate_num: CrateNum) -> CrateDisambiguator {
assert_eq!(crate_num, LOCAL_CRATE);
tcx.sess.local_crate_disambiguator()
}

fn original_crate_name(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Symbol {
assert_eq!(crate_num, LOCAL_CRATE);
tcx.crate_name.clone()
}

fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh {
assert_eq!(crate_num, LOCAL_CRATE);
tcx.hir().crate_hash
}

fn instance_def_size_estimate<'tcx>(tcx: TyCtxt<'tcx>, instance_def: InstanceDef<'tcx>) -> usize {
match instance_def {
InstanceDef::Item(..) | InstanceDef::DropGlue(..) => {
let mir = tcx.instance_mir(instance_def);
mir.basic_blocks().iter().map(|bb| bb.statements.len()).sum()
}
// Estimate the size of other compiler-generated shims to be 1.
_ => 1,
}
}

/// If `def_id` is an issue 33140 hack impl, returns its self type; otherwise, returns `None`.
///
/// See [`ImplOverlapKind::Issue33140`] for more details.
fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Ty<'_>> {
debug!("issue33140_self_ty({:?})", def_id);

let trait_ref = tcx
.impl_trait_ref(def_id)
.unwrap_or_else(|| bug!("issue33140_self_ty called on inherent impl {:?}", def_id));

debug!("issue33140_self_ty({:?}), trait-ref={:?}", def_id, trait_ref);

let is_marker_like = tcx.impl_polarity(def_id) == ty::ImplPolarity::Positive
&& tcx.associated_item_def_ids(trait_ref.def_id).is_empty();

// Check whether these impls would be ok for a marker trait.
if !is_marker_like {
debug!("issue33140_self_ty - not marker-like!");
return None;
}

// impl must be `impl Trait for dyn Marker1 + Marker2 + ...`
if trait_ref.substs.len() != 1 {
debug!("issue33140_self_ty - impl has substs!");
return None;
}

let predicates = tcx.predicates_of(def_id);
if predicates.parent.is_some() || !predicates.predicates.is_empty() {
debug!("issue33140_self_ty - impl has predicates {:?}!", predicates);
return None;
}

let self_ty = trait_ref.self_ty();
let self_ty_matches = match self_ty.kind {
ty::Dynamic(ref data, ty::ReStatic) => data.principal().is_none(),
_ => false,
};

if self_ty_matches {
debug!("issue33140_self_ty - MATCHES!");
Some(self_ty)
} else {
debug!("issue33140_self_ty - non-matching self type");
None
}
}

/// Check if a function is async.
fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
let hir_id = tcx
.hir()
.as_local_hir_id(def_id)
.unwrap_or_else(|| bug!("asyncness: expected local `DefId`, got `{:?}`", def_id));

let node = tcx.hir().get(hir_id);

let fn_like = hir_map::blocks::FnLikeNode::from_node(node).unwrap_or_else(|| {
bug!("asyncness: expected fn-like node but got `{:?}`", def_id);
});

fn_like.asyncness()
}

pub fn provide(providers: &mut ty::query::Providers<'_>) {
context::provide(providers);
erase_regions::provide(providers);
layout::provide(providers);
*providers = ty::query::Providers {
asyncness,
associated_item,
associated_item_def_ids,
adt_sized_constraint,
def_span,
param_env,
trait_of_item,
crate_disambiguator,
original_crate_name,
crate_hash,
trait_impls_of: trait_def::trait_impls_of_provider,
instance_def_size_estimate,
issue33140_self_ty,
..*providers
};
*providers =
ty::query::Providers { trait_impls_of: trait_def::trait_impls_of_provider, ..*providers };
}

/// A map for the local crate mapping each type to a vector of its
1 change: 1 addition & 0 deletions src/librustc_interface/Cargo.toml
Original file line number Diff line number Diff line change
@@ -39,6 +39,7 @@ rustc_errors = { path = "../librustc_errors" }
rustc_plugin_impl = { path = "../librustc_plugin_impl" }
rustc_privacy = { path = "../librustc_privacy" }
rustc_resolve = { path = "../librustc_resolve" }
rustc_ty = { path = "../librustc_ty" }
tempfile = "3.0.5"
once_cell = "1"

1 change: 1 addition & 0 deletions src/librustc_interface/passes.rs
Original file line number Diff line number Diff line change
@@ -677,6 +677,7 @@ pub fn default_provide(providers: &mut ty::query::Providers<'_>) {
rustc_passes::provide(providers);
rustc_resolve::provide(providers);
rustc_traits::provide(providers);
rustc_ty::provide(providers);
rustc_metadata::provide(providers);
rustc_lint::provide(providers);
rustc_codegen_utils::provide(providers);
16 changes: 16 additions & 0 deletions src/librustc_ty/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
authors = ["The Rust Project Developers"]
name = "rustc_ty"
version = "0.0.0"
edition = "2018"

[lib]
name = "rustc_ty"
path = "lib.rs"

[dependencies]
log = "0.4"
rustc = { path = "../librustc" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_hir = { path = "../librustc_hir" }
rustc_span = { path = "../librustc_span" }
25 changes: 25 additions & 0 deletions src/librustc_ty/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//! Various checks
//!
//! # Note
//!
//! This API is completely unstable and subject to change.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(bool_to_option)]
#![feature(in_band_lifetimes)]
#![feature(nll)]
#![feature(slice_patterns)]
#![recursion_limit = "256"]

#[macro_use]
extern crate rustc;
#[macro_use]
extern crate log;

use rustc::ty::query::Providers;

mod ty;

pub fn provide(providers: &mut Providers<'_>) {
ty::provide(providers);
}
369 changes: 369 additions & 0 deletions src/librustc_ty/ty.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,369 @@
use rustc::hir::map as hir_map;
use rustc::session::CrateDisambiguator;
use rustc::traits::{self};
use rustc::ty::subst::Subst;
use rustc::ty::{self, ToPredicate, Ty, TyCtxt};
use rustc_data_structures::svh::Svh;
use rustc_hir as hir;
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc_span::symbol::Symbol;
use rustc_span::Span;

fn sized_constraint_for_ty(tcx: TyCtxt<'tcx>, adtdef: &ty::AdtDef, ty: Ty<'tcx>) -> Vec<Ty<'tcx>> {
use ty::TyKind::*;

let result = match ty.kind {
Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..)
| FnPtr(_) | Array(..) | Closure(..) | Generator(..) | Never => vec![],

Str | Dynamic(..) | Slice(_) | Foreign(..) | Error | GeneratorWitness(..) => {
// these are never sized - return the target type
vec![ty]
}

Tuple(ref tys) => match tys.last() {
None => vec![],
Some(ty) => sized_constraint_for_ty(tcx, adtdef, ty.expect_ty()),
},

Adt(adt, substs) => {
// recursive case
let adt_tys = adt.sized_constraint(tcx);
debug!("sized_constraint_for_ty({:?}) intermediate = {:?}", ty, adt_tys);
adt_tys
.iter()
.map(|ty| ty.subst(tcx, substs))
.flat_map(|ty| sized_constraint_for_ty(tcx, adtdef, ty))
.collect()
}

Projection(..) | Opaque(..) => {
// must calculate explicitly.
// FIXME: consider special-casing always-Sized projections
vec![ty]
}

UnnormalizedProjection(..) => bug!("only used with chalk-engine"),

Param(..) => {
// perf hack: if there is a `T: Sized` bound, then
// we know that `T` is Sized and do not need to check
// it on the impl.

let sized_trait = match tcx.lang_items().sized_trait() {
Some(x) => x,
_ => return vec![ty],
};
let sized_predicate = ty::Binder::dummy(ty::TraitRef {
def_id: sized_trait,
substs: tcx.mk_substs_trait(ty, &[]),
})
.to_predicate();
let predicates = tcx.predicates_of(adtdef.did).predicates;
if predicates.iter().any(|(p, _)| *p == sized_predicate) { vec![] } else { vec![ty] }
}

Placeholder(..) | Bound(..) | Infer(..) => {
bug!("unexpected type `{:?}` in sized_constraint_for_ty", ty)
}
};
debug!("sized_constraint_for_ty({:?}) = {:?}", ty, result);
result
}

fn associated_item_from_trait_item_ref(
tcx: TyCtxt<'_>,
parent_def_id: DefId,
parent_vis: &hir::Visibility<'_>,
trait_item_ref: &hir::TraitItemRef,
) -> ty::AssocItem {
let def_id = tcx.hir().local_def_id(trait_item_ref.id.hir_id);
let (kind, has_self) = match trait_item_ref.kind {
hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
hir::AssocItemKind::Method { has_self } => (ty::AssocKind::Method, has_self),
hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
hir::AssocItemKind::OpaqueTy => bug!("only impls can have opaque types"),
};

ty::AssocItem {
ident: trait_item_ref.ident,
kind,
// Visibility of trait items is inherited from their traits.
vis: ty::Visibility::from_hir(parent_vis, trait_item_ref.id.hir_id, tcx),
defaultness: trait_item_ref.defaultness,
def_id,
container: ty::TraitContainer(parent_def_id),
method_has_self_argument: has_self,
}
}

fn associated_item_from_impl_item_ref(
tcx: TyCtxt<'_>,
parent_def_id: DefId,
impl_item_ref: &hir::ImplItemRef<'_>,
) -> ty::AssocItem {
let def_id = tcx.hir().local_def_id(impl_item_ref.id.hir_id);
let (kind, has_self) = match impl_item_ref.kind {
hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
hir::AssocItemKind::Method { has_self } => (ty::AssocKind::Method, has_self),
hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
hir::AssocItemKind::OpaqueTy => (ty::AssocKind::OpaqueTy, false),
};

ty::AssocItem {
ident: impl_item_ref.ident,
kind,
// Visibility of trait impl items doesn't matter.
vis: ty::Visibility::from_hir(&impl_item_ref.vis, impl_item_ref.id.hir_id, tcx),
defaultness: impl_item_ref.defaultness,
def_id,
container: ty::ImplContainer(parent_def_id),
method_has_self_argument: has_self,
}
}

fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
let id = tcx.hir().as_local_hir_id(def_id).unwrap();
let parent_id = tcx.hir().get_parent_item(id);
let parent_def_id = tcx.hir().local_def_id(parent_id);
let parent_item = tcx.hir().expect_item(parent_id);
match parent_item.kind {
hir::ItemKind::Impl(.., ref impl_item_refs) => {
if let Some(impl_item_ref) = impl_item_refs.iter().find(|i| i.id.hir_id == id) {
let assoc_item =
associated_item_from_impl_item_ref(tcx, parent_def_id, impl_item_ref);
debug_assert_eq!(assoc_item.def_id, def_id);
return assoc_item;
}
}

hir::ItemKind::Trait(.., ref trait_item_refs) => {
if let Some(trait_item_ref) = trait_item_refs.iter().find(|i| i.id.hir_id == id) {
let assoc_item = associated_item_from_trait_item_ref(
tcx,
parent_def_id,
&parent_item.vis,
trait_item_ref,
);
debug_assert_eq!(assoc_item.def_id, def_id);
return assoc_item;
}
}

_ => {}
}

span_bug!(
parent_item.span,
"unexpected parent of trait or impl item or item not found: {:?}",
parent_item.kind
)
}

/// Calculates the `Sized` constraint.
///
/// In fact, there are only a few options for the types in the constraint:
/// - an obviously-unsized type
/// - a type parameter or projection whose Sizedness can't be known
/// - a tuple of type parameters or projections, if there are multiple
/// such.
/// - a Error, if a type contained itself. The representability
/// check should catch this case.
fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtSizedConstraint<'_> {
let def = tcx.adt_def(def_id);

let result = tcx.mk_type_list(
def.variants
.iter()
.flat_map(|v| v.fields.last())
.flat_map(|f| sized_constraint_for_ty(tcx, def, tcx.type_of(f.did))),
);

debug!("adt_sized_constraint: {:?} => {:?}", def, result);

ty::AdtSizedConstraint(result)
}

fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
let id = tcx.hir().as_local_hir_id(def_id).unwrap();
let item = tcx.hir().expect_item(id);
match item.kind {
hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter(
trait_item_refs
.iter()
.map(|trait_item_ref| trait_item_ref.id)
.map(|id| tcx.hir().local_def_id(id.hir_id)),
),
hir::ItemKind::Impl(.., ref impl_item_refs) => tcx.arena.alloc_from_iter(
impl_item_refs
.iter()
.map(|impl_item_ref| impl_item_ref.id)
.map(|id| tcx.hir().local_def_id(id.hir_id)),
),
hir::ItemKind::TraitAlias(..) => &[],
_ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
}
}

fn def_span(tcx: TyCtxt<'_>, def_id: DefId) -> Span {
tcx.hir().span_if_local(def_id).unwrap()
}

/// If the given `DefId` describes an item belonging to a trait,
/// returns the `DefId` of the trait that the trait item belongs to;
/// otherwise, returns `None`.
fn trait_of_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
tcx.opt_associated_item(def_id).and_then(|associated_item| match associated_item.container {
ty::TraitContainer(def_id) => Some(def_id),
ty::ImplContainer(_) => None,
})
}

/// See `ParamEnv` struct definition for details.
fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
// The param_env of an impl Trait type is its defining function's param_env
if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) {
return param_env(tcx, parent);
}
// Compute the bounds on Self and the type parameters.

let ty::InstantiatedPredicates { predicates } =
tcx.predicates_of(def_id).instantiate_identity(tcx);

// Finally, we have to normalize the bounds in the environment, in
// case they contain any associated type projections. This process
// can yield errors if the put in illegal associated types, like
// `<i32 as Foo>::Bar` where `i32` does not implement `Foo`. We
// report these errors right here; this doesn't actually feel
// right to me, because constructing the environment feels like a
// kind of a "idempotent" action, but I'm not sure where would be
// a better place. In practice, we construct environments for
// every fn once during type checking, and we'll abort if there
// are any errors at that point, so after type checking you can be
// sure that this will succeed without errors anyway.

let unnormalized_env = ty::ParamEnv::new(
tcx.intern_predicates(&predicates),
traits::Reveal::UserFacing,
tcx.sess.opts.debugging_opts.chalk.then_some(def_id),
);

let body_id = tcx.hir().as_local_hir_id(def_id).map_or(hir::DUMMY_HIR_ID, |id| {
tcx.hir().maybe_body_owned_by(id).map_or(id, |body| body.hir_id)
});
let cause = traits::ObligationCause::misc(tcx.def_span(def_id), body_id);
traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause)
}

fn crate_disambiguator(tcx: TyCtxt<'_>, crate_num: CrateNum) -> CrateDisambiguator {
assert_eq!(crate_num, LOCAL_CRATE);
tcx.sess.local_crate_disambiguator()
}

fn original_crate_name(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Symbol {
assert_eq!(crate_num, LOCAL_CRATE);
tcx.crate_name.clone()
}

fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh {
assert_eq!(crate_num, LOCAL_CRATE);
tcx.hir().crate_hash
}

fn instance_def_size_estimate<'tcx>(
tcx: TyCtxt<'tcx>,
instance_def: ty::InstanceDef<'tcx>,
) -> usize {
use ty::InstanceDef;

match instance_def {
InstanceDef::Item(..) | InstanceDef::DropGlue(..) => {
let mir = tcx.instance_mir(instance_def);
mir.basic_blocks().iter().map(|bb| bb.statements.len()).sum()
}
// Estimate the size of other compiler-generated shims to be 1.
_ => 1,
}
}

/// If `def_id` is an issue 33140 hack impl, returns its self type; otherwise, returns `None`.
///
/// See [`ImplOverlapKind::Issue33140`] for more details.
fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Ty<'_>> {
debug!("issue33140_self_ty({:?})", def_id);

let trait_ref = tcx
.impl_trait_ref(def_id)
.unwrap_or_else(|| bug!("issue33140_self_ty called on inherent impl {:?}", def_id));

debug!("issue33140_self_ty({:?}), trait-ref={:?}", def_id, trait_ref);

let is_marker_like = tcx.impl_polarity(def_id) == ty::ImplPolarity::Positive
&& tcx.associated_item_def_ids(trait_ref.def_id).is_empty();

// Check whether these impls would be ok for a marker trait.
if !is_marker_like {
debug!("issue33140_self_ty - not marker-like!");
return None;
}

// impl must be `impl Trait for dyn Marker1 + Marker2 + ...`
if trait_ref.substs.len() != 1 {
debug!("issue33140_self_ty - impl has substs!");
return None;
}

let predicates = tcx.predicates_of(def_id);
if predicates.parent.is_some() || !predicates.predicates.is_empty() {
debug!("issue33140_self_ty - impl has predicates {:?}!", predicates);
return None;
}

let self_ty = trait_ref.self_ty();
let self_ty_matches = match self_ty.kind {
ty::Dynamic(ref data, ty::ReStatic) => data.principal().is_none(),
_ => false,
};

if self_ty_matches {
debug!("issue33140_self_ty - MATCHES!");
Some(self_ty)
} else {
debug!("issue33140_self_ty - non-matching self type");
None
}
}

/// Check if a function is async.
fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
let hir_id = tcx
.hir()
.as_local_hir_id(def_id)
.unwrap_or_else(|| bug!("asyncness: expected local `DefId`, got `{:?}`", def_id));

let node = tcx.hir().get(hir_id);

let fn_like = hir_map::blocks::FnLikeNode::from_node(node).unwrap_or_else(|| {
bug!("asyncness: expected fn-like node but got `{:?}`", def_id);
});

fn_like.asyncness()
}

pub fn provide(providers: &mut ty::query::Providers<'_>) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you need to call this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, sorry. Added a commit for that.

*providers = ty::query::Providers {
asyncness,
associated_item,
associated_item_def_ids,
adt_sized_constraint,
def_span,
param_env,
trait_of_item,
crate_disambiguator,
original_crate_name,
crate_hash,
instance_def_size_estimate,
issue33140_self_ty,
..*providers
};
}