mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 13:51:31 +00:00
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>
This commit is contained in:
commit
ba583091e6
12 changed files with 234 additions and 147 deletions
|
@ -504,7 +504,7 @@ fn apply_auto_import(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
let mut ps = Vec::<SmolStr>::with_capacity(10);
|
||||||
match path.kind {
|
match path.kind {
|
||||||
hir::PathKind::Abs => ps.push("".into()),
|
hir::PathKind::Abs => ps.push("".into()),
|
||||||
|
@ -512,11 +512,12 @@ pub fn collect_hir_path_segments(path: &hir::Path) -> Vec<SmolStr> {
|
||||||
hir::PathKind::Plain => {}
|
hir::PathKind::Plain => {}
|
||||||
hir::PathKind::Self_ => ps.push("self".into()),
|
hir::PathKind::Self_ => ps.push("self".into()),
|
||||||
hir::PathKind::Super => ps.push("super".into()),
|
hir::PathKind::Super => ps.push("super".into()),
|
||||||
|
hir::PathKind::Type(_) => return None,
|
||||||
}
|
}
|
||||||
for s in path.segments.iter() {
|
for s in path.segments.iter() {
|
||||||
ps.push(s.name.to_string().into());
|
ps.push(s.name.to_string().into());
|
||||||
}
|
}
|
||||||
ps
|
Some(ps)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function produces sequence of text edits into edit
|
// This function produces sequence of text edits into edit
|
||||||
|
@ -552,7 +553,7 @@ pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist
|
||||||
}
|
}
|
||||||
|
|
||||||
let hir_path = hir::Path::from_ast(path.clone())?;
|
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 {
|
if segments.len() < 2 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,7 @@ use crate::{
|
||||||
db::HirDatabase,
|
db::HirDatabase,
|
||||||
diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr},
|
diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr},
|
||||||
expr::AstPtr,
|
expr::AstPtr,
|
||||||
name,
|
path::known,
|
||||||
path::{PathKind, PathSegment},
|
|
||||||
ty::{ApplicationTy, InferenceResult, Ty, TypeCtor},
|
ty::{ApplicationTy, InferenceResult, Ty, TypeCtor},
|
||||||
Adt, Function, Name, Path,
|
Adt, Function, Name, Path,
|
||||||
};
|
};
|
||||||
|
@ -108,14 +107,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
let std_result_path = Path {
|
let std_result_path = known::std_result_result();
|
||||||
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 resolver = self.func.resolver(db);
|
let resolver = self.func.resolver(db);
|
||||||
let std_result_enum = match resolver.resolve_known_enum(db, &std_result_path) {
|
let std_result_enum = match resolver.resolve_known_enum(db, &std_result_path) {
|
||||||
|
|
|
@ -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 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 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"));
|
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 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 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"));
|
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_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 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"));
|
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 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 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 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 FUTURE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"future"));
|
||||||
pub(crate) const OK: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"Ok"));
|
pub(crate) const RESULT: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"result"));
|
||||||
pub(crate) const FUTURE_MOD: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"future"));
|
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 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 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 OUTPUT_TYPE: 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 TARGET_TYPE: 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 BOX_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"Box"));
|
pub(crate) const BOX_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"Box"));
|
||||||
|
|
||||||
fn resolve_name(text: &SmolStr) -> SmolStr {
|
fn resolve_name(text: &SmolStr) -> SmolStr {
|
||||||
|
|
|
@ -382,6 +382,11 @@ impl CrateDefMap {
|
||||||
return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
|
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 {
|
for (i, segment) in segments {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::sync::Arc;
|
use std::{iter, sync::Arc};
|
||||||
|
|
||||||
use ra_syntax::{
|
use ra_syntax::{
|
||||||
ast::{self, NameOwner, TypeAscriptionOwner},
|
ast::{self, NameOwner, TypeAscriptionOwner},
|
||||||
|
@ -42,7 +42,7 @@ pub enum GenericArg {
|
||||||
// or lifetime...
|
// or lifetime...
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum PathKind {
|
pub enum PathKind {
|
||||||
Plain,
|
Plain,
|
||||||
Self_,
|
Self_,
|
||||||
|
@ -50,6 +50,8 @@ pub enum PathKind {
|
||||||
Crate,
|
Crate,
|
||||||
// Absolute path
|
// Absolute path
|
||||||
Abs,
|
Abs,
|
||||||
|
// Type based path like `<T>::foo`
|
||||||
|
Type(Box<TypeRef>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Path {
|
impl Path {
|
||||||
|
@ -63,6 +65,16 @@ impl Path {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.
|
/// Converts an `ast::Path` to `Path`. Works with use trees.
|
||||||
pub fn from_ast(mut path: ast::Path) -> Option<Path> {
|
pub fn from_ast(mut path: ast::Path) -> Option<Path> {
|
||||||
let mut kind = PathKind::Plain;
|
let mut kind = PathKind::Plain;
|
||||||
|
@ -92,25 +104,33 @@ impl Path {
|
||||||
ast::PathSegmentKind::Type { type_ref, trait_ref } => {
|
ast::PathSegmentKind::Type { type_ref, trait_ref } => {
|
||||||
assert!(path.qualifier().is_none()); // this can only occur at the first segment
|
assert!(path.qualifier().is_none()); // this can only occur at the first segment
|
||||||
|
|
||||||
// FIXME: handle <T> syntax (type segments without trait)
|
let self_type = TypeRef::from_ast(type_ref?);
|
||||||
|
|
||||||
|
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
|
// <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
|
||||||
let path = Path::from_ast(trait_ref?.path()?)?;
|
Some(trait_ref) => {
|
||||||
|
let path = Path::from_ast(trait_ref.path()?)?;
|
||||||
kind = path.kind;
|
kind = path.kind;
|
||||||
let mut prefix_segments = path.segments;
|
let mut prefix_segments = path.segments;
|
||||||
prefix_segments.reverse();
|
prefix_segments.reverse();
|
||||||
segments.extend(prefix_segments);
|
segments.extend(prefix_segments);
|
||||||
// Insert the type reference (T in the above example) as Self parameter for the trait
|
// 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()?;
|
let mut last_segment = segments.last_mut()?;
|
||||||
if last_segment.args_and_bindings.is_none() {
|
if last_segment.args_and_bindings.is_none() {
|
||||||
last_segment.args_and_bindings = Some(Arc::new(GenericArgs::empty()));
|
last_segment.args_and_bindings =
|
||||||
|
Some(Arc::new(GenericArgs::empty()));
|
||||||
};
|
};
|
||||||
let args = last_segment.args_and_bindings.as_mut().unwrap();
|
let args = last_segment.args_and_bindings.as_mut().unwrap();
|
||||||
let mut args_inner = Arc::make_mut(args);
|
let mut args_inner = Arc::make_mut(args);
|
||||||
args_inner.has_self_type = true;
|
args_inner.has_self_type = true;
|
||||||
args_inner.args.insert(0, GenericArg::Type(self_type));
|
args_inner.args.insert(0, GenericArg::Type(self_type));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
ast::PathSegmentKind::CrateKw => {
|
ast::PathSegmentKind::CrateKw => {
|
||||||
kind = PathKind::Crate;
|
kind = PathKind::Crate;
|
||||||
break;
|
break;
|
||||||
|
@ -214,7 +234,7 @@ impl GenericArgs {
|
||||||
}
|
}
|
||||||
if let Some(ret_type) = ret_type {
|
if let Some(ret_type) = ret_type {
|
||||||
let type_ref = TypeRef::from_ast_opt(ret_type.type_ref());
|
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() {
|
if args.is_empty() && bindings.is_empty() {
|
||||||
None
|
None
|
||||||
|
@ -230,10 +250,7 @@ impl GenericArgs {
|
||||||
|
|
||||||
impl From<Name> for Path {
|
impl From<Name> for Path {
|
||||||
fn from(name: Name) -> Path {
|
fn from(name: Name) -> Path {
|
||||||
Path {
|
Path::from_simple_segments(PathKind::Plain, iter::once(name))
|
||||||
kind: PathKind::Plain,
|
|
||||||
segments: vec![PathSegment { name, args_and_bindings: None }],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,6 +304,7 @@ fn convert_path(prefix: Option<Path>, path: ast::Path) -> Option<Path> {
|
||||||
let segment = path.segment()?;
|
let segment = path.segment()?;
|
||||||
let res = match segment.kind()? {
|
let res = match segment.kind()? {
|
||||||
ast::PathSegmentKind::Name(name) => {
|
ast::PathSegmentKind::Name(name) => {
|
||||||
|
// no type args in use
|
||||||
let mut res = prefix
|
let mut res = prefix
|
||||||
.unwrap_or_else(|| Path { kind: PathKind::Plain, segments: Vec::with_capacity(1) });
|
.unwrap_or_else(|| Path { kind: PathKind::Plain, segments: Vec::with_capacity(1) });
|
||||||
res.segments.push(PathSegment {
|
res.segments.push(PathSegment {
|
||||||
|
@ -299,19 +317,19 @@ fn convert_path(prefix: Option<Path>, path: ast::Path) -> Option<Path> {
|
||||||
if prefix.is_some() {
|
if prefix.is_some() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Path { kind: PathKind::Crate, segments: Vec::new() }
|
Path::from_simple_segments(PathKind::Crate, iter::empty())
|
||||||
}
|
}
|
||||||
ast::PathSegmentKind::SelfKw => {
|
ast::PathSegmentKind::SelfKw => {
|
||||||
if prefix.is_some() {
|
if prefix.is_some() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Path { kind: PathKind::Self_, segments: Vec::new() }
|
Path::from_simple_segments(PathKind::Self_, iter::empty())
|
||||||
}
|
}
|
||||||
ast::PathSegmentKind::SuperKw => {
|
ast::PathSegmentKind::SuperKw => {
|
||||||
if prefix.is_some() {
|
if prefix.is_some() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Path { kind: PathKind::Super, segments: Vec::new() }
|
Path::from_simple_segments(PathKind::Super, iter::empty())
|
||||||
}
|
}
|
||||||
ast::PathSegmentKind::Type { .. } => {
|
ast::PathSegmentKind::Type { .. } => {
|
||||||
// not allowed in imports
|
// not allowed in imports
|
||||||
|
@ -320,3 +338,31 @@ fn convert_path(prefix: Option<Path>, path: ast::Path) -> Option<Path> {
|
||||||
};
|
};
|
||||||
Some(res)
|
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])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ use crate::{
|
||||||
name::{Name, SELF_PARAM, SELF_TYPE},
|
name::{Name, SELF_PARAM, SELF_TYPE},
|
||||||
nameres::{CrateDefMap, CrateModuleId, PerNs},
|
nameres::{CrateDefMap, CrateModuleId, PerNs},
|
||||||
path::{Path, PathKind},
|
path::{Path, PathKind},
|
||||||
|
type_ref::TypeRef,
|
||||||
Adt, BuiltinType, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, Static, Struct,
|
Adt, BuiltinType, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, Static, Struct,
|
||||||
Trait, TypeAlias,
|
Trait, TypeAlias,
|
||||||
};
|
};
|
||||||
|
@ -64,9 +65,10 @@ pub enum TypeNs {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ValueOrPartial {
|
pub enum ResolveValueResult<'a> {
|
||||||
ValueNs(ValueNs),
|
ValueNs(ValueNs),
|
||||||
Partial(TypeNs, usize),
|
Partial(TypeNs, usize),
|
||||||
|
TypeRef(&'a TypeRef),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -183,11 +185,15 @@ impl Resolver {
|
||||||
Some(res)
|
Some(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn resolve_path_in_value_ns(
|
pub(crate) fn resolve_path_in_value_ns<'p>(
|
||||||
&self,
|
&self,
|
||||||
db: &impl HirDatabase,
|
db: &impl HirDatabase,
|
||||||
path: &Path,
|
path: &'p Path,
|
||||||
) -> Option<ValueOrPartial> {
|
) -> Option<ResolveValueResult<'p>> {
|
||||||
|
if let PathKind::Type(type_ref) = &path.kind {
|
||||||
|
return Some(ResolveValueResult::TypeRef(type_ref));
|
||||||
|
}
|
||||||
|
|
||||||
let n_segments = path.segments.len();
|
let n_segments = path.segments.len();
|
||||||
let tmp = SELF_PARAM;
|
let tmp = SELF_PARAM;
|
||||||
let first_name = if path.is_self() { &tmp } else { &path.segments.first()?.name };
|
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);
|
.find(|entry| entry.name() == first_name);
|
||||||
|
|
||||||
if let Some(e) = entry {
|
if let Some(e) = entry {
|
||||||
return Some(ValueOrPartial::ValueNs(ValueNs::LocalBinding(e.pat())));
|
return Some(ResolveValueResult::ValueNs(ValueNs::LocalBinding(e.pat())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Scope::ExprScope(_) => continue,
|
Scope::ExprScope(_) => continue,
|
||||||
|
@ -216,7 +222,7 @@ impl Resolver {
|
||||||
Scope::GenericParams(params) if n_segments > 1 => {
|
Scope::GenericParams(params) if n_segments > 1 => {
|
||||||
if let Some(param) = params.find_by_name(first_name) {
|
if let Some(param) = params.find_by_name(first_name) {
|
||||||
let ty = TypeNs::GenericParam(param.idx);
|
let ty = TypeNs::GenericParam(param.idx);
|
||||||
return Some(ValueOrPartial::Partial(ty, 1));
|
return Some(ResolveValueResult::Partial(ty, 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Scope::GenericParams(_) => continue,
|
Scope::GenericParams(_) => continue,
|
||||||
|
@ -224,7 +230,7 @@ impl Resolver {
|
||||||
Scope::ImplBlockScope(impl_) if n_segments > 1 => {
|
Scope::ImplBlockScope(impl_) if n_segments > 1 => {
|
||||||
if first_name == &SELF_TYPE {
|
if first_name == &SELF_TYPE {
|
||||||
let ty = TypeNs::SelfType(*impl_);
|
let ty = TypeNs::SelfType(*impl_);
|
||||||
return Some(ValueOrPartial::Partial(ty, 1));
|
return Some(ResolveValueResult::Partial(ty, 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Scope::ImplBlockScope(_) => continue,
|
Scope::ImplBlockScope(_) => continue,
|
||||||
|
@ -247,7 +253,7 @@ impl Resolver {
|
||||||
| ModuleDef::BuiltinType(_)
|
| ModuleDef::BuiltinType(_)
|
||||||
| ModuleDef::Module(_) => return None,
|
| ModuleDef::Module(_) => return None,
|
||||||
};
|
};
|
||||||
Some(ValueOrPartial::ValueNs(value))
|
Some(ResolveValueResult::ValueNs(value))
|
||||||
}
|
}
|
||||||
Some(idx) => {
|
Some(idx) => {
|
||||||
let ty = match module_def.take_types()? {
|
let ty = match module_def.take_types()? {
|
||||||
|
@ -262,7 +268,7 @@ impl Resolver {
|
||||||
| ModuleDef::Const(_)
|
| ModuleDef::Const(_)
|
||||||
| ModuleDef::Static(_) => return None,
|
| ModuleDef::Static(_) => return None,
|
||||||
};
|
};
|
||||||
Some(ValueOrPartial::Partial(ty, idx))
|
Some(ResolveValueResult::Partial(ty, idx))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -277,8 +283,8 @@ impl Resolver {
|
||||||
path: &Path,
|
path: &Path,
|
||||||
) -> Option<ValueNs> {
|
) -> Option<ValueNs> {
|
||||||
match self.resolve_path_in_value_ns(db, path)? {
|
match self.resolve_path_in_value_ns(db, path)? {
|
||||||
ValueOrPartial::ValueNs(it) => Some(it),
|
ResolveValueResult::ValueNs(it) => Some(it),
|
||||||
ValueOrPartial::Partial(..) => None,
|
ResolveValueResult::Partial(..) | ResolveValueResult::TypeRef(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,7 @@ use crate::{
|
||||||
BodySourceMap,
|
BodySourceMap,
|
||||||
},
|
},
|
||||||
ids::LocationCtx,
|
ids::LocationCtx,
|
||||||
name,
|
path::known,
|
||||||
path::{PathKind, PathSegment},
|
|
||||||
resolve::{ScopeDef, TypeNs, ValueNs},
|
resolve::{ScopeDef, TypeNs, ValueNs},
|
||||||
ty::method_resolution::implements_trait,
|
ty::method_resolution::implements_trait,
|
||||||
AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HasBody, HirFileId, MacroDef,
|
AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HasBody, HirFileId, MacroDef,
|
||||||
|
@ -433,14 +432,7 @@ impl SourceAnalyzer {
|
||||||
/// Checks that particular type `ty` implements `std::future::Future`.
|
/// Checks that particular type `ty` implements `std::future::Future`.
|
||||||
/// This function is used in `.await` syntax completion.
|
/// This function is used in `.await` syntax completion.
|
||||||
pub fn impls_future(&self, db: &impl HirDatabase, ty: Ty) -> bool {
|
pub fn impls_future(&self, db: &impl HirDatabase, ty: Ty) -> bool {
|
||||||
let std_future_path = Path {
|
let std_future_path = known::std_future_future();
|
||||||
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_trait = match self.resolver.resolve_known_trait(db, &std_future_path) {
|
let std_future_trait = match self.resolver.resolve_known_trait(db, &std_future_path) {
|
||||||
Some(it) => it,
|
Some(it) => it,
|
||||||
|
|
|
@ -42,7 +42,7 @@ fn deref_by_trait(
|
||||||
crate::lang_item::LangItemTarget::Trait(t) => t,
|
crate::lang_item::LangItemTarget::Trait(t) => t,
|
||||||
_ => return None,
|
_ => 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 {
|
if target.generic_params(db).count_params_including_parent() != 1 {
|
||||||
// the Target type + Deref trait should only have one generic parameter,
|
// the Target type + Deref trait should only have one generic parameter,
|
||||||
|
|
|
@ -44,11 +44,12 @@ use crate::{
|
||||||
generics::{GenericParams, HasGenericParams},
|
generics::{GenericParams, HasGenericParams},
|
||||||
name,
|
name,
|
||||||
nameres::Namespace,
|
nameres::Namespace,
|
||||||
path::{GenericArg, GenericArgs, PathKind, PathSegment},
|
path::{known, GenericArg, GenericArgs},
|
||||||
resolve::{Resolver, TypeNs, ValueNs, ValueOrPartial},
|
resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs},
|
||||||
ty::infer::diagnostics::InferenceDiagnostic,
|
ty::infer::diagnostics::InferenceDiagnostic,
|
||||||
type_ref::{Mutability, TypeRef},
|
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;
|
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_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?;
|
||||||
|
|
||||||
let (value, self_subst) = match value_or_partial {
|
let (value, self_subst) = match value_or_partial {
|
||||||
ValueOrPartial::ValueNs(it) => (it, None),
|
ResolveValueResult::ValueNs(it) => (it, None),
|
||||||
ValueOrPartial::Partial(def, remaining_index) => {
|
ResolveValueResult::Partial(def, remaining_index) => {
|
||||||
self.resolve_assoc_item(def, path, remaining_index, id)?
|
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(
|
fn resolve_assoc_item(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut def: TypeNs,
|
mut def_or_ty: Either<TypeNs, Ty>,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
remaining_index: usize,
|
remaining_index: usize,
|
||||||
id: ExprOrPatId,
|
id: ExprOrPatId,
|
||||||
|
@ -516,7 +521,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
// resolve intermediate segments
|
// resolve intermediate segments
|
||||||
for (i, segment) in path.segments[remaining_index..].iter().enumerate() {
|
for (i, segment) in path.segments[remaining_index..].iter().enumerate() {
|
||||||
let is_last_segment = i == path.segments[remaining_index..].len() - 1;
|
let is_last_segment = i == path.segments[remaining_index..].len() - 1;
|
||||||
ty = {
|
ty = match def_or_ty {
|
||||||
|
Either::A(def) => {
|
||||||
let typable: TypableDef = match def {
|
let typable: TypableDef = match def {
|
||||||
TypeNs::Adt(it) => it.into(),
|
TypeNs::Adt(it) => it.into(),
|
||||||
TypeNs::TypeAlias(it) => it.into(),
|
TypeNs::TypeAlias(it) => it.into(),
|
||||||
|
@ -540,6 +546,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
typable,
|
typable,
|
||||||
);
|
);
|
||||||
ty.subst(&substs)
|
ty.subst(&substs)
|
||||||
|
}
|
||||||
|
Either::B(ty) => ty,
|
||||||
};
|
};
|
||||||
if is_last_segment {
|
if is_last_segment {
|
||||||
break;
|
break;
|
||||||
|
@ -550,15 +558,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
log::debug!("looking for path segment: {:?}", segment);
|
log::debug!("looking for path segment: {:?}", segment);
|
||||||
|
|
||||||
let ty = mem::replace(&mut ty, Ty::Unknown);
|
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 {
|
match item {
|
||||||
crate::ImplItem::Method(_) => None,
|
crate::ImplItem::Method(_) => None,
|
||||||
crate::ImplItem::Const(_) => None,
|
crate::ImplItem::Const(_) => None,
|
||||||
|
|
||||||
// FIXME: Resolve associated types
|
// FIXME: Resolve associated types
|
||||||
crate::ImplItem::TypeAlias(_) => {
|
crate::ImplItem::TypeAlias(_) => {
|
||||||
// Some(TypeNs::TypeAlias(..))
|
// Some(Either::A(TypeNs::TypeAlias(..)))
|
||||||
None::<TypeNs>
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
@ -1434,57 +1442,26 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_into_iter_item(&self) -> Option<TypeAlias> {
|
fn resolve_into_iter_item(&self) -> Option<TypeAlias> {
|
||||||
let into_iter_path = Path {
|
let path = known::std_iter_into_iterator();
|
||||||
kind: PathKind::Abs,
|
let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
|
||||||
segments: vec![
|
trait_.associated_type_by_name(self.db, &name::ITEM_TYPE)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_ops_try_ok(&self) -> Option<TypeAlias> {
|
fn resolve_ops_try_ok(&self) -> Option<TypeAlias> {
|
||||||
let ops_try_path = Path {
|
let path = known::std_ops_try();
|
||||||
kind: PathKind::Abs,
|
let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
|
||||||
segments: vec![
|
trait_.associated_type_by_name(self.db, &name::OK_TYPE)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_future_future_output(&self) -> Option<TypeAlias> {
|
fn resolve_future_future_output(&self) -> Option<TypeAlias> {
|
||||||
let future_future_path = Path {
|
let path = known::std_future_future();
|
||||||
kind: PathKind::Abs,
|
let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
|
||||||
segments: vec![
|
trait_.associated_type_by_name(self.db, &name::OUTPUT_TYPE)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_boxed_box(&self) -> Option<Adt> {
|
fn resolve_boxed_box(&self) -> Option<Adt> {
|
||||||
let boxed_box_path = Path {
|
let path = known::std_boxed_box();
|
||||||
kind: PathKind::Abs,
|
let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
|
||||||
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)?;
|
|
||||||
Some(Adt::Struct(struct_))
|
Some(Adt::Struct(struct_))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
<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]
|
#[test]
|
||||||
fn infer_struct() {
|
fn infer_struct() {
|
||||||
assert_snapshot!(
|
assert_snapshot!(
|
||||||
|
|
|
@ -2385,6 +2385,9 @@ impl PathSegment {
|
||||||
pub fn ret_type(&self) -> Option<RetType> {
|
pub fn ret_type(&self) -> Option<RetType> {
|
||||||
AstChildren::new(&self.syntax).next()
|
AstChildren::new(&self.syntax).next()
|
||||||
}
|
}
|
||||||
|
pub fn path_type(&self) -> Option<PathType> {
|
||||||
|
AstChildren::new(&self.syntax).next()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct PathType {
|
pub struct PathType {
|
||||||
|
|
|
@ -689,7 +689,7 @@ Grammar(
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
"PathSegment": (
|
"PathSegment": (
|
||||||
options: [ "NameRef", "TypeArgList", "ParamList", "RetType" ]
|
options: [ "NameRef", "TypeArgList", "ParamList", "RetType", "PathType" ]
|
||||||
),
|
),
|
||||||
"TypeArgList": (collections: [
|
"TypeArgList": (collections: [
|
||||||
("type_args", "TypeArg"),
|
("type_args", "TypeArg"),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue