mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-29 13:25:09 +00:00
Make type walking infrastructure a bit nicer
If/when we switch to using Chalk's Ty, we'll need to replace this by its `Fold` trait, but I didn't want to import the whole thing just yet.
This commit is contained in:
parent
c4fcfa2b0d
commit
b8c1e402fa
10 changed files with 146 additions and 147 deletions
|
@ -1,7 +1,7 @@
|
|||
use std::{collections::HashSet, fmt::Write, path::Path, time::Instant};
|
||||
|
||||
use ra_db::SourceDatabase;
|
||||
use ra_hir::{Crate, HasBodySource, HasSource, HirDisplay, ImplItem, ModuleDef, Ty};
|
||||
use ra_hir::{Crate, HasBodySource, HasSource, HirDisplay, ImplItem, ModuleDef, Ty, TypeWalk};
|
||||
use ra_syntax::AstNode;
|
||||
|
||||
use crate::Result;
|
||||
|
|
|
@ -69,7 +69,9 @@ pub use self::{
|
|||
resolve::Resolution,
|
||||
source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer},
|
||||
source_id::{AstIdMap, ErasedFileAstId},
|
||||
ty::{display::HirDisplay, ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor},
|
||||
ty::{
|
||||
display::HirDisplay, ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk,
|
||||
},
|
||||
type_ref::Mutability,
|
||||
};
|
||||
|
||||
|
|
|
@ -130,12 +130,14 @@ impl ProjectionTy {
|
|||
substs: self.parameters.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
|
||||
impl TypeWalk for ProjectionTy {
|
||||
fn walk(&self, f: &mut impl FnMut(&Ty)) {
|
||||
self.parameters.walk(f);
|
||||
}
|
||||
|
||||
pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
|
||||
fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
|
||||
self.parameters.walk_mut(f);
|
||||
}
|
||||
}
|
||||
|
@ -146,12 +148,12 @@ pub struct UnselectedProjectionTy {
|
|||
pub parameters: Substs,
|
||||
}
|
||||
|
||||
impl UnselectedProjectionTy {
|
||||
pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
|
||||
impl TypeWalk for UnselectedProjectionTy {
|
||||
fn walk(&self, f: &mut impl FnMut(&Ty)) {
|
||||
self.parameters.walk(f);
|
||||
}
|
||||
|
||||
pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
|
||||
fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
|
||||
self.parameters.walk_mut(f);
|
||||
}
|
||||
}
|
||||
|
@ -312,20 +314,14 @@ impl TraitRef {
|
|||
pub fn self_ty(&self) -> &Ty {
|
||||
&self.substs[0]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn subst(mut self, substs: &Substs) -> TraitRef {
|
||||
self.substs.walk_mut(&mut |ty_mut| {
|
||||
let ty = mem::replace(ty_mut, Ty::Unknown);
|
||||
*ty_mut = ty.subst(substs);
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
|
||||
impl TypeWalk for TraitRef {
|
||||
fn walk(&self, f: &mut impl FnMut(&Ty)) {
|
||||
self.substs.walk(f);
|
||||
}
|
||||
|
||||
pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
|
||||
fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
|
||||
self.substs.walk_mut(f);
|
||||
}
|
||||
}
|
||||
|
@ -365,20 +361,10 @@ impl GenericPredicate {
|
|||
GenericPredicate::Error => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn subst(self, substs: &Substs) -> GenericPredicate {
|
||||
match self {
|
||||
GenericPredicate::Implemented(trait_ref) => {
|
||||
GenericPredicate::Implemented(trait_ref.subst(substs))
|
||||
}
|
||||
GenericPredicate::Projection(projection_predicate) => {
|
||||
GenericPredicate::Projection(projection_predicate.subst(substs))
|
||||
}
|
||||
GenericPredicate::Error => self,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
|
||||
impl TypeWalk for GenericPredicate {
|
||||
fn walk(&self, f: &mut impl FnMut(&Ty)) {
|
||||
match self {
|
||||
GenericPredicate::Implemented(trait_ref) => trait_ref.walk(f),
|
||||
GenericPredicate::Projection(projection_pred) => projection_pred.walk(f),
|
||||
|
@ -386,7 +372,7 @@ impl GenericPredicate {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
|
||||
fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
|
||||
match self {
|
||||
GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut(f),
|
||||
GenericPredicate::Projection(projection_pred) => projection_pred.walk_mut(f),
|
||||
|
@ -430,16 +416,16 @@ impl FnSig {
|
|||
pub fn ret(&self) -> &Ty {
|
||||
&self.params_and_return[self.params_and_return.len() - 1]
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies the given substitutions to all types in this signature and
|
||||
/// returns the result.
|
||||
pub fn subst(&self, substs: &Substs) -> FnSig {
|
||||
let result: Vec<_> =
|
||||
self.params_and_return.iter().map(|ty| ty.clone().subst(substs)).collect();
|
||||
FnSig { params_and_return: result.into() }
|
||||
impl TypeWalk for FnSig {
|
||||
fn walk(&self, f: &mut impl FnMut(&Ty)) {
|
||||
for t in self.params_and_return.iter() {
|
||||
t.walk(f);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
|
||||
fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
|
||||
// Without an Arc::make_mut_slice, we can't avoid the clone here:
|
||||
let mut v: Vec<_> = self.params_and_return.iter().cloned().collect();
|
||||
for t in &mut v {
|
||||
|
@ -463,64 +449,6 @@ impl Ty {
|
|||
Ty::apply(TypeCtor::Tuple { cardinality: 0 }, Substs::empty())
|
||||
}
|
||||
|
||||
pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
|
||||
match self {
|
||||
Ty::Apply(a_ty) => {
|
||||
for t in a_ty.parameters.iter() {
|
||||
t.walk(f);
|
||||
}
|
||||
}
|
||||
Ty::Projection(p_ty) => {
|
||||
for t in p_ty.parameters.iter() {
|
||||
t.walk(f);
|
||||
}
|
||||
}
|
||||
Ty::UnselectedProjection(p_ty) => {
|
||||
for t in p_ty.parameters.iter() {
|
||||
t.walk(f);
|
||||
}
|
||||
}
|
||||
Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
|
||||
for p in predicates.iter() {
|
||||
p.walk(f);
|
||||
}
|
||||
}
|
||||
Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
|
||||
}
|
||||
f(self);
|
||||
}
|
||||
|
||||
fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
|
||||
match self {
|
||||
Ty::Apply(a_ty) => {
|
||||
a_ty.parameters.walk_mut(f);
|
||||
}
|
||||
Ty::Projection(p_ty) => {
|
||||
p_ty.parameters.walk_mut(f);
|
||||
}
|
||||
Ty::UnselectedProjection(p_ty) => {
|
||||
p_ty.parameters.walk_mut(f);
|
||||
}
|
||||
Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
|
||||
let mut v: Vec<_> = predicates.iter().cloned().collect();
|
||||
for p in &mut v {
|
||||
p.walk_mut(f);
|
||||
}
|
||||
*predicates = v.into();
|
||||
}
|
||||
Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
|
||||
}
|
||||
f(self);
|
||||
}
|
||||
|
||||
fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Ty {
|
||||
self.walk_mut(&mut |ty_mut| {
|
||||
let ty = mem::replace(ty_mut, Ty::Unknown);
|
||||
*ty_mut = f(ty);
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
pub fn as_reference(&self) -> Option<(&Ty, Mutability)> {
|
||||
match self {
|
||||
Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(mutability), parameters }) => {
|
||||
|
@ -596,26 +524,6 @@ impl Ty {
|
|||
}
|
||||
}
|
||||
|
||||
/// Replaces type parameters in this type using the given `Substs`. (So e.g.
|
||||
/// if `self` is `&[T]`, where type parameter T has index 0, and the
|
||||
/// `Substs` contain `u32` at index 0, we'll have `&[u32]` afterwards.)
|
||||
pub fn subst(self, substs: &Substs) -> Ty {
|
||||
self.fold(&mut |ty| match ty {
|
||||
Ty::Param { idx, name } => {
|
||||
substs.get(idx as usize).cloned().unwrap_or(Ty::Param { idx, name })
|
||||
}
|
||||
ty => ty,
|
||||
})
|
||||
}
|
||||
|
||||
/// Substitutes `Ty::Bound` vars (as opposed to type parameters).
|
||||
pub fn subst_bound_vars(self, substs: &Substs) -> Ty {
|
||||
self.fold(&mut |ty| match ty {
|
||||
Ty::Bound(idx) => substs.get(idx as usize).cloned().unwrap_or_else(|| Ty::Bound(idx)),
|
||||
ty => ty,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the type parameters of this type if it has some (i.e. is an ADT
|
||||
/// or function); so if `self` is `Option<u32>`, this returns the `u32`.
|
||||
pub fn substs(&self) -> Option<Substs> {
|
||||
|
@ -625,17 +533,6 @@ impl Ty {
|
|||
}
|
||||
}
|
||||
|
||||
/// Shifts up `Ty::Bound` vars by `n`.
|
||||
pub fn shift_bound_vars(self, n: i32) -> Ty {
|
||||
self.fold(&mut |ty| match ty {
|
||||
Ty::Bound(idx) => {
|
||||
assert!(idx as i32 >= -n);
|
||||
Ty::Bound((idx as i32 + n) as u32)
|
||||
}
|
||||
ty => ty,
|
||||
})
|
||||
}
|
||||
|
||||
/// If this is an `impl Trait` or `dyn Trait`, returns that trait.
|
||||
pub fn inherent_trait(&self) -> Option<Trait> {
|
||||
match self {
|
||||
|
@ -650,6 +547,116 @@ impl Ty {
|
|||
}
|
||||
}
|
||||
|
||||
/// This allows walking structures that contain types to do something with those
|
||||
/// types, similar to Chalk's `Fold` trait.
|
||||
pub trait TypeWalk {
|
||||
fn walk(&self, f: &mut impl FnMut(&Ty));
|
||||
fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty));
|
||||
|
||||
fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.walk_mut(&mut |ty_mut| {
|
||||
let ty = mem::replace(ty_mut, Ty::Unknown);
|
||||
*ty_mut = f(ty);
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
/// Replaces type parameters in this type using the given `Substs`. (So e.g.
|
||||
/// if `self` is `&[T]`, where type parameter T has index 0, and the
|
||||
/// `Substs` contain `u32` at index 0, we'll have `&[u32]` afterwards.)
|
||||
fn subst(self, substs: &Substs) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.fold(&mut |ty| match ty {
|
||||
Ty::Param { idx, name } => {
|
||||
substs.get(idx as usize).cloned().unwrap_or(Ty::Param { idx, name })
|
||||
}
|
||||
ty => ty,
|
||||
})
|
||||
}
|
||||
|
||||
/// Substitutes `Ty::Bound` vars (as opposed to type parameters).
|
||||
fn subst_bound_vars(self, substs: &Substs) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.fold(&mut |ty| match ty {
|
||||
Ty::Bound(idx) => substs.get(idx as usize).cloned().unwrap_or_else(|| Ty::Bound(idx)),
|
||||
ty => ty,
|
||||
})
|
||||
}
|
||||
|
||||
/// Shifts up `Ty::Bound` vars by `n`.
|
||||
fn shift_bound_vars(self, n: i32) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.fold(&mut |ty| match ty {
|
||||
Ty::Bound(idx) => {
|
||||
assert!(idx as i32 >= -n);
|
||||
Ty::Bound((idx as i32 + n) as u32)
|
||||
}
|
||||
ty => ty,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeWalk for Ty {
|
||||
fn walk(&self, f: &mut impl FnMut(&Ty)) {
|
||||
match self {
|
||||
Ty::Apply(a_ty) => {
|
||||
for t in a_ty.parameters.iter() {
|
||||
t.walk(f);
|
||||
}
|
||||
}
|
||||
Ty::Projection(p_ty) => {
|
||||
for t in p_ty.parameters.iter() {
|
||||
t.walk(f);
|
||||
}
|
||||
}
|
||||
Ty::UnselectedProjection(p_ty) => {
|
||||
for t in p_ty.parameters.iter() {
|
||||
t.walk(f);
|
||||
}
|
||||
}
|
||||
Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
|
||||
for p in predicates.iter() {
|
||||
p.walk(f);
|
||||
}
|
||||
}
|
||||
Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
|
||||
}
|
||||
f(self);
|
||||
}
|
||||
|
||||
fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
|
||||
match self {
|
||||
Ty::Apply(a_ty) => {
|
||||
a_ty.parameters.walk_mut(f);
|
||||
}
|
||||
Ty::Projection(p_ty) => {
|
||||
p_ty.parameters.walk_mut(f);
|
||||
}
|
||||
Ty::UnselectedProjection(p_ty) => {
|
||||
p_ty.parameters.walk_mut(f);
|
||||
}
|
||||
Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
|
||||
let mut v: Vec<_> = predicates.iter().cloned().collect();
|
||||
for p in &mut v {
|
||||
p.walk_mut(f);
|
||||
}
|
||||
*predicates = v.into();
|
||||
}
|
||||
Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
|
||||
}
|
||||
f(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for &Ty {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
|
||||
HirDisplay::hir_fmt(*self, f)
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::iter::successors;
|
|||
|
||||
use log::{info, warn};
|
||||
|
||||
use super::{traits::Solution, Canonical, Ty};
|
||||
use super::{traits::Solution, Canonical, Ty, TypeWalk};
|
||||
use crate::{HasGenericParams, HirDatabase, Name, Resolver};
|
||||
|
||||
const AUTODEREF_RECURSION_LIMIT: usize = 10;
|
||||
|
|
|
@ -30,7 +30,7 @@ use super::{
|
|||
autoderef, lower, method_resolution, op, primitive,
|
||||
traits::{Guidance, Obligation, ProjectionPredicate, Solution},
|
||||
ApplicationTy, CallableDef, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef,
|
||||
Ty, TypableDef, TypeCtor,
|
||||
Ty, TypableDef, TypeCtor, TypeWalk,
|
||||
};
|
||||
use crate::{
|
||||
adt::VariantDef,
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use super::{InferenceContext, Obligation};
|
||||
use crate::db::HirDatabase;
|
||||
use crate::ty::{
|
||||
Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty,
|
||||
Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty, TypeWalk,
|
||||
};
|
||||
|
||||
impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||
|
|
|
@ -10,6 +10,7 @@ use std::sync::Arc;
|
|||
|
||||
use super::{
|
||||
FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
|
||||
TypeWalk,
|
||||
};
|
||||
use crate::{
|
||||
adt::VariantDef,
|
||||
|
|
|
@ -8,7 +8,7 @@ use ra_db::salsa;
|
|||
use ra_prof::profile;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty};
|
||||
use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk};
|
||||
use crate::{db::HirDatabase, Crate, ImplBlock, Trait};
|
||||
|
||||
use self::chalk::{from_chalk, ToChalk};
|
||||
|
@ -138,25 +138,13 @@ pub struct ProjectionPredicate {
|
|||
pub ty: Ty,
|
||||
}
|
||||
|
||||
impl ProjectionPredicate {
|
||||
pub fn subst(mut self, substs: &super::Substs) -> ProjectionPredicate {
|
||||
self.walk_mut(&mut |ty| match ty {
|
||||
Ty::Param { idx, .. } => {
|
||||
if let Some(t) = substs.get(*idx as usize).cloned() {
|
||||
*ty = t;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
|
||||
impl TypeWalk for ProjectionPredicate {
|
||||
fn walk(&self, f: &mut impl FnMut(&Ty)) {
|
||||
self.projection_ty.walk(f);
|
||||
self.ty.walk(f);
|
||||
}
|
||||
|
||||
pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
|
||||
fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
|
||||
self.projection_ty.walk_mut(f);
|
||||
self.ty.walk_mut(f);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ use crate::{
|
|||
ty::display::HirDisplay,
|
||||
ty::{
|
||||
ApplicationTy, CallableDef, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
|
||||
TypeWalk,
|
||||
},
|
||||
Crate, HasGenericParams, ImplBlock, ImplItem, Trait, TypeAlias,
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//! This modules takes care of rendering various defenitions as completion items.
|
||||
use hir::{Docs, HasSource, HirDisplay, PerNs, Resolution, Ty};
|
||||
use hir::{Docs, HasSource, HirDisplay, PerNs, Resolution, Ty, TypeWalk};
|
||||
use join_to_string::join;
|
||||
use ra_syntax::ast::NameOwner;
|
||||
use test_utils::tested_by;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue