mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-27 04:19:13 +00:00
Refactor some more
Type-relative paths (`<T>::foo`) also need to work in type context, for example `<T>::Item` is legal. So rather than returning the type ref from the resolver function, just check it before.
This commit is contained in:
parent
406280e52f
commit
fe1dfd2b20
4 changed files with 100 additions and 57 deletions
|
@ -190,6 +190,13 @@ impl Path {
|
||||||
pub fn expand_macro_expr(&self) -> Option<Name> {
|
pub fn expand_macro_expr(&self) -> Option<Name> {
|
||||||
self.as_ident().and_then(|name| Some(name.clone()))
|
self.as_ident().and_then(|name| Some(name.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_type_relative(&self) -> bool {
|
||||||
|
match self.kind {
|
||||||
|
PathKind::Type(_) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GenericArgs {
|
impl GenericArgs {
|
||||||
|
|
|
@ -15,7 +15,6 @@ 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,
|
||||||
};
|
};
|
||||||
|
@ -65,10 +64,9 @@ pub enum TypeNs {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum ResolveValueResult<'a> {
|
pub enum ResolveValueResult {
|
||||||
ValueNs(ValueNs),
|
ValueNs(ValueNs),
|
||||||
Partial(TypeNs, usize),
|
Partial(TypeNs, usize),
|
||||||
TypeRef(&'a TypeRef),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
@ -131,6 +129,9 @@ impl Resolver {
|
||||||
db: &impl HirDatabase,
|
db: &impl HirDatabase,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
) -> Option<(TypeNs, Option<usize>)> {
|
) -> Option<(TypeNs, Option<usize>)> {
|
||||||
|
if path.is_type_relative() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
let first_name = &path.segments.first()?.name;
|
let first_name = &path.segments.first()?.name;
|
||||||
let skip_to_mod = path.kind != PathKind::Plain;
|
let skip_to_mod = path.kind != PathKind::Plain;
|
||||||
for scope in self.scopes.iter().rev() {
|
for scope in self.scopes.iter().rev() {
|
||||||
|
@ -189,11 +190,10 @@ impl Resolver {
|
||||||
&self,
|
&self,
|
||||||
db: &impl HirDatabase,
|
db: &impl HirDatabase,
|
||||||
path: &'p Path,
|
path: &'p Path,
|
||||||
) -> Option<ResolveValueResult<'p>> {
|
) -> Option<ResolveValueResult> {
|
||||||
if let PathKind::Type(type_ref) = &path.kind {
|
if path.is_type_relative() {
|
||||||
return Some(ResolveValueResult::TypeRef(type_ref));
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 };
|
||||||
|
@ -284,7 +284,7 @@ impl Resolver {
|
||||||
) -> Option<ValueNs> {
|
) -> Option<ValueNs> {
|
||||||
match self.resolve_path_in_value_ns(db, path)? {
|
match self.resolve_path_in_value_ns(db, path)? {
|
||||||
ResolveValueResult::ValueNs(it) => Some(it),
|
ResolveValueResult::ValueNs(it) => Some(it),
|
||||||
ResolveValueResult::Partial(..) | ResolveValueResult::TypeRef(_) => None,
|
ResolveValueResult::Partial(..) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,8 +48,7 @@ use crate::{
|
||||||
resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs},
|
resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs},
|
||||||
ty::infer::diagnostics::InferenceDiagnostic,
|
ty::infer::diagnostics::InferenceDiagnostic,
|
||||||
type_ref::{Mutability, TypeRef},
|
type_ref::{Mutability, TypeRef},
|
||||||
Adt, AssocItem, ConstData, DefWithBody, Either, FnData, Function, HasBody, Name, Path,
|
Adt, AssocItem, ConstData, DefWithBody, FnData, Function, HasBody, Name, Path, StructField,
|
||||||
StructField,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
mod unify;
|
mod unify;
|
||||||
|
@ -468,16 +467,27 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path, id: ExprOrPatId) -> Option<Ty> {
|
fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path, id: ExprOrPatId) -> Option<Ty> {
|
||||||
let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?;
|
let (value, self_subst) = if let crate::PathKind::Type(type_ref) = &path.kind {
|
||||||
|
if path.segments.is_empty() {
|
||||||
let (value, self_subst) = match value_or_partial {
|
// This can't actually happen syntax-wise
|
||||||
ResolveValueResult::ValueNs(it) => (it, None),
|
return 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);
|
||||||
let ty = self.make_ty(type_ref);
|
let remaining_segments_for_ty = &path.segments[..path.segments.len() - 1];
|
||||||
self.resolve_assoc_item(Either::B(ty), path, 0, id)?
|
let ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty);
|
||||||
|
self.resolve_ty_assoc_item(
|
||||||
|
ty,
|
||||||
|
path.segments.last().expect("path had at least one segment"),
|
||||||
|
id,
|
||||||
|
)?
|
||||||
|
} else {
|
||||||
|
let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?;
|
||||||
|
|
||||||
|
match value_or_partial {
|
||||||
|
ResolveValueResult::ValueNs(it) => (it, None),
|
||||||
|
ResolveValueResult::Partial(def, remaining_index) => {
|
||||||
|
self.resolve_assoc_item(def, path, remaining_index, id)?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -508,15 +518,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
|
|
||||||
fn resolve_assoc_item(
|
fn resolve_assoc_item(
|
||||||
&mut self,
|
&mut self,
|
||||||
// mut def_or_ty: Either<TypeNs, Ty>,
|
|
||||||
def: TypeNs,
|
def: TypeNs,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
remaining_index: usize,
|
remaining_index: usize,
|
||||||
id: ExprOrPatId,
|
id: ExprOrPatId,
|
||||||
) -> Option<(ValueNs, Option<Substs>)> {
|
) -> Option<(ValueNs, Option<Substs>)> {
|
||||||
assert!(remaining_index < path.segments.len());
|
assert!(remaining_index < path.segments.len());
|
||||||
let krate = self.resolver.krate()?;
|
|
||||||
|
|
||||||
// there may be more intermediate segments between the resolved one and
|
// there may be more intermediate segments between the resolved one and
|
||||||
// the end. Only the last segment needs to be resolved to a value; from
|
// the end. Only the last segment needs to be resolved to a value; from
|
||||||
// the segments before that, we need to get either a type or a trait ref.
|
// the segments before that, we need to get either a type or a trait ref.
|
||||||
|
@ -525,11 +532,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
let remaining_segments = &path.segments[remaining_index..];
|
let remaining_segments = &path.segments[remaining_index..];
|
||||||
let is_before_last = remaining_segments.len() == 1;
|
let is_before_last = remaining_segments.len() == 1;
|
||||||
|
|
||||||
let (def, substs) = match (def, is_before_last) {
|
match (def, is_before_last) {
|
||||||
(TypeNs::Trait(_trait), true) => {
|
(TypeNs::Trait(_trait), true) => {
|
||||||
// Associated item of trait, e.g. `Default::default`
|
// FIXME Associated item of trait, e.g. `Default::default`
|
||||||
// FIXME
|
None
|
||||||
return None;
|
|
||||||
}
|
}
|
||||||
(def, _) => {
|
(def, _) => {
|
||||||
// Either we already have a type (e.g. `Vec::new`), or we have a
|
// Either we already have a type (e.g. `Vec::new`), or we have a
|
||||||
|
@ -550,29 +556,45 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
|
|
||||||
let segment =
|
let segment =
|
||||||
remaining_segments.last().expect("there should be at least one segment here");
|
remaining_segments.last().expect("there should be at least one segment here");
|
||||||
// Find impl
|
|
||||||
let def = ty.clone().iterate_impl_items(self.db, krate, |item| match item {
|
|
||||||
crate::ImplItem::Method(func) => {
|
|
||||||
if segment.name == func.name(self.db) {
|
|
||||||
Some(ValueNs::Function(func))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
crate::ImplItem::Const(konst) => {
|
self.resolve_ty_assoc_item(ty, segment, id)
|
||||||
if segment.name == konst.name(self.db) {
|
|
||||||
Some(ValueNs::Const(konst))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
crate::ImplItem::TypeAlias(_) => None,
|
|
||||||
})?;
|
|
||||||
let self_types = self.find_self_types(&def, ty);
|
|
||||||
(def, self_types)
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_ty_assoc_item(
|
||||||
|
&mut self,
|
||||||
|
ty: Ty,
|
||||||
|
segment: &crate::path::PathSegment,
|
||||||
|
id: ExprOrPatId,
|
||||||
|
) -> Option<(ValueNs, Option<Substs>)> {
|
||||||
|
if let Ty::Unknown = ty {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let krate = self.resolver.krate()?;
|
||||||
|
|
||||||
|
// Find impl
|
||||||
|
// FIXME: consider trait candidates
|
||||||
|
let def = ty.clone().iterate_impl_items(self.db, krate, |item| match item {
|
||||||
|
crate::ImplItem::Method(func) => {
|
||||||
|
if segment.name == func.name(self.db) {
|
||||||
|
Some(ValueNs::Function(func))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
crate::ImplItem::Const(konst) => {
|
||||||
|
if konst.name(self.db).map_or(false, |n| n == segment.name) {
|
||||||
|
Some(ValueNs::Const(konst))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
crate::ImplItem::TypeAlias(_) => None,
|
||||||
|
})?;
|
||||||
|
let substs = self.find_self_types(&def, ty);
|
||||||
|
|
||||||
self.write_assoc_resolution(
|
self.write_assoc_resolution(
|
||||||
id,
|
id,
|
||||||
|
|
|
@ -86,6 +86,24 @@ impl Ty {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn from_type_relative_path(
|
||||||
|
db: &impl HirDatabase,
|
||||||
|
resolver: &Resolver,
|
||||||
|
ty: Ty,
|
||||||
|
remaining_segments: &[PathSegment],
|
||||||
|
) -> Ty {
|
||||||
|
if remaining_segments.len() == 1 {
|
||||||
|
// resolve unselected assoc types
|
||||||
|
let segment = &remaining_segments[0];
|
||||||
|
Ty::select_associated_type(db, resolver, ty, segment)
|
||||||
|
} else if remaining_segments.len() > 1 {
|
||||||
|
// FIXME report error (ambiguous associated type)
|
||||||
|
Ty::Unknown
|
||||||
|
} else {
|
||||||
|
ty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn from_partly_resolved_hir_path(
|
pub(crate) fn from_partly_resolved_hir_path(
|
||||||
db: &impl HirDatabase,
|
db: &impl HirDatabase,
|
||||||
resolver: &Resolver,
|
resolver: &Resolver,
|
||||||
|
@ -140,20 +158,16 @@ impl Ty {
|
||||||
TypeNs::EnumVariant(_) => return Ty::Unknown,
|
TypeNs::EnumVariant(_) => return Ty::Unknown,
|
||||||
};
|
};
|
||||||
|
|
||||||
if remaining_segments.len() == 1 {
|
Ty::from_type_relative_path(db, resolver, ty, remaining_segments)
|
||||||
// resolve unselected assoc types
|
|
||||||
let segment = &remaining_segments[0];
|
|
||||||
Ty::select_associated_type(db, resolver, ty, segment)
|
|
||||||
} else if remaining_segments.len() > 1 {
|
|
||||||
// FIXME report error (ambiguous associated type)
|
|
||||||
Ty::Unknown
|
|
||||||
} else {
|
|
||||||
ty
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty {
|
pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty {
|
||||||
// Resolve the path (in type namespace)
|
// Resolve the path (in type namespace)
|
||||||
|
if let crate::PathKind::Type(type_ref) = &path.kind {
|
||||||
|
let ty = Ty::from_hir(db, resolver, &type_ref);
|
||||||
|
let remaining_segments = &path.segments[..];
|
||||||
|
return Ty::from_type_relative_path(db, resolver, ty, remaining_segments);
|
||||||
|
}
|
||||||
let (resolution, remaining_index) = match resolver.resolve_path_in_type_ns(db, path) {
|
let (resolution, remaining_index) = match resolver.resolve_path_in_type_ns(db, path) {
|
||||||
Some(it) => it,
|
Some(it) => it,
|
||||||
None => return Ty::Unknown,
|
None => return Ty::Unknown,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue