From 4926bed42680d329f906be93450bec6b2ba0e99b Mon Sep 17 00:00:00 2001 From: uHOOCCOOHu Date: Thu, 12 Sep 2019 02:01:07 +0800 Subject: Support path starting with a type --- crates/ra_hir/src/expr/validation.rs | 14 ++-- crates/ra_hir/src/nameres.rs | 12 +++- crates/ra_hir/src/path.rs | 81 +++++++++++++++-------- crates/ra_hir/src/resolve.rs | 28 ++++---- crates/ra_hir/src/source_binder.rs | 14 ++-- crates/ra_hir/src/ty/infer.rs | 120 ++++++++++++++++------------------- crates/ra_hir/src/ty/tests.rs | 58 +++++++++++++++++ 7 files changed, 203 insertions(+), 124 deletions(-) (limited to 'crates/ra_hir/src') diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs index 030ec53a2..c675bf8de 100644 --- a/crates/ra_hir/src/expr/validation.rs +++ b/crates/ra_hir/src/expr/validation.rs @@ -8,7 +8,7 @@ use crate::{ diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr}, expr::AstPtr, name, - path::{PathKind, PathSegment}, + path::PathKind, ty::{ApplicationTy, InferenceResult, Ty, TypeCtor}, Adt, Function, Name, Path, }; @@ -108,14 +108,10 @@ impl<'a, 'b> ExprValidator<'a, 'b> { None => return, }; - let std_result_path = Path { - kind: PathKind::Abs, - segments: vec![ - PathSegment { name: name::STD, args_and_bindings: None }, - PathSegment { name: name::RESULT_MOD, args_and_bindings: None }, - PathSegment { name: name::RESULT_TYPE, args_and_bindings: None }, - ], - }; + let std_result_path = Path::from_simple_segments( + PathKind::Abs, + vec![name::STD, name::RESULT_MOD, name::RESULT_TYPE], + ); let resolver = self.func.resolver(db); let std_result_enum = match resolver.resolve_known_enum(db, &std_result_path) { diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 7922e3f7e..be1cc76b6 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs @@ -382,6 +382,11 @@ impl CrateDefMap { return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude } } + PathKind::Type => { + // This is handled in `infer::infer_path_expr` + // The result returned here does not matter + return ResolvePathResult::empty(ReachedFixedPoint::Yes); + } }; for (i, segment) in segments { @@ -401,8 +406,11 @@ impl CrateDefMap { curr_per_ns = match curr { ModuleDef::Module(module) => { if module.krate != self.krate { - let path = - Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ }; + let path = Path { + segments: path.segments[i..].to_vec(), + kind: PathKind::Self_, + type_ref: None, + }; log::debug!("resolving {:?} in other crate", path); let defp_map = db.crate_def_map(module.krate); let (def, s) = defp_map.resolve_path(db, module.module_id, &path); diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index d6c78593b..7c19fda14 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs @@ -1,4 +1,4 @@ -use std::sync::Arc; +use std::{iter, sync::Arc}; use ra_syntax::{ ast::{self, NameOwner, TypeAscriptionOwner}, @@ -10,6 +10,7 @@ use crate::{name, type_ref::TypeRef, AsName, Name}; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Path { pub kind: PathKind, + pub type_ref: Option>, pub segments: Vec, } @@ -50,6 +51,8 @@ pub enum PathKind { Crate, // Absolute path Abs, + // Type based path like `::foo` + Type, } impl Path { @@ -63,10 +66,22 @@ impl Path { } } + pub fn from_simple_segments(kind: PathKind, segments: impl IntoIterator) -> Path { + Path { + kind, + type_ref: None, + segments: segments + .into_iter() + .map(|name| PathSegment { name, args_and_bindings: None }) + .collect(), + } + } + /// Converts an `ast::Path` to `Path`. Works with use trees. pub fn from_ast(mut path: ast::Path) -> Option { let mut kind = PathKind::Plain; let mut segments = Vec::new(); + let mut path_type_ref = None; loop { let segment = path.segment()?; @@ -92,24 +107,33 @@ impl Path { ast::PathSegmentKind::Type { type_ref, trait_ref } => { assert!(path.qualifier().is_none()); // this can only occur at the first segment - // FIXME: handle syntax (type segments without trait) - - // >::Foo desugars to Trait::Foo - let path = Path::from_ast(trait_ref?.path()?)?; - kind = path.kind; - let mut prefix_segments = path.segments; - prefix_segments.reverse(); - segments.extend(prefix_segments); - // Insert the type reference (T in the above example) as Self parameter for the trait let self_type = TypeRef::from_ast(type_ref?); - let mut last_segment = segments.last_mut()?; - if last_segment.args_and_bindings.is_none() { - last_segment.args_and_bindings = Some(Arc::new(GenericArgs::empty())); - }; - let args = last_segment.args_and_bindings.as_mut().unwrap(); - let mut args_inner = Arc::make_mut(args); - args_inner.has_self_type = true; - args_inner.args.insert(0, GenericArg::Type(self_type)); + + match trait_ref { + // ::foo + None => { + kind = PathKind::Type; + path_type_ref = Some(Box::new(self_type)); + } + // >::Foo desugars to Trait::Foo + Some(trait_ref) => { + let path = Path::from_ast(trait_ref.path()?)?; + kind = path.kind; + let mut prefix_segments = path.segments; + prefix_segments.reverse(); + segments.extend(prefix_segments); + // Insert the type reference (T in the above example) as Self parameter for the trait + let mut last_segment = segments.last_mut()?; + if last_segment.args_and_bindings.is_none() { + last_segment.args_and_bindings = + Some(Arc::new(GenericArgs::empty())); + }; + let args = last_segment.args_and_bindings.as_mut().unwrap(); + let mut args_inner = Arc::make_mut(args); + args_inner.has_self_type = true; + args_inner.args.insert(0, GenericArg::Type(self_type)); + } + } } ast::PathSegmentKind::CrateKw => { kind = PathKind::Crate; @@ -130,7 +154,7 @@ impl Path { }; } segments.reverse(); - return Some(Path { kind, segments }); + return Some(Path { kind, type_ref: path_type_ref, segments }); fn qualifier(path: &ast::Path) -> Option { if let Some(q) = path.qualifier() { @@ -230,10 +254,7 @@ impl GenericArgs { impl From for Path { fn from(name: Name) -> Path { - Path { - kind: PathKind::Plain, - segments: vec![PathSegment { name, args_and_bindings: None }], - } + Path::from_simple_segments(PathKind::Plain, iter::once(name)) } } @@ -287,8 +308,12 @@ fn convert_path(prefix: Option, path: ast::Path) -> Option { let segment = path.segment()?; let res = match segment.kind()? { ast::PathSegmentKind::Name(name) => { - let mut res = prefix - .unwrap_or_else(|| Path { kind: PathKind::Plain, segments: Vec::with_capacity(1) }); + // no type args in use + let mut res = prefix.unwrap_or_else(|| Path { + kind: PathKind::Plain, + type_ref: None, + segments: Vec::with_capacity(1), + }); res.segments.push(PathSegment { name: name.as_name(), args_and_bindings: None, // no type args in use @@ -299,19 +324,19 @@ fn convert_path(prefix: Option, path: ast::Path) -> Option { if prefix.is_some() { return None; } - Path { kind: PathKind::Crate, segments: Vec::new() } + Path::from_simple_segments(PathKind::Crate, iter::empty()) } ast::PathSegmentKind::SelfKw => { if prefix.is_some() { return None; } - Path { kind: PathKind::Self_, segments: Vec::new() } + Path::from_simple_segments(PathKind::Self_, iter::empty()) } ast::PathSegmentKind::SuperKw => { if prefix.is_some() { return None; } - Path { kind: PathKind::Super, segments: Vec::new() } + Path::from_simple_segments(PathKind::Super, iter::empty()) } ast::PathSegmentKind::Type { .. } => { // not allowed in imports diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 3207b6626..e357c74e3 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -15,6 +15,7 @@ use crate::{ name::{Name, SELF_PARAM, SELF_TYPE}, nameres::{CrateDefMap, CrateModuleId, PerNs}, path::{Path, PathKind}, + type_ref::TypeRef, Adt, BuiltinType, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, Static, Struct, Trait, TypeAlias, }; @@ -64,9 +65,10 @@ pub enum TypeNs { } #[derive(Debug)] -pub enum ValueOrPartial { +pub enum ResolveValueResult<'a> { ValueNs(ValueNs), Partial(TypeNs, usize), + TypeRef(&'a TypeRef), } #[derive(Debug)] @@ -183,11 +185,15 @@ impl Resolver { Some(res) } - pub(crate) fn resolve_path_in_value_ns( + pub(crate) fn resolve_path_in_value_ns<'p>( &self, db: &impl HirDatabase, - path: &Path, - ) -> Option { + path: &'p Path, + ) -> Option> { + if let Some(type_ref) = &path.type_ref { + return Some(ResolveValueResult::TypeRef(type_ref)); + } + let n_segments = path.segments.len(); let tmp = SELF_PARAM; let first_name = if path.is_self() { &tmp } else { &path.segments.first()?.name }; @@ -208,7 +214,7 @@ impl Resolver { .find(|entry| entry.name() == first_name); if let Some(e) = entry { - return Some(ValueOrPartial::ValueNs(ValueNs::LocalBinding(e.pat()))); + return Some(ResolveValueResult::ValueNs(ValueNs::LocalBinding(e.pat()))); } } Scope::ExprScope(_) => continue, @@ -216,7 +222,7 @@ impl Resolver { Scope::GenericParams(params) if n_segments > 1 => { if let Some(param) = params.find_by_name(first_name) { let ty = TypeNs::GenericParam(param.idx); - return Some(ValueOrPartial::Partial(ty, 1)); + return Some(ResolveValueResult::Partial(ty, 1)); } } Scope::GenericParams(_) => continue, @@ -224,7 +230,7 @@ impl Resolver { Scope::ImplBlockScope(impl_) if n_segments > 1 => { if first_name == &SELF_TYPE { let ty = TypeNs::SelfType(*impl_); - return Some(ValueOrPartial::Partial(ty, 1)); + return Some(ResolveValueResult::Partial(ty, 1)); } } Scope::ImplBlockScope(_) => continue, @@ -247,7 +253,7 @@ impl Resolver { | ModuleDef::BuiltinType(_) | ModuleDef::Module(_) => return None, }; - Some(ValueOrPartial::ValueNs(value)) + Some(ResolveValueResult::ValueNs(value)) } Some(idx) => { let ty = match module_def.take_types()? { @@ -262,7 +268,7 @@ impl Resolver { | ModuleDef::Const(_) | ModuleDef::Static(_) => return None, }; - Some(ValueOrPartial::Partial(ty, idx)) + Some(ResolveValueResult::Partial(ty, idx)) } }; } @@ -277,8 +283,8 @@ impl Resolver { path: &Path, ) -> Option { match self.resolve_path_in_value_ns(db, path)? { - ValueOrPartial::ValueNs(it) => Some(it), - ValueOrPartial::Partial(..) => None, + ResolveValueResult::ValueNs(it) => Some(it), + ResolveValueResult::Partial(..) | ResolveValueResult::TypeRef(_) => None, } } diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index cff55b640..59053cda3 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -26,7 +26,7 @@ use crate::{ }, ids::LocationCtx, name, - path::{PathKind, PathSegment}, + path::PathKind, resolve::{ScopeDef, TypeNs, ValueNs}, ty::method_resolution::implements_trait, AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HasBody, HirFileId, MacroDef, @@ -433,14 +433,10 @@ impl SourceAnalyzer { /// Checks that particular type `ty` implements `std::future::Future`. /// This function is used in `.await` syntax completion. pub fn impls_future(&self, db: &impl HirDatabase, ty: Ty) -> bool { - let std_future_path = Path { - kind: PathKind::Abs, - segments: vec![ - PathSegment { name: name::STD, args_and_bindings: None }, - PathSegment { name: name::FUTURE_MOD, args_and_bindings: None }, - PathSegment { name: name::FUTURE_TYPE, args_and_bindings: None }, - ], - }; + let std_future_path = Path::from_simple_segments( + PathKind::Abs, + vec![name::STD, name::FUTURE_MOD, name::FUTURE_TYPE], + ); let std_future_trait = match self.resolver.resolve_known_trait(db, &std_future_path) { Some(it) => it, diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index bf57bb3b7..3981de829 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -44,11 +44,12 @@ use crate::{ generics::{GenericParams, HasGenericParams}, name, nameres::Namespace, - path::{GenericArg, GenericArgs, PathKind, PathSegment}, - resolve::{Resolver, TypeNs, ValueNs, ValueOrPartial}, + path::{GenericArg, GenericArgs, PathKind}, + resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, ty::infer::diagnostics::InferenceDiagnostic, type_ref::{Mutability, TypeRef}, - Adt, ConstData, DefWithBody, FnData, Function, HasBody, ImplItem, Name, Path, StructField, + Adt, ConstData, DefWithBody, Either, FnData, Function, HasBody, ImplItem, Name, Path, + StructField, }; mod unify; @@ -470,9 +471,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?; let (value, self_subst) = match value_or_partial { - ValueOrPartial::ValueNs(it) => (it, None), - ValueOrPartial::Partial(def, remaining_index) => { - self.resolve_assoc_item(def, path, remaining_index, id)? + ResolveValueResult::ValueNs(it) => (it, None), + ResolveValueResult::Partial(def, remaining_index) => { + self.resolve_assoc_item(Either::A(def), path, remaining_index, id)? + } + ResolveValueResult::TypeRef(type_ref) => { + let ty = self.make_ty(type_ref); + self.resolve_assoc_item(Either::B(ty), path, 0, id)? } }; @@ -503,7 +508,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { fn resolve_assoc_item( &mut self, - mut def: TypeNs, + mut def_or_ty: Either, path: &Path, remaining_index: usize, id: ExprOrPatId, @@ -516,30 +521,33 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // resolve intermediate segments for (i, segment) in path.segments[remaining_index..].iter().enumerate() { let is_last_segment = i == path.segments[remaining_index..].len() - 1; - ty = { - let typable: TypableDef = match def { - TypeNs::Adt(it) => it.into(), - TypeNs::TypeAlias(it) => it.into(), - TypeNs::BuiltinType(it) => it.into(), - // FIXME associated item of traits, generics, and Self - TypeNs::Trait(_) | TypeNs::GenericParam(_) | TypeNs::SelfType(_) => { - return None; - } - // FIXME: report error here - TypeNs::EnumVariant(_) => return None, - }; - - let ty = self.db.type_for_def(typable, Namespace::Types); + ty = match def_or_ty { + Either::A(def) => { + let typable: TypableDef = match def { + TypeNs::Adt(it) => it.into(), + TypeNs::TypeAlias(it) => it.into(), + TypeNs::BuiltinType(it) => it.into(), + // FIXME associated item of traits, generics, and Self + TypeNs::Trait(_) | TypeNs::GenericParam(_) | TypeNs::SelfType(_) => { + return None; + } + // FIXME: report error here + TypeNs::EnumVariant(_) => return None, + }; - // For example, this substs will take `Gen::**::make` - assert!(remaining_index > 0); - let substs = Ty::substs_from_path_segment( - self.db, - &self.resolver, - &path.segments[remaining_index + i - 1], - typable, - ); - ty.subst(&substs) + let ty = self.db.type_for_def(typable, Namespace::Types); + + // For example, this substs will take `Gen::**::make` + assert!(remaining_index > 0); + let substs = Ty::substs_from_path_segment( + self.db, + &self.resolver, + &path.segments[remaining_index + i - 1], + typable, + ); + ty.subst(&substs) + } + Either::B(ty) => ty, }; if is_last_segment { break; @@ -550,15 +558,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { log::debug!("looking for path segment: {:?}", segment); let ty = mem::replace(&mut ty, Ty::Unknown); - def = ty.iterate_impl_items(self.db, krate, |item| { + def_or_ty = ty.iterate_impl_items(self.db, krate, |item| { match item { crate::ImplItem::Method(_) => None, crate::ImplItem::Const(_) => None, // FIXME: Resolve associated types crate::ImplItem::TypeAlias(_) => { - // Some(TypeNs::TypeAlias(..)) - None:: + // Some(Either::A(TypeNs::TypeAlias(..))) + None } } })?; @@ -1434,56 +1442,38 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } fn resolve_into_iter_item(&self) -> Option { - let into_iter_path = Path { - kind: PathKind::Abs, - segments: vec![ - PathSegment { name: name::STD, args_and_bindings: None }, - PathSegment { name: name::ITER, args_and_bindings: None }, - PathSegment { name: name::INTO_ITERATOR, args_and_bindings: None }, - ], - }; + let into_iter_path = Path::from_simple_segments( + PathKind::Abs, + vec![name::STD, name::ITER, name::INTO_ITERATOR], + ); let trait_ = self.resolver.resolve_known_trait(self.db, &into_iter_path)?; trait_.associated_type_by_name(self.db, &name::ITEM) } fn resolve_ops_try_ok(&self) -> Option { - let ops_try_path = Path { - kind: PathKind::Abs, - segments: vec![ - PathSegment { name: name::STD, args_and_bindings: None }, - PathSegment { name: name::OPS, args_and_bindings: None }, - PathSegment { name: name::TRY, args_and_bindings: None }, - ], - }; + let ops_try_path = + Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::TRY]); let trait_ = self.resolver.resolve_known_trait(self.db, &ops_try_path)?; trait_.associated_type_by_name(self.db, &name::OK) } fn resolve_future_future_output(&self) -> Option { - let future_future_path = Path { - kind: PathKind::Abs, - segments: vec![ - PathSegment { name: name::STD, args_and_bindings: None }, - PathSegment { name: name::FUTURE_MOD, args_and_bindings: None }, - PathSegment { name: name::FUTURE_TYPE, args_and_bindings: None }, - ], - }; + let future_future_path = Path::from_simple_segments( + PathKind::Abs, + vec![name::STD, name::FUTURE_MOD, name::FUTURE_TYPE], + ); let trait_ = self.resolver.resolve_known_trait(self.db, &future_future_path)?; trait_.associated_type_by_name(self.db, &name::OUTPUT) } fn resolve_boxed_box(&self) -> Option { - let boxed_box_path = Path { - kind: PathKind::Abs, - segments: vec![ - PathSegment { name: name::STD, args_and_bindings: None }, - PathSegment { name: name::BOXED_MOD, args_and_bindings: None }, - PathSegment { name: name::BOX_TYPE, args_and_bindings: None }, - ], - }; + let boxed_box_path = Path::from_simple_segments( + PathKind::Abs, + vec![name::STD, name::BOXED_MOD, name::BOX_TYPE], + ); let struct_ = self.resolver.resolve_known_struct(self.db, &boxed_box_path)?; Some(Adt::Struct(struct_)) } diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index f6a2a658f..1bd677cab 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -281,6 +281,64 @@ fn test() { ); } +#[test] +fn infer_path_type() { + assert_snapshot!( + infer(r#" +struct S; + +impl S { + fn foo() -> i32 { 1 } +} + +fn test() { + S::foo(); + ::foo(); +} +"#), + @r###" + [41; 46) '{ 1 }': i32 + [43; 44) '1': i32 + [60; 93) '{ ...o(); }': () + [66; 72) 'S::foo': fn foo() -> i32 + [66; 74) 'S::foo()': i32 + [80; 88) '::foo': fn foo() -> i32 + [80; 90) '::foo()': i32 +"### + ); +} + +#[test] +fn infer_slice_method() { + assert_snapshot!( + infer(r#" +#[lang = "slice"] +impl [T] { + fn foo(&self) -> T { + loop {} + } +} + +#[lang = "slice_alloc"] +impl [T] {} + +fn test() { + <[_]>::foo(b"foo"); +} +"#), + @r###" + [45; 49) 'self': &[T] + [56; 79) '{ ... }': ! + [66; 73) 'loop {}': ! + [71; 73) '{}': () + [133; 160) '{ ...o"); }': () + [139; 149) '<[_]>::foo': fn foo(&[T]) -> T + [139; 157) '<[_]>:..."foo")': u8 + [150; 156) 'b"foo"': &[u8] +"### + ); +} + #[test] fn infer_struct() { assert_snapshot!( -- cgit v1.2.3 From de9670fe456d89f97e8044d4e0919d2c16d1087f Mon Sep 17 00:00:00 2001 From: uHOOCCOOHu Date: Sun, 15 Sep 2019 19:48:24 +0800 Subject: Move store TypeRef of type based path in PathKind --- crates/ra_hir/src/nameres.rs | 9 +++------ crates/ra_hir/src/path.rs | 19 ++++++------------- crates/ra_hir/src/resolve.rs | 2 +- 3 files changed, 10 insertions(+), 20 deletions(-) (limited to 'crates/ra_hir/src') diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index be1cc76b6..b808a0c36 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs @@ -382,7 +382,7 @@ impl CrateDefMap { return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude } } - PathKind::Type => { + PathKind::Type(_) => { // This is handled in `infer::infer_path_expr` // The result returned here does not matter return ResolvePathResult::empty(ReachedFixedPoint::Yes); @@ -406,11 +406,8 @@ impl CrateDefMap { curr_per_ns = match curr { ModuleDef::Module(module) => { if module.krate != self.krate { - let path = Path { - segments: path.segments[i..].to_vec(), - kind: PathKind::Self_, - type_ref: None, - }; + let path = + Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ }; log::debug!("resolving {:?} in other crate", path); let defp_map = db.crate_def_map(module.krate); let (def, s) = defp_map.resolve_path(db, module.module_id, &path); diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index 7c19fda14..9e449f6cc 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs @@ -10,7 +10,6 @@ use crate::{name, type_ref::TypeRef, AsName, Name}; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Path { pub kind: PathKind, - pub type_ref: Option>, pub segments: Vec, } @@ -43,7 +42,7 @@ pub enum GenericArg { // or lifetime... } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum PathKind { Plain, Self_, @@ -52,7 +51,7 @@ pub enum PathKind { // Absolute path Abs, // Type based path like `::foo` - Type, + Type(Box), } impl Path { @@ -69,7 +68,6 @@ impl Path { pub fn from_simple_segments(kind: PathKind, segments: impl IntoIterator) -> Path { Path { kind, - type_ref: None, segments: segments .into_iter() .map(|name| PathSegment { name, args_and_bindings: None }) @@ -81,7 +79,6 @@ impl Path { pub fn from_ast(mut path: ast::Path) -> Option { let mut kind = PathKind::Plain; let mut segments = Vec::new(); - let mut path_type_ref = None; loop { let segment = path.segment()?; @@ -112,8 +109,7 @@ impl Path { match trait_ref { // ::foo None => { - kind = PathKind::Type; - path_type_ref = Some(Box::new(self_type)); + kind = PathKind::Type(Box::new(self_type)); } // >::Foo desugars to Trait::Foo Some(trait_ref) => { @@ -154,7 +150,7 @@ impl Path { }; } segments.reverse(); - return Some(Path { kind, type_ref: path_type_ref, segments }); + return Some(Path { kind, segments }); fn qualifier(path: &ast::Path) -> Option { if let Some(q) = path.qualifier() { @@ -309,11 +305,8 @@ fn convert_path(prefix: Option, path: ast::Path) -> Option { let res = match segment.kind()? { ast::PathSegmentKind::Name(name) => { // no type args in use - let mut res = prefix.unwrap_or_else(|| Path { - kind: PathKind::Plain, - type_ref: None, - segments: Vec::with_capacity(1), - }); + let mut res = prefix + .unwrap_or_else(|| Path { kind: PathKind::Plain, segments: Vec::with_capacity(1) }); res.segments.push(PathSegment { name: name.as_name(), args_and_bindings: None, // no type args in use diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index e357c74e3..bb6915901 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -190,7 +190,7 @@ impl Resolver { db: &impl HirDatabase, path: &'p Path, ) -> Option> { - if let Some(type_ref) = &path.type_ref { + if let PathKind::Type(type_ref) = &path.kind { return Some(ResolveValueResult::TypeRef(type_ref)); } -- cgit v1.2.3 From 7ed3be32916facf3b709d5277381408cd3ec134a Mon Sep 17 00:00:00 2001 From: uHOOCCOOHu Date: Sun, 15 Sep 2019 20:14:33 +0800 Subject: Define known paths and group names --- crates/ra_hir/src/expr/validation.rs | 8 ++------ crates/ra_hir/src/name.rs | 27 ++++++++++++++++---------- crates/ra_hir/src/path.rs | 30 ++++++++++++++++++++++++++++- crates/ra_hir/src/source_binder.rs | 8 ++------ crates/ra_hir/src/ty/autoderef.rs | 2 +- crates/ra_hir/src/ty/infer.rs | 37 ++++++++++++------------------------ 6 files changed, 63 insertions(+), 49 deletions(-) (limited to 'crates/ra_hir/src') diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs index c675bf8de..f06e5ec07 100644 --- a/crates/ra_hir/src/expr/validation.rs +++ b/crates/ra_hir/src/expr/validation.rs @@ -7,8 +7,7 @@ use crate::{ db::HirDatabase, diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr}, expr::AstPtr, - name, - path::PathKind, + path::known, ty::{ApplicationTy, InferenceResult, Ty, TypeCtor}, Adt, Function, Name, Path, }; @@ -108,10 +107,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { None => return, }; - let std_result_path = Path::from_simple_segments( - PathKind::Abs, - vec![name::STD, name::RESULT_MOD, name::RESULT_TYPE], - ); + let std_result_path = known::std_result_result(); let resolver = self.func.resolver(db); let std_result_enum = match resolver.resolve_known_enum(db, &std_result_path) { diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs index abdfec296..1bf993ffb 100644 --- a/crates/ra_hir/src/name.rs +++ b/crates/ra_hir/src/name.rs @@ -85,6 +85,7 @@ impl AsName for ra_db::Dependency { } } +// Primitives pub(crate) const ISIZE: Name = Name::new(SmolStr::new_inline_from_ascii(5, b"isize")); pub(crate) const I8: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"i8")); pub(crate) const I16: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"i16")); @@ -102,24 +103,30 @@ pub(crate) const F64: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"f64") pub(crate) const BOOL: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"bool")); pub(crate) const CHAR: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"char")); pub(crate) const STR: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"str")); + +// Special names pub(crate) const SELF_PARAM: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"self")); pub(crate) const SELF_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"Self")); pub(crate) const MACRO_RULES: Name = Name::new(SmolStr::new_inline_from_ascii(11, b"macro_rules")); + +// Components of known path (value or mod name) pub(crate) const STD: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"std")); pub(crate) const ITER: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"iter")); -pub(crate) const INTO_ITERATOR: Name = - Name::new(SmolStr::new_inline_from_ascii(12, b"IntoIterator")); -pub(crate) const ITEM: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"Item")); pub(crate) const OPS: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"ops")); -pub(crate) const TRY: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"Try")); -pub(crate) const OK: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"Ok")); -pub(crate) const FUTURE_MOD: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"future")); +pub(crate) const FUTURE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"future")); +pub(crate) const RESULT: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"result")); +pub(crate) const BOXED: Name = Name::new(SmolStr::new_inline_from_ascii(5, b"boxed")); + +// Components of known path (type name) +pub(crate) const INTO_ITERATOR_TYPE: Name = + Name::new(SmolStr::new_inline_from_ascii(12, b"IntoIterator")); +pub(crate) const ITEM_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"Item")); +pub(crate) const TRY_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"Try")); +pub(crate) const OK_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"Ok")); pub(crate) const FUTURE_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Future")); -pub(crate) const RESULT_MOD: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"result")); pub(crate) const RESULT_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Result")); -pub(crate) const OUTPUT: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Output")); -pub(crate) const TARGET: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Target")); -pub(crate) const BOXED_MOD: Name = Name::new(SmolStr::new_inline_from_ascii(5, b"boxed")); +pub(crate) const OUTPUT_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Output")); +pub(crate) const TARGET_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Target")); pub(crate) const BOX_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"Box")); fn resolve_name(text: &SmolStr) -> SmolStr { diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index 9e449f6cc..a61161b63 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs @@ -234,7 +234,7 @@ impl GenericArgs { } if let Some(ret_type) = ret_type { let type_ref = TypeRef::from_ast_opt(ret_type.type_ref()); - bindings.push((name::OUTPUT, type_ref)) + bindings.push((name::OUTPUT_TYPE, type_ref)) } if args.is_empty() && bindings.is_empty() { None @@ -338,3 +338,31 @@ fn convert_path(prefix: Option, path: ast::Path) -> Option { }; Some(res) } + +pub mod known { + use super::{Path, PathKind}; + use crate::name; + + pub fn std_iter_into_iterator() -> Path { + Path::from_simple_segments( + PathKind::Abs, + vec![name::STD, name::ITER, name::INTO_ITERATOR_TYPE], + ) + } + + pub fn std_ops_try() -> Path { + Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::TRY_TYPE]) + } + + pub fn std_result_result() -> Path { + Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::RESULT, name::RESULT_TYPE]) + } + + pub fn std_future_future() -> Path { + Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::FUTURE, name::FUTURE_TYPE]) + } + + pub fn std_boxed_box() -> Path { + Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::BOXED, name::BOX_TYPE]) + } +} diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 59053cda3..2a907c9f1 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -25,8 +25,7 @@ use crate::{ BodySourceMap, }, ids::LocationCtx, - name, - path::PathKind, + path::known, resolve::{ScopeDef, TypeNs, ValueNs}, ty::method_resolution::implements_trait, AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HasBody, HirFileId, MacroDef, @@ -433,10 +432,7 @@ impl SourceAnalyzer { /// Checks that particular type `ty` implements `std::future::Future`. /// This function is used in `.await` syntax completion. pub fn impls_future(&self, db: &impl HirDatabase, ty: Ty) -> bool { - let std_future_path = Path::from_simple_segments( - PathKind::Abs, - vec![name::STD, name::FUTURE_MOD, name::FUTURE_TYPE], - ); + let std_future_path = known::std_future_future(); let std_future_trait = match self.resolver.resolve_known_trait(db, &std_future_path) { Some(it) => it, diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs index 5ba7cf2e0..94f8ecdc9 100644 --- a/crates/ra_hir/src/ty/autoderef.rs +++ b/crates/ra_hir/src/ty/autoderef.rs @@ -42,7 +42,7 @@ fn deref_by_trait( crate::lang_item::LangItemTarget::Trait(t) => t, _ => return None, }; - let target = deref_trait.associated_type_by_name(db, &name::TARGET)?; + let target = deref_trait.associated_type_by_name(db, &name::TARGET_TYPE)?; if target.generic_params(db).count_params_including_parent() != 1 { // the Target type + Deref trait should only have one generic parameter, diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 3981de829..785499f77 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -44,7 +44,7 @@ use crate::{ generics::{GenericParams, HasGenericParams}, name, nameres::Namespace, - path::{GenericArg, GenericArgs, PathKind}, + path::{known, GenericArg, GenericArgs}, resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, ty::infer::diagnostics::InferenceDiagnostic, type_ref::{Mutability, TypeRef}, @@ -1442,39 +1442,26 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } fn resolve_into_iter_item(&self) -> Option { - let into_iter_path = Path::from_simple_segments( - PathKind::Abs, - vec![name::STD, name::ITER, name::INTO_ITERATOR], - ); - - let trait_ = self.resolver.resolve_known_trait(self.db, &into_iter_path)?; - trait_.associated_type_by_name(self.db, &name::ITEM) + let path = known::std_iter_into_iterator(); + let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; + trait_.associated_type_by_name(self.db, &name::ITEM_TYPE) } fn resolve_ops_try_ok(&self) -> Option { - let ops_try_path = - Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::TRY]); - - let trait_ = self.resolver.resolve_known_trait(self.db, &ops_try_path)?; - trait_.associated_type_by_name(self.db, &name::OK) + let path = known::std_ops_try(); + let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; + trait_.associated_type_by_name(self.db, &name::OK_TYPE) } fn resolve_future_future_output(&self) -> Option { - let future_future_path = Path::from_simple_segments( - PathKind::Abs, - vec![name::STD, name::FUTURE_MOD, name::FUTURE_TYPE], - ); - - let trait_ = self.resolver.resolve_known_trait(self.db, &future_future_path)?; - trait_.associated_type_by_name(self.db, &name::OUTPUT) + let path = known::std_future_future(); + let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; + trait_.associated_type_by_name(self.db, &name::OUTPUT_TYPE) } fn resolve_boxed_box(&self) -> Option { - let boxed_box_path = Path::from_simple_segments( - PathKind::Abs, - vec![name::STD, name::BOXED_MOD, name::BOX_TYPE], - ); - let struct_ = self.resolver.resolve_known_struct(self.db, &boxed_box_path)?; + let path = known::std_boxed_box(); + let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; Some(Adt::Struct(struct_)) } } -- cgit v1.2.3