mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-02 14:51:48 +00:00
style: rename crates to kebab case
This commit is contained in:
parent
e025b37df6
commit
1f011fa4a3
462 changed files with 158 additions and 158 deletions
142
crates/hir-ty/src/autoderef.rs
Normal file
142
crates/hir-ty/src/autoderef.rs
Normal file
|
@ -0,0 +1,142 @@
|
|||
//! In certain situations, rust automatically inserts derefs as necessary: for
|
||||
//! example, field accesses `foo.bar` still work when `foo` is actually a
|
||||
//! reference to a type with the field `bar`. This is an approximation of the
|
||||
//! logic in rustc (which lives in librustc_typeck/check/autoderef.rs).
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use chalk_ir::cast::Cast;
|
||||
use hir_expand::name::name;
|
||||
use limit::Limit;
|
||||
use syntax::SmolStr;
|
||||
|
||||
use crate::{
|
||||
db::HirDatabase, infer::unify::InferenceTable, Canonical, Goal, Interner, ProjectionTyExt,
|
||||
TraitEnvironment, Ty, TyBuilder, TyKind,
|
||||
};
|
||||
|
||||
static AUTODEREF_RECURSION_LIMIT: Limit = Limit::new(10);
|
||||
|
||||
pub(crate) enum AutoderefKind {
|
||||
Builtin,
|
||||
Overloaded,
|
||||
}
|
||||
|
||||
pub(crate) struct Autoderef<'a, 'db> {
|
||||
pub(crate) table: &'a mut InferenceTable<'db>,
|
||||
ty: Ty,
|
||||
at_start: bool,
|
||||
steps: Vec<(AutoderefKind, Ty)>,
|
||||
}
|
||||
|
||||
impl<'a, 'db> Autoderef<'a, 'db> {
|
||||
pub(crate) fn new(table: &'a mut InferenceTable<'db>, ty: Ty) -> Self {
|
||||
let ty = table.resolve_ty_shallow(&ty);
|
||||
Autoderef { table, ty, at_start: true, steps: Vec::new() }
|
||||
}
|
||||
|
||||
pub(crate) fn step_count(&self) -> usize {
|
||||
self.steps.len()
|
||||
}
|
||||
|
||||
pub(crate) fn steps(&self) -> &[(AutoderefKind, Ty)] {
|
||||
&self.steps
|
||||
}
|
||||
|
||||
pub(crate) fn final_ty(&self) -> Ty {
|
||||
self.ty.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for Autoderef<'_, '_> {
|
||||
type Item = (Ty, usize);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.at_start {
|
||||
self.at_start = false;
|
||||
return Some((self.ty.clone(), 0));
|
||||
}
|
||||
|
||||
if AUTODEREF_RECURSION_LIMIT.check(self.steps.len() + 1).is_err() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let (kind, new_ty) = autoderef_step(self.table, self.ty.clone())?;
|
||||
|
||||
self.steps.push((kind, self.ty.clone()));
|
||||
self.ty = new_ty;
|
||||
|
||||
Some((self.ty.clone(), self.step_count()))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn autoderef_step(table: &mut InferenceTable, ty: Ty) -> Option<(AutoderefKind, Ty)> {
|
||||
if let Some(derefed) = builtin_deref(&ty) {
|
||||
Some((AutoderefKind::Builtin, table.resolve_ty_shallow(derefed)))
|
||||
} else {
|
||||
Some((AutoderefKind::Overloaded, deref_by_trait(table, ty)?))
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: replace uses of this with Autoderef above
|
||||
pub fn autoderef<'a>(
|
||||
db: &'a dyn HirDatabase,
|
||||
env: Arc<TraitEnvironment>,
|
||||
ty: Canonical<Ty>,
|
||||
) -> impl Iterator<Item = Canonical<Ty>> + 'a {
|
||||
let mut table = InferenceTable::new(db, env);
|
||||
let ty = table.instantiate_canonical(ty);
|
||||
let mut autoderef = Autoderef::new(&mut table, ty);
|
||||
let mut v = Vec::new();
|
||||
while let Some((ty, _steps)) = autoderef.next() {
|
||||
v.push(autoderef.table.canonicalize(ty).value);
|
||||
}
|
||||
v.into_iter()
|
||||
}
|
||||
|
||||
pub(crate) fn deref(table: &mut InferenceTable, ty: Ty) -> Option<Ty> {
|
||||
let _p = profile::span("deref");
|
||||
autoderef_step(table, ty).map(|(_, ty)| ty)
|
||||
}
|
||||
|
||||
fn builtin_deref(ty: &Ty) -> Option<&Ty> {
|
||||
match ty.kind(Interner) {
|
||||
TyKind::Ref(.., ty) => Some(ty),
|
||||
TyKind::Raw(.., ty) => Some(ty),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn deref_by_trait(table: &mut InferenceTable, ty: Ty) -> Option<Ty> {
|
||||
let _p = profile::span("deref_by_trait");
|
||||
if table.resolve_ty_shallow(&ty).inference_var(Interner).is_some() {
|
||||
// don't try to deref unknown variables
|
||||
return None;
|
||||
}
|
||||
|
||||
let db = table.db;
|
||||
let deref_trait = db
|
||||
.lang_item(table.trait_env.krate, SmolStr::new_inline("deref"))
|
||||
.and_then(|l| l.as_trait())?;
|
||||
let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?;
|
||||
|
||||
let projection = {
|
||||
let b = TyBuilder::assoc_type_projection(db, target);
|
||||
if b.remaining() != 1 {
|
||||
// the Target type + Deref trait should only have one generic parameter,
|
||||
// namely Deref's Self type
|
||||
return None;
|
||||
}
|
||||
b.push(ty).build()
|
||||
};
|
||||
|
||||
// Check that the type implements Deref at all
|
||||
let trait_ref = projection.trait_ref(db);
|
||||
let implements_goal: Goal = trait_ref.cast(Interner);
|
||||
table.try_obligation(implements_goal.clone())?;
|
||||
|
||||
table.register_obligation(implements_goal);
|
||||
|
||||
let result = table.normalize_projection_ty(projection);
|
||||
Some(table.resolve_ty_shallow(&result))
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue