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
@ -190,6 +190,13 @@ impl Path {
|
||||
pub fn expand_macro_expr(&self) -> Option<Name> {
|
||||
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 {
|
||||
|
@ -15,7 +15,6 @@ 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,
|
||||
};
|
||||
@ -65,10 +64,9 @@ pub enum TypeNs {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum ResolveValueResult<'a> {
|
||||
pub enum ResolveValueResult {
|
||||
ValueNs(ValueNs),
|
||||
Partial(TypeNs, usize),
|
||||
TypeRef(&'a TypeRef),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
@ -131,6 +129,9 @@ impl Resolver {
|
||||
db: &impl HirDatabase,
|
||||
path: &Path,
|
||||
) -> Option<(TypeNs, Option<usize>)> {
|
||||
if path.is_type_relative() {
|
||||
return None;
|
||||
}
|
||||
let first_name = &path.segments.first()?.name;
|
||||
let skip_to_mod = path.kind != PathKind::Plain;
|
||||
for scope in self.scopes.iter().rev() {
|
||||
@ -189,11 +190,10 @@ impl Resolver {
|
||||
&self,
|
||||
db: &impl HirDatabase,
|
||||
path: &'p Path,
|
||||
) -> Option<ResolveValueResult<'p>> {
|
||||
if let PathKind::Type(type_ref) = &path.kind {
|
||||
return Some(ResolveValueResult::TypeRef(type_ref));
|
||||
) -> Option<ResolveValueResult> {
|
||||
if path.is_type_relative() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let n_segments = path.segments.len();
|
||||
let tmp = SELF_PARAM;
|
||||
let first_name = if path.is_self() { &tmp } else { &path.segments.first()?.name };
|
||||
@ -284,7 +284,7 @@ impl Resolver {
|
||||
) -> Option<ValueNs> {
|
||||
match self.resolve_path_in_value_ns(db, path)? {
|
||||
ResolveValueResult::ValueNs(it) => Some(it),
|
||||
ResolveValueResult::Partial(..) | ResolveValueResult::TypeRef(_) => None,
|
||||
ResolveValueResult::Partial(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,8 +48,7 @@ use crate::{
|
||||
resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs},
|
||||
ty::infer::diagnostics::InferenceDiagnostic,
|
||||
type_ref::{Mutability, TypeRef},
|
||||
Adt, AssocItem, ConstData, DefWithBody, Either, FnData, Function, HasBody, Name, Path,
|
||||
StructField,
|
||||
Adt, AssocItem, ConstData, DefWithBody, FnData, Function, HasBody, Name, Path, StructField,
|
||||
};
|
||||
|
||||
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> {
|
||||
let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?;
|
||||
|
||||
let (value, self_subst) = match value_or_partial {
|
||||
ResolveValueResult::ValueNs(it) => (it, None),
|
||||
ResolveValueResult::Partial(def, remaining_index) => {
|
||||
self.resolve_assoc_item(Either::A(def), path, remaining_index, id)?
|
||||
let (value, self_subst) = if let crate::PathKind::Type(type_ref) = &path.kind {
|
||||
if path.segments.is_empty() {
|
||||
// This can't actually happen syntax-wise
|
||||
return None;
|
||||
}
|
||||
ResolveValueResult::TypeRef(type_ref) => {
|
||||
let ty = self.make_ty(type_ref);
|
||||
self.resolve_assoc_item(Either::B(ty), path, 0, id)?
|
||||
let ty = self.make_ty(type_ref);
|
||||
let remaining_segments_for_ty = &path.segments[..path.segments.len() - 1];
|
||||
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(
|
||||
&mut self,
|
||||
// mut def_or_ty: Either<TypeNs, Ty>,
|
||||
def: TypeNs,
|
||||
path: &Path,
|
||||
remaining_index: usize,
|
||||
id: ExprOrPatId,
|
||||
) -> Option<(ValueNs, Option<Substs>)> {
|
||||
assert!(remaining_index < path.segments.len());
|
||||
let krate = self.resolver.krate()?;
|
||||
|
||||
// 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 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 is_before_last = remaining_segments.len() == 1;
|
||||
|
||||
let (def, substs) = match (def, is_before_last) {
|
||||
match (def, is_before_last) {
|
||||
(TypeNs::Trait(_trait), true) => {
|
||||
// Associated item of trait, e.g. `Default::default`
|
||||
// FIXME
|
||||
return None;
|
||||
// FIXME Associated item of trait, e.g. `Default::default`
|
||||
None
|
||||
}
|
||||
(def, _) => {
|
||||
// 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 =
|
||||
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) => {
|
||||
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)
|
||||
self.resolve_ty_assoc_item(ty, segment, id)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
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(
|
||||
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(
|
||||
db: &impl HirDatabase,
|
||||
resolver: &Resolver,
|
||||
@ -140,20 +158,16 @@ impl Ty {
|
||||
TypeNs::EnumVariant(_) => return Ty::Unknown,
|
||||
};
|
||||
|
||||
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
|
||||
}
|
||||
Ty::from_type_relative_path(db, resolver, ty, remaining_segments)
|
||||
}
|
||||
|
||||
pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty {
|
||||
// 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) {
|
||||
Some(it) => it,
|
||||
None => return Ty::Unknown,
|
||||
|
Loading…
x
Reference in New Issue
Block a user