Skip to content

Commit

Permalink
cleanup CanonicalType
Browse files Browse the repository at this point in the history
  • Loading branch information
lzoghbi committed May 30, 2024
1 parent 45c0639 commit b0e2931
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 200 deletions.
109 changes: 23 additions & 86 deletions src/ident.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,120 +327,57 @@ impl CanonicalPath {
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
pub enum TypeKind {
RawPointer,
Callable(CallableKind),
DynTrait,
Generic,
UnionFld,
StaticMut,
Function,
#[default]
// Default case. Types that we have fully resolved
// and do not need extra information about.
// Default case for types that we
// don't need extra information about.
Plain,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum CallableKind {
Closure,
FnPtr,
FnOnce,
Other,

impl Display for TypeKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s = match self {
TypeKind::RawPointer => "raw pointer",
TypeKind::UnionFld => "union field",
TypeKind::StaticMut => "mutable static",
TypeKind::Function => "function",
TypeKind::Plain => "plain",
};
write!(f, "{}", s)
}
}

/// Type representing a type identifier.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
pub struct CanonicalType {
ty: String,
ty_kind: TypeKind,
trait_bounds: Vec<CanonicalPath>,
}
pub struct CanonicalType(TypeKind);

impl Display for CanonicalType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.ty.fmt(f)
self.0.fmt(f)
}
}

impl CanonicalType {
fn char_ok(c: char) -> bool {
c.is_ascii_alphanumeric() || "_-&*+#|!=',;:<>()[]{}? ".contains(c)
}

pub fn invariant(&self) -> bool {
self.ty.chars().all(Self::char_ok)
}

pub fn check_invariant(&self) {
if !self.invariant() {
warn!("failed invariant! on CanonicalType {}", self);
}
}

pub fn new(s: &str) -> Self {
Self::new_owned_string(s.to_string())
}

pub fn new_owned_string(s: String) -> Self {
Self::new_owned(s, vec![], Default::default())
}

pub fn new_owned(s: String, b: Vec<CanonicalPath>, k: TypeKind) -> Self {
let result = Self { ty: s, trait_bounds: b, ty_kind: k };
result.check_invariant();
result
}

pub fn as_str(&self) -> &str {
self.ty.as_str()
}

pub fn add_trait_bound(&mut self, trait_bound: CanonicalPath) {
self.trait_bounds.push(trait_bound)
}

pub fn get_trait_bounds(&self) -> &Vec<CanonicalPath> {
&self.trait_bounds
pub fn new(k: TypeKind) -> Self {
Self(k)
}

pub fn is_raw_ptr(&self) -> bool {
matches!(self.ty_kind, TypeKind::RawPointer)
}

pub fn is_callable(&self) -> bool {
matches!(&self.ty_kind, TypeKind::Callable(_))
}

pub fn is_dyn_trait(&self) -> bool {
matches!(self.ty_kind, TypeKind::DynTrait)
}

pub fn is_generic(&self) -> bool {
matches!(self.ty_kind, TypeKind::Generic)
}

pub fn is_closure(&self) -> bool {
matches!(&self.ty_kind, TypeKind::Callable(crate::ident::CallableKind::Closure))
matches!(self.0, TypeKind::RawPointer)
}

pub fn is_union_field(&self) -> bool {
matches!(self.ty_kind, TypeKind::UnionFld)
matches!(self.0, TypeKind::UnionFld)
}

pub fn is_mut_static(&self) -> bool {
matches!(self.ty_kind, TypeKind::StaticMut)
matches!(self.0, TypeKind::StaticMut)
}

pub fn is_function(&self) -> bool {
matches!(self.ty_kind, TypeKind::Function)
}

pub fn is_fn_ptr(&self) -> bool {
matches!(&self.ty_kind, TypeKind::Callable(crate::ident::CallableKind::FnPtr))
}

pub fn get_callable_kind(&self) -> Option<CallableKind> {
if let TypeKind::Callable(kind) = &self.ty_kind {
return Some(kind.clone());
}
None
matches!(self.0, TypeKind::Function)
}
}

Expand Down
16 changes: 4 additions & 12 deletions src/resolution/hacky_resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,8 @@ impl<'a> Resolve<'a> for HackyResolver<'a> {
Self::aggregate_path(self.filepath, &self.lookup_path_vec(p))
}

fn resolve_path_type(&self, p: &'a syn::Path) -> CanonicalType {
Self::aggregate_path_type(&self.lookup_path_vec(p))
fn resolve_path_type(&self, _: &'a syn::Path) -> CanonicalType {
CanonicalType::new(Default::default())
}

fn resolve_def(&self, i: &'a syn::Ident) -> CanonicalPath {
Expand Down Expand Up @@ -199,8 +199,8 @@ impl<'a> Resolve<'a> for HackyResolver<'a> {
CanonicalPath::new_owned(format!("UNKNOWN_FIELD::{}", i), src_loc)
}

fn resolve_field_type(&self, i: &syn::Ident) -> CanonicalType {
CanonicalType::new_owned_string(format!("UNKNOWN_TYPE::{}", i))
fn resolve_field_type(&self, _: &syn::Ident) -> CanonicalType {
CanonicalType::new(Default::default())
}

fn resolve_field_index(&self, idx: &'a syn::Index) -> CanonicalPath {
Expand Down Expand Up @@ -467,12 +467,4 @@ impl<'a> HackyResolver<'a> {
}
CanonicalPath::from_path(result, SrcLoc::from_span(fp, &span))
}

fn aggregate_path_type(p: &[&'a syn::Ident]) -> CanonicalType {
let mut result = IdentPath::new_empty();
for &i in p {
result.push_ident(&ident_from_syn(i));
}
CanonicalType::new_owned_string(result.to_string())
}
}
2 changes: 1 addition & 1 deletion src/resolution/name_resolution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ impl<'a> ResolverImpl<'a> {
let token = self.token(i, s)?;
let def = self.find_def(&token)?;

get_canonical_type(&self.sems, self.db, &def)
get_canonical_type(self.db, &def)
}

pub fn is_ffi(&self, s: SrcLoc, i: Ident) -> Result<bool> {
Expand Down
108 changes: 7 additions & 101 deletions src/resolution/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use ra_ap_hir_expand::InFile;
use crate::ident::{CanonicalPath, CanonicalType, Ident, TypeKind};

use ra_ap_hir::{
Adt, AsAssocItem, AssocItemContainer, DefWithBody, GenericParam, HasSource,
HirDisplay, Module, ModuleSource, Semantics, VariantDef,
Adt, AsAssocItem, AssocItemContainer, DefWithBody, GenericParam, HasSource, Module,
ModuleSource, Semantics, VariantDef,
};

use ra_ap_hir_expand::name::AsName;
Expand Down Expand Up @@ -206,32 +206,12 @@ fn get_container_name(
container_names
}

// Get the fully resolved type of a definition.
// e.g in pub fn test() -> Option<&(dyn Error + 'static)> { None }
// the type of function 'test' is core::option::Option<&dyn core::error::Error>
/// Type resolution
pub(super) fn get_canonical_type(
sems: &Semantics<RootDatabase>,
db: &RootDatabase,
def: &Definition,
) -> Result<CanonicalType> {
let mut type_defs: Vec<Definition> = Vec::new();
let mut trait_bounds: Vec<CanonicalPath> = Vec::new();
let mut ty_kind = TypeKind::Plain;
let mut type_;

let mut push = |d| {
if !type_defs.contains(&d) {
type_defs.push(d);
}
};

let mut resolve_bounds = |tr| {
if let Some(b) = canonical_path(sems, db, &tr) {
if !trait_bounds.contains(&b) {
trait_bounds.push(b);
}
}
};

let ty = match def {
Definition::Adt(it) => Some(it.ty(db)),
Expand All @@ -256,92 +236,18 @@ pub(super) fn get_canonical_type(
}
Some(it.ty(db))
}
Definition::GenericParam(GenericParam::TypeParam(it)) => {
it.trait_bounds(db).into_iter().for_each(|it| resolve_bounds(it.into()));
Some(it.ty(db))
}
Definition::GenericParam(GenericParam::TypeParam(it)) => Some(it.ty(db)),
Definition::GenericParam(GenericParam::ConstParam(it)) => Some(it.ty(db)),
Definition::Variant(_) => {
match canonical_path(sems, db, def) {
Some(cp) => {
return Ok(CanonicalType::new_owned(
cp.as_str().to_string(),
vec![],
ty_kind,
))
}
None => {
return Err(anyhow!(
"Could not resolve type for definition {:?}",
def.name(db)
))
}
};
}
Definition::Variant(_) => return Ok(CanonicalType::new(ty_kind)),
_ => None,
};

if ty.is_none()
/*|| (ty.is_some() && ty.clone().unwrap().contains_unknown())*/
{
return Err(anyhow!("Could not resolve type for definition {:?}", def.name(db)));
}
.ok_or_else(|| anyhow!("Could not resolve type for definition {:?}", def.name(db)))?;

let ty = ty.unwrap();
if ty.impls_fnonce(db) {
// impls_fnonce can be used in RA to check if a type is callable.
// FnOnce is a supertait of FnMut and Fn, so any callable type
// implements at least FnOnce.
// TODO: More sophisticated checks are needed to precisely
// determine which trait is actually implemented.
ty_kind = TypeKind::Callable(crate::ident::CallableKind::FnOnce)
}
if ty.is_closure() {
ty_kind = TypeKind::Callable(crate::ident::CallableKind::Closure)
}
if ty.is_fn() {
ty_kind = TypeKind::Callable(crate::ident::CallableKind::FnPtr)
}
if ty.is_raw_ptr() {
ty_kind = TypeKind::RawPointer
}
if ty.as_dyn_trait().is_some() {
ty_kind = TypeKind::DynTrait
}
if ty.as_type_param(db).is_some() {
ty_kind = TypeKind::Generic
}

// Get the type as it is displayed by rust-analyzer
type_ = ty.display(db).to_string();

// Walk type and gather all Enums, Structs, Unions,
// or Traits it contains to fully resolve them
ty.walk(db, |t| {
if let Some(adt) = t.as_adt() {
push(adt.into());
} else if let Some(trait_) = t.as_dyn_trait() {
push(trait_.into());
} else if let Some(traits) = t.as_impl_traits(db) {
traits.for_each(|it| push(it.into()));
} else if let Some(trait_) = t.as_associated_type_parent_trait(db) {
push(trait_.into());
}
});

// Resolve types.
// e.g 'Option' resolves to 'core::option::Option'.
type_defs.into_iter().for_each(|it| {
type_ = canonical_path(sems, db, &it).map_or(type_.clone(), |cp| {
type_.replace(
name_to_string(it.name(db).expect("Definition should a have name"))
.as_str(),
cp.as_str(),
)
})
});

Ok(CanonicalType::new_owned(type_, trait_bounds, ty_kind))
Ok(CanonicalType::new(ty_kind))
}

/// Get source node from the original source
Expand Down

0 comments on commit b0e2931

Please sign in to comment.