Assert that Instance::try_resolve is only used on body-like things
This commit is contained in:
parent
e7ad3ae331
commit
9bf9f5db9b
10 changed files with 118 additions and 99 deletions
|
@ -5,7 +5,7 @@ use std::path::PathBuf;
|
|||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Namespace;
|
||||
use rustc_hir::def::{CtorKind, DefKind, Namespace};
|
||||
use rustc_hir::def_id::{CrateNum, DefId};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_index::bit_set::FiniteBitSet;
|
||||
|
@ -498,7 +498,8 @@ impl<'tcx> Instance<'tcx> {
|
|||
|
||||
/// Resolves a `(def_id, args)` pair to an (optional) instance -- most commonly,
|
||||
/// this is used to find the precise code that will run for a trait method invocation,
|
||||
/// if known.
|
||||
/// if known. This should only be used for functions and consts. If you want to
|
||||
/// resolve an associated type, use [`TyCtxt::try_normalize_erasing_regions`].
|
||||
///
|
||||
/// Returns `Ok(None)` if we cannot resolve `Instance` to a specific instance.
|
||||
/// For example, in a context like this,
|
||||
|
@ -527,6 +528,23 @@ impl<'tcx> Instance<'tcx> {
|
|||
def_id: DefId,
|
||||
args: GenericArgsRef<'tcx>,
|
||||
) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> {
|
||||
assert_matches!(
|
||||
tcx.def_kind(def_id),
|
||||
DefKind::Fn
|
||||
| DefKind::AssocFn
|
||||
| DefKind::Const
|
||||
| DefKind::AssocConst
|
||||
| DefKind::AnonConst
|
||||
| DefKind::InlineConst
|
||||
| DefKind::Static { .. }
|
||||
| DefKind::Ctor(_, CtorKind::Fn)
|
||||
| DefKind::Closure
|
||||
| DefKind::SyntheticCoroutineBody,
|
||||
"`Instance::try_resolve` should only be used to resolve instances of \
|
||||
functions, statics, and consts; to resolve associated types, use \
|
||||
`try_normalize_erasing_regions`."
|
||||
);
|
||||
|
||||
// Rust code can easily create exponentially-long types using only a
|
||||
// polynomial recursion depth. Even with the default recursion
|
||||
// depth, you can easily get cases that take >2^60 steps to run,
|
||||
|
|
|
@ -1,149 +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::{LangItem, lang_items};
|
||||
use rustc_span::{DesugaringKind, Ident, Span, sym};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::ty::{AssocItemContainer, GenericArgsRef, Instance, Ty, TyCtxt, TypingEnv};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum CallDesugaringKind {
|
||||
/// for _ in x {} calls x.into_iter()
|
||||
ForLoopIntoIter,
|
||||
/// for _ in x {} calls iter.next()
|
||||
ForLoopNext,
|
||||
/// x? calls x.branch()
|
||||
QuestionBranch,
|
||||
/// x? calls type_of(x)::from_residual()
|
||||
QuestionFromResidual,
|
||||
/// try { ..; x } calls type_of(x)::from_output(x)
|
||||
TryBlockFromOutput,
|
||||
/// `.await` calls `IntoFuture::into_future`
|
||||
Await,
|
||||
}
|
||||
|
||||
impl CallDesugaringKind {
|
||||
pub fn trait_def_id(self, tcx: TyCtxt<'_>) -> DefId {
|
||||
match self {
|
||||
Self::ForLoopIntoIter => tcx.get_diagnostic_item(sym::IntoIterator).unwrap(),
|
||||
Self::ForLoopNext => tcx.require_lang_item(LangItem::Iterator, None),
|
||||
Self::QuestionBranch | Self::TryBlockFromOutput => {
|
||||
tcx.require_lang_item(LangItem::Try, None)
|
||||
}
|
||||
Self::QuestionFromResidual => tcx.get_diagnostic_item(sym::FromResidual).unwrap(),
|
||||
Self::Await => tcx.get_diagnostic_item(sym::IntoFuture).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_args: GenericArgsRef<'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>,
|
||||
typing_env: TypingEnv<'tcx>,
|
||||
method_did: DefId,
|
||||
method_args: GenericArgsRef<'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::Impl => tcx.trait_id_of_impl(container_id),
|
||||
AssocItemContainer::Trait => 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_args.type_at(0) })
|
||||
} else if let Some(trait_id) = operator {
|
||||
Some(CallKind::Operator { self_arg, trait_id, self_ty: method_args.type_at(0) })
|
||||
} else if is_deref {
|
||||
let deref_target = tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
|
||||
Instance::try_resolve(tcx, typing_env, deref_target, method_args).transpose()
|
||||
});
|
||||
if let Some(Ok(instance)) = deref_target {
|
||||
let deref_target_ty = instance.ty(tcx, typing_env);
|
||||
Some(CallKind::DerefCoercion {
|
||||
deref_target: tcx.def_span(instance.def_id()),
|
||||
deref_target_ty,
|
||||
self_ty: method_args.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 tcx.is_lang_item(method_did, LangItem::IntoIterIntoIter)
|
||||
&& fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop)
|
||||
{
|
||||
Some((CallDesugaringKind::ForLoopIntoIter, method_args.type_at(0)))
|
||||
} else if tcx.is_lang_item(method_did, LangItem::IteratorNext)
|
||||
&& fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop)
|
||||
{
|
||||
Some((CallDesugaringKind::ForLoopNext, method_args.type_at(0)))
|
||||
} else if fn_call_span.desugaring_kind() == Some(DesugaringKind::QuestionMark) {
|
||||
if tcx.is_lang_item(method_did, LangItem::TryTraitBranch) {
|
||||
Some((CallDesugaringKind::QuestionBranch, method_args.type_at(0)))
|
||||
} else if tcx.is_lang_item(method_did, LangItem::TryTraitFromResidual) {
|
||||
Some((CallDesugaringKind::QuestionFromResidual, method_args.type_at(0)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else if tcx.is_lang_item(method_did, LangItem::TryTraitFromOutput)
|
||||
&& fn_call_span.desugaring_kind() == Some(DesugaringKind::TryBlock)
|
||||
{
|
||||
Some((CallDesugaringKind::TryBlockFromOutput, method_args.type_at(0)))
|
||||
} else if fn_call_span.is_desugaring(DesugaringKind::Await) {
|
||||
Some((CallDesugaringKind::Await, method_args.type_at(0)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
CallKind::Normal { self_arg, desugaring, method_did, method_args }
|
||||
})
|
||||
}
|
|
@ -1,9 +1,7 @@
|
|||
pub mod bug;
|
||||
pub mod call_kind;
|
||||
pub mod common;
|
||||
pub mod find_self_call;
|
||||
|
||||
pub use call_kind::{CallDesugaringKind, CallKind, call_kind};
|
||||
pub use find_self_call::find_self_call;
|
||||
|
||||
#[derive(Default, Copy, Clone)]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue