Unnamed repository; edit this file 'description' to name the repository.
Normalize type anchor type before resolving the rest of value paths
Ryo Yoshida 2023-03-29
parent 8aef04f · commit 6447d48
-rw-r--r--crates/hir-ty/src/infer/path.rs19
-rw-r--r--crates/hir-ty/src/lower.rs2
-rw-r--r--crates/hir-ty/src/tests/traits.rs20
3 files changed, 34 insertions, 7 deletions
diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs
index 266e410187..368c3f6524 100644
--- a/crates/hir-ty/src/infer/path.rs
+++ b/crates/hir-ty/src/infer/path.rs
@@ -30,11 +30,18 @@ impl<'a> InferenceContext<'a> {
fn resolve_value_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<Ty> {
let (value, self_subst) = if let Some(type_ref) = path.type_anchor() {
- let Some(last) = path.segments().last() else { return None };
- let ty = self.make_ty(type_ref);
- let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1);
+ let last = path.segments().last()?;
+
+ // Don't use `self.make_ty()` here as we need `orig_ns`.
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
- let (ty, _) = ctx.lower_ty_relative_path(ty, None, remaining_segments_for_ty);
+ let (ty, orig_ns) = ctx.lower_ty_ext(type_ref);
+ let ty = self.table.insert_type_vars(ty);
+ let ty = self.table.normalize_associated_types_in(ty);
+
+ let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1);
+ let (ty, _) = ctx.lower_ty_relative_path(ty, orig_ns, remaining_segments_for_ty);
+ let ty = self.table.insert_type_vars(ty);
+ let ty = self.table.normalize_associated_types_in(ty);
self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))?
} else {
// FIXME: report error, unresolved first path segment
@@ -169,7 +176,7 @@ impl<'a> InferenceContext<'a> {
) -> Option<(ValueNs, Substitution)> {
let trait_ = trait_ref.hir_trait_id();
let item =
- self.db.trait_data(trait_).items.iter().map(|(_name, id)| (*id)).find_map(|item| {
+ self.db.trait_data(trait_).items.iter().map(|(_name, id)| *id).find_map(|item| {
match item {
AssocItemId::FunctionId(func) => {
if segment.name == &self.db.function_data(func).name {
@@ -288,7 +295,7 @@ impl<'a> InferenceContext<'a> {
name: &Name,
id: ExprOrPatId,
) -> Option<(ValueNs, Substitution)> {
- let ty = self.resolve_ty_shallow(ty);
+ let ty = self.resolve_ty_shallow(&ty);
let (enum_id, subst) = match ty.as_adt() {
Some((AdtId::EnumId(e), subst)) => (e, subst),
_ => return None,
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 797e9ad0e9..adadbb888b 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -103,7 +103,7 @@ impl ImplTraitLoweringState {
#[derive(Debug)]
pub struct TyLoweringContext<'a> {
pub db: &'a dyn HirDatabase,
- pub resolver: &'a Resolver,
+ resolver: &'a Resolver,
in_binders: DebruijnIndex,
/// Note: Conceptually, it's thinkable that we could be in a location where
/// some type params should be represented as placeholders, and others
diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs
index 7e6092f5b6..1201165cfa 100644
--- a/crates/hir-ty/src/tests/traits.rs
+++ b/crates/hir-ty/src/tests/traits.rs
@@ -4239,6 +4239,26 @@ impl Trait for () {
type Assoc = E;
fn f() {
+ let a = Self::Assoc::Unit;
+ // ^ E
+ let a = <Self>::Assoc::Unit;
+ // ^ E
+ let a = <Self::Assoc>::Unit;
+ // ^ E
+ let a = <<Self>::Assoc>::Unit;
+ // ^ E
+
+ // should be `Copy` but we don't track ownership anyway.
+ let value = E::Unit;
+ if let Self::Assoc::Unit = value {}
+ // ^^^^^^^^^^^^^^^^^ E
+ if let <Self>::Assoc::Unit = value {}
+ // ^^^^^^^^^^^^^^^^^^^ E
+ if let <Self::Assoc>::Unit = value {}
+ // ^^^^^^^^^^^^^^^^^^^ E
+ if let <<Self>::Assoc>::Unit = value {}
+ // ^^^^^^^^^^^^^^^^^^^^^ E
+
let x = 42;
let a = Self::Assoc::Struct { x };
// ^ E