Merge #1817
1817: Support path starting with a type r=matklad a=uHOOCCOOHu
The path syntax `<Ty>::foo`
Co-authored-by: uHOOCCOOHu <hooccooh1896@gmail.com>
diff --git a/crates/ra_assists/src/auto_import.rs b/crates/ra_assists/src/auto_import.rs
index 1158adb..5aae985 100644
--- a/crates/ra_assists/src/auto_import.rs
+++ b/crates/ra_assists/src/auto_import.rs
@@ -504,7 +504,7 @@
}
}
-pub fn collect_hir_path_segments(path: &hir::Path) -> Vec<SmolStr> {
+pub fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> {
let mut ps = Vec::<SmolStr>::with_capacity(10);
match path.kind {
hir::PathKind::Abs => ps.push("".into()),
@@ -512,11 +512,12 @@
hir::PathKind::Plain => {}
hir::PathKind::Self_ => ps.push("self".into()),
hir::PathKind::Super => ps.push("super".into()),
+ hir::PathKind::Type(_) => return None,
}
for s in path.segments.iter() {
ps.push(s.name.to_string().into());
}
- ps
+ Some(ps)
}
// This function produces sequence of text edits into edit
@@ -552,7 +553,7 @@
}
let hir_path = hir::Path::from_ast(path.clone())?;
- let segments = collect_hir_path_segments(&hir_path);
+ let segments = collect_hir_path_segments(&hir_path)?;
if segments.len() < 2 {
return None;
}
diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs
index 030ec53..f06e5ec 100644
--- a/crates/ra_hir/src/expr/validation.rs
+++ b/crates/ra_hir/src/expr/validation.rs
@@ -7,8 +7,7 @@
db::HirDatabase,
diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr},
expr::AstPtr,
- name,
- path::{PathKind, PathSegment},
+ path::known,
ty::{ApplicationTy, InferenceResult, Ty, TypeCtor},
Adt, Function, Name, Path,
};
@@ -108,14 +107,7 @@
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 = 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 abdfec2..1bf993f 100644
--- a/crates/ra_hir/src/name.rs
+++ b/crates/ra_hir/src/name.rs
@@ -85,6 +85,7 @@
}
}
+// 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 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/nameres.rs b/crates/ra_hir/src/nameres.rs
index 7922e3f7..b808a0c 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -382,6 +382,11 @@
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 {
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs
index d6c7859..a61161b 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},
@@ -42,7 +42,7 @@
// or lifetime...
}
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum PathKind {
Plain,
Self_,
@@ -50,6 +50,8 @@
Crate,
// Absolute path
Abs,
+ // Type based path like `<T>::foo`
+ Type(Box<TypeRef>),
}
impl Path {
@@ -63,6 +65,16 @@
}
}
+ pub fn from_simple_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> Path {
+ Path {
+ kind,
+ 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<Path> {
let mut kind = PathKind::Plain;
@@ -92,24 +104,32 @@
ast::PathSegmentKind::Type { type_ref, trait_ref } => {
assert!(path.qualifier().is_none()); // this can only occur at the first segment
- // FIXME: handle <T> syntax (type segments without trait)
-
- // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::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 {
+ // <T>::foo
+ None => {
+ kind = PathKind::Type(Box::new(self_type));
+ }
+ // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::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;
@@ -214,7 +234,7 @@
}
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
@@ -230,10 +250,7 @@
impl From<Name> 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,6 +304,7 @@
let segment = path.segment()?;
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, segments: Vec::with_capacity(1) });
res.segments.push(PathSegment {
@@ -299,19 +317,19 @@
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
@@ -320,3 +338,31 @@
};
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/resolve.rs b/crates/ra_hir/src/resolve.rs
index 3207b66..bb69159 100644
--- a/crates/ra_hir/src/resolve.rs
+++ b/crates/ra_hir/src/resolve.rs
@@ -15,6 +15,7 @@
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 @@
}
#[derive(Debug)]
-pub enum ValueOrPartial {
+pub enum ResolveValueResult<'a> {
ValueNs(ValueNs),
Partial(TypeNs, usize),
+ TypeRef(&'a TypeRef),
}
#[derive(Debug)]
@@ -183,11 +185,15 @@
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<ValueOrPartial> {
+ path: &'p Path,
+ ) -> Option<ResolveValueResult<'p>> {
+ if let PathKind::Type(type_ref) = &path.kind {
+ 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 @@
.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 @@
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 @@
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 @@
| 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 @@
| ModuleDef::Const(_)
| ModuleDef::Static(_) => return None,
};
- Some(ValueOrPartial::Partial(ty, idx))
+ Some(ResolveValueResult::Partial(ty, idx))
}
};
}
@@ -277,8 +283,8 @@
path: &Path,
) -> Option<ValueNs> {
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 cff55b6..2a907c9 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -25,8 +25,7 @@
BodySourceMap,
},
ids::LocationCtx,
- name,
- path::{PathKind, PathSegment},
+ path::known,
resolve::{ScopeDef, TypeNs, ValueNs},
ty::method_resolution::implements_trait,
AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HasBody, HirFileId, MacroDef,
@@ -433,14 +432,7 @@
/// 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 = 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 5ba7cf2e..94f8ecd 100644
--- a/crates/ra_hir/src/ty/autoderef.rs
+++ b/crates/ra_hir/src/ty/autoderef.rs
@@ -42,7 +42,7 @@
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 7d9b867..bf9609d 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -44,11 +44,12 @@
generics::{GenericParams, HasGenericParams},
name,
nameres::Namespace,
- path::{GenericArg, GenericArgs, PathKind, PathSegment},
- resolve::{Resolver, TypeNs, ValueNs, ValueOrPartial},
+ path::{known, GenericArg, GenericArgs},
+ 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 @@
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 @@
fn resolve_assoc_item(
&mut self,
- mut def: TypeNs,
+ mut def_or_ty: Either<TypeNs, Ty>,
path: &Path,
remaining_index: usize,
id: ExprOrPatId,
@@ -516,30 +521,33 @@
// 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,
- };
+ 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,
+ };
- let ty = self.db.type_for_def(typable, Namespace::Types);
+ let ty = self.db.type_for_def(typable, Namespace::Types);
- // For example, this substs will take `Gen::*<u32>*::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)
+ // For example, this substs will take `Gen::*<u32>*::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 @@
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::<TypeNs>
+ // Some(Either::A(TypeNs::TypeAlias(..)))
+ None
}
}
})?;
@@ -1434,57 +1442,26 @@
}
fn resolve_into_iter_item(&self) -> Option<TypeAlias> {
- 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 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<TypeAlias> {
- 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 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<TypeAlias> {
- 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 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<Adt> {
- 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 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_))
}
}
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index f6a2a65..1bd677c 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -282,6 +282,64 @@
}
#[test]
+fn infer_path_type() {
+ assert_snapshot!(
+ infer(r#"
+struct S;
+
+impl S {
+ fn foo() -> i32 { 1 }
+}
+
+fn test() {
+ S::foo();
+ <S>::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) '<S>::foo': fn foo() -> i32
+ [80; 90) '<S>::foo()': i32
+"###
+ );
+}
+
+#[test]
+fn infer_slice_method() {
+ assert_snapshot!(
+ infer(r#"
+#[lang = "slice"]
+impl<T> [T] {
+ fn foo(&self) -> T {
+ loop {}
+ }
+}
+
+#[lang = "slice_alloc"]
+impl<T> [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<u8>(&[T]) -> T
+ [139; 157) '<[_]>:..."foo")': u8
+ [150; 156) 'b"foo"': &[u8]
+"###
+ );
+}
+
+#[test]
fn infer_struct() {
assert_snapshot!(
infer(r#"
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index 591ac8c..dc1f8c8 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -2385,6 +2385,9 @@
pub fn ret_type(&self) -> Option<RetType> {
AstChildren::new(&self.syntax).next()
}
+ pub fn path_type(&self) -> Option<PathType> {
+ AstChildren::new(&self.syntax).next()
+ }
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct PathType {
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index 08cc6ee..da9de22 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -689,7 +689,7 @@
]
),
"PathSegment": (
- options: [ "NameRef", "TypeArgList", "ParamList", "RetType" ]
+ options: [ "NameRef", "TypeArgList", "ParamList", "RetType", "PathType" ]
),
"TypeArgList": (collections: [
("type_args", "TypeArg"),