Move some utils out of rustc_const_eval
This allows us to get rid of the `rustc_const_eval->rustc_borrowck` dependency edge which was delaying the compilation of borrowck. The added utils in `rustc_middle` are small and should not affect compile times there.
This commit is contained in:
parent
e6e956dade
commit
2109fe4e4e
15 changed files with 30 additions and 25 deletions
|
@ -14,6 +14,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
|
|||
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
|
||||
use rustc_middle::ty::{suggest_constraining_type_param, Adt, Closure, FnDef, FnPtr, Param, Ty};
|
||||
use rustc_middle::ty::{Binder, TraitRef};
|
||||
use rustc_middle::util::{call_kind, CallDesugaringKind, CallKind};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{BytePos, Pos, Span, Symbol};
|
||||
|
@ -21,7 +22,6 @@ use rustc_trait_selection::traits::SelectionContext;
|
|||
|
||||
use super::ConstCx;
|
||||
use crate::errors;
|
||||
use crate::util::{call_kind, CallDesugaringKind, CallKind};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Status {
|
||||
|
|
|
@ -1,137 +0,0 @@
|
|||
//! Common logic for borrowck use-after-move errors when moved into a `fn(self)`,
|
||||
//! as well as errors when attempting to call a non-const function in a const
|
||||
//! context.
|
||||
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{lang_items, LangItem};
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
use rustc_middle::ty::{AssocItemContainer, Instance, ParamEnv, Ty, TyCtxt};
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{sym, DesugaringKind, Span};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum CallDesugaringKind {
|
||||
/// for _ in x {} calls x.into_iter()
|
||||
ForLoopIntoIter,
|
||||
/// x? calls x.branch()
|
||||
QuestionBranch,
|
||||
/// x? calls type_of(x)::from_residual()
|
||||
QuestionFromResidual,
|
||||
/// try { ..; x } calls type_of(x)::from_output(x)
|
||||
TryBlockFromOutput,
|
||||
}
|
||||
|
||||
impl CallDesugaringKind {
|
||||
pub fn trait_def_id(self, tcx: TyCtxt<'_>) -> DefId {
|
||||
match self {
|
||||
Self::ForLoopIntoIter => tcx.get_diagnostic_item(sym::IntoIterator).unwrap(),
|
||||
Self::QuestionBranch | Self::TryBlockFromOutput => {
|
||||
tcx.require_lang_item(LangItem::Try, None)
|
||||
}
|
||||
Self::QuestionFromResidual => tcx.get_diagnostic_item(sym::FromResidual).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum CallKind<'tcx> {
|
||||
/// A normal method call of the form `receiver.foo(a, b, c)`
|
||||
Normal {
|
||||
self_arg: Option<Ident>,
|
||||
desugaring: Option<(CallDesugaringKind, Ty<'tcx>)>,
|
||||
method_did: DefId,
|
||||
method_substs: SubstsRef<'tcx>,
|
||||
},
|
||||
/// A call to `Fn(..)::call(..)`, desugared from `my_closure(a, b, c)`
|
||||
FnCall { fn_trait_id: DefId, self_ty: Ty<'tcx> },
|
||||
/// A call to an operator trait, desugared from operator syntax (e.g. `a << b`)
|
||||
Operator { self_arg: Option<Ident>, trait_id: DefId, self_ty: Ty<'tcx> },
|
||||
DerefCoercion {
|
||||
/// The `Span` of the `Target` associated type
|
||||
/// in the `Deref` impl we are using.
|
||||
deref_target: Span,
|
||||
/// The type `T::Deref` we are dereferencing to
|
||||
deref_target_ty: Ty<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
},
|
||||
}
|
||||
|
||||
pub fn call_kind<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
method_did: DefId,
|
||||
method_substs: SubstsRef<'tcx>,
|
||||
fn_call_span: Span,
|
||||
from_hir_call: bool,
|
||||
self_arg: Option<Ident>,
|
||||
) -> CallKind<'tcx> {
|
||||
let parent = tcx.opt_associated_item(method_did).and_then(|assoc| {
|
||||
let container_id = assoc.container_id(tcx);
|
||||
match assoc.container {
|
||||
AssocItemContainer::ImplContainer => tcx.trait_id_of_impl(container_id),
|
||||
AssocItemContainer::TraitContainer => Some(container_id),
|
||||
}
|
||||
});
|
||||
|
||||
let fn_call = parent.and_then(|p| {
|
||||
lang_items::FN_TRAITS.iter().filter_map(|&l| tcx.lang_items().get(l)).find(|&id| id == p)
|
||||
});
|
||||
|
||||
let operator = if !from_hir_call && let Some(p) = parent {
|
||||
lang_items::OPERATORS.iter().filter_map(|&l| tcx.lang_items().get(l)).find(|&id| id == p)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did);
|
||||
|
||||
// Check for a 'special' use of 'self' -
|
||||
// an FnOnce call, an operator (e.g. `<<`), or a
|
||||
// deref coercion.
|
||||
let kind = if let Some(trait_id) = fn_call {
|
||||
Some(CallKind::FnCall { fn_trait_id: trait_id, self_ty: method_substs.type_at(0) })
|
||||
} else if let Some(trait_id) = operator {
|
||||
Some(CallKind::Operator { self_arg, trait_id, self_ty: method_substs.type_at(0) })
|
||||
} else if is_deref {
|
||||
let deref_target = tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
|
||||
Instance::resolve(tcx, param_env, deref_target, method_substs).transpose()
|
||||
});
|
||||
if let Some(Ok(instance)) = deref_target {
|
||||
let deref_target_ty = instance.ty(tcx, param_env);
|
||||
Some(CallKind::DerefCoercion {
|
||||
deref_target: tcx.def_span(instance.def_id()),
|
||||
deref_target_ty,
|
||||
self_ty: method_substs.type_at(0),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
kind.unwrap_or_else(|| {
|
||||
// This isn't a 'special' use of `self`
|
||||
debug!(?method_did, ?fn_call_span);
|
||||
let desugaring = if Some(method_did) == tcx.lang_items().into_iter_fn()
|
||||
&& fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop)
|
||||
{
|
||||
Some((CallDesugaringKind::ForLoopIntoIter, method_substs.type_at(0)))
|
||||
} else if fn_call_span.desugaring_kind() == Some(DesugaringKind::QuestionMark) {
|
||||
if Some(method_did) == tcx.lang_items().branch_fn() {
|
||||
Some((CallDesugaringKind::QuestionBranch, method_substs.type_at(0)))
|
||||
} else if Some(method_did) == tcx.lang_items().from_residual_fn() {
|
||||
Some((CallDesugaringKind::QuestionFromResidual, method_substs.type_at(0)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else if Some(method_did) == tcx.lang_items().from_output_fn()
|
||||
&& fn_call_span.desugaring_kind() == Some(DesugaringKind::TryBlock)
|
||||
{
|
||||
Some((CallDesugaringKind::TryBlockFromOutput, method_substs.type_at(0)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
CallKind::Normal { self_arg, desugaring, method_did, method_substs }
|
||||
})
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
use rustc_middle::mir::visit::PlaceContext;
|
||||
use rustc_middle::mir::visit::Visitor;
|
||||
use rustc_middle::mir::{Body, Local, Location};
|
||||
|
||||
pub trait FindAssignments {
|
||||
// Finds all statements that assign directly to local (i.e., X = ...)
|
||||
// and returns their locations.
|
||||
fn find_assignments(&self, local: Local) -> Vec<Location>;
|
||||
}
|
||||
|
||||
impl<'tcx> FindAssignments for Body<'tcx> {
|
||||
fn find_assignments(&self, local: Local) -> Vec<Location> {
|
||||
let mut visitor = FindLocalAssignmentVisitor { needle: local, locations: vec![] };
|
||||
visitor.visit_body(self);
|
||||
visitor.locations
|
||||
}
|
||||
}
|
||||
|
||||
// The Visitor walks the MIR to return the assignment statements corresponding
|
||||
// to a Local.
|
||||
struct FindLocalAssignmentVisitor {
|
||||
needle: Local,
|
||||
locations: Vec<Location>,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for FindLocalAssignmentVisitor {
|
||||
fn visit_local(&mut self, local: Local, place_context: PlaceContext, location: Location) {
|
||||
if self.needle != local {
|
||||
return;
|
||||
}
|
||||
|
||||
if place_context.is_place_assignment() {
|
||||
self.locations.push(location);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_span::def_id::DefId;
|
||||
|
||||
/// Checks if the specified `local` is used as the `self` parameter of a method call
|
||||
/// in the provided `BasicBlock`. If it is, then the `DefId` of the called method is
|
||||
/// returned.
|
||||
pub fn find_self_call<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
local: Local,
|
||||
block: BasicBlock,
|
||||
) -> Option<(DefId, SubstsRef<'tcx>)> {
|
||||
debug!("find_self_call(local={:?}): terminator={:?}", local, &body[block].terminator);
|
||||
if let Some(Terminator { kind: TerminatorKind::Call { func, args, .. }, .. }) =
|
||||
&body[block].terminator
|
||||
{
|
||||
debug!("find_self_call: func={:?}", func);
|
||||
if let Operand::Constant(box Constant { literal, .. }) = func {
|
||||
if let ty::FnDef(def_id, substs) = *literal.ty().kind() {
|
||||
if let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) =
|
||||
tcx.opt_associated_item(def_id)
|
||||
{
|
||||
debug!("find_self_call: args={:?}", args);
|
||||
if let [Operand::Move(self_place) | Operand::Copy(self_place), ..] = **args {
|
||||
if self_place.as_local() == Some(local) {
|
||||
return Some((def_id, substs));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
|
@ -1,14 +1,9 @@
|
|||
mod alignment;
|
||||
mod call_kind;
|
||||
mod check_validity_requirement;
|
||||
pub mod collect_writes;
|
||||
mod compare_types;
|
||||
mod find_self_call;
|
||||
mod type_name;
|
||||
|
||||
pub use self::alignment::is_disaligned;
|
||||
pub use self::call_kind::{call_kind, CallDesugaringKind, CallKind};
|
||||
pub use self::check_validity_requirement::check_validity_requirement;
|
||||
pub use self::compare_types::{is_equal_up_to_subtyping, is_subtype};
|
||||
pub use self::find_self_call::find_self_call;
|
||||
pub use self::type_name::type_name;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue