Repository: rust-lang/rust-analyzer
Pull request #18068 (2024-09-06 12:07:00)

fix: Always explicitly set `TraitRef` self types when lowering


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 9223a9cf4f..6df73c2fd1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -997,12 +997,12 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
 
 [[package]]
 name = "lsp-server"
-version = "0.7.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "248f65b78f6db5d8e1b1604b4098a28b43d21a8eb1deeca22b1c421b276c7095"
+version = "0.7.7"
 dependencies = [
  "crossbeam-channel",
+ "ctrlc",
  "log",
+ "lsp-types",
  "serde",
  "serde_json",
 ]
@@ -1010,11 +1010,11 @@ dependencies = [
 [[package]]
 name = "lsp-server"
 version = "0.7.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "550446e84739dcaf6d48a4a093973850669e13e8a34d8f8d64851041be267cd9"
 dependencies = [
  "crossbeam-channel",
- "ctrlc",
  "log",
- "lsp-types",
  "serde",
  "serde_json",
 ]
@@ -1652,7 +1652,7 @@ dependencies = [
  "intern",
  "itertools",
  "load-cargo",
- "lsp-server 0.7.6",
+ "lsp-server 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "lsp-types",
  "memchr",
  "mimalloc",
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index a82d091cbb..b79aa89db4 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -851,7 +851,7 @@ impl InferenceContext<'_> {
                 };
 
                 for (expr, ty) in exprs.iter().zip(tys.iter_mut()) {
-                    self.infer_expr_coerce(*expr, &Expectation::has_type(ty.clone()));
+                    *ty = self.infer_expr_coerce(*expr, &Expectation::has_type(ty.clone()));
                 }
 
                 TyKind::Tuple(tys.len(), Substitution::from_iter(Interner, tys)).intern(Interner)
diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs
index 0b44bbec70..e4841c7b15 100644
--- a/crates/hir-ty/src/infer/path.rs
+++ b/crates/hir-ty/src/infer/path.rs
@@ -247,8 +247,12 @@ impl InferenceContext<'_> {
                     &self.resolver,
                     self.owner.into(),
                 );
-                let trait_ref =
-                    ctx.lower_trait_ref_from_resolved_path(trait_, resolved_segment, None);
+                let trait_ref = ctx.lower_trait_ref_from_resolved_path(
+                    trait_,
+                    resolved_segment,
+                    self.table.new_type_var(),
+                );
+
                 self.resolve_trait_assoc_item(trait_ref, segment, id)
             }
             (def, _) => {
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 213400d04a..c6c2108e34 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -516,8 +516,11 @@ impl<'a> TyLoweringContext<'a> {
             TypeNs::TraitId(trait_) => {
                 let ty = match remaining_segments.len() {
                     1 => {
-                        let trait_ref =
-                            self.lower_trait_ref_from_resolved_path(trait_, resolved_segment, None);
+                        let trait_ref = self.lower_trait_ref_from_resolved_path(
+                            trait_,
+                            resolved_segment,
+                            TyKind::Error.intern(Interner),
+                        );
                         let segment = remaining_segments.first().unwrap();
                         let found = self
                             .db
@@ -952,11 +955,17 @@ impl<'a> TyLoweringContext<'a> {
         Substitution::from_iter(Interner, substs)
     }
 
-    fn lower_trait_ref_from_path(
+    pub(crate) fn lower_trait_ref_from_resolved_path(
         &self,
-        path: &Path,
-        explicit_self_ty: Option<Ty>,
-    ) -> Option<TraitRef> {
+        resolved: TraitId,
+        segment: PathSegment<'_>,
+        explicit_self_ty: Ty,
+    ) -> TraitRef {
+        let substs = self.trait_ref_substs_from_path(segment, resolved, explicit_self_ty);
+        TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs }
+    }
+
+    fn lower_trait_ref_from_path(&self, path: &Path, explicit_self_ty: Ty) -> Option<TraitRef> {
         let resolved = match self.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), path)? {
             // FIXME(trait_alias): We need to handle trait alias here.
             TypeNs::TraitId(tr) => tr,
@@ -966,21 +975,7 @@ impl<'a> TyLoweringContext<'a> {
         Some(self.lower_trait_ref_from_resolved_path(resolved, segment, explicit_self_ty))
     }
 
-    pub(crate) fn lower_trait_ref_from_resolved_path(
-        &self,
-        resolved: TraitId,
-        segment: PathSegment<'_>,
-        explicit_self_ty: Option<Ty>,
-    ) -> TraitRef {
-        let substs = self.trait_ref_substs_from_path(segment, resolved, explicit_self_ty);
-        TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs }
-    }
-
-    fn lower_trait_ref(
-        &self,
-        trait_ref: &HirTraitRef,
-        explicit_self_ty: Option<Ty>,
-    ) -> Option<TraitRef> {
+    fn lower_trait_ref(&self, trait_ref: &HirTraitRef, explicit_self_ty: Ty) -> Option<TraitRef> {
         self.lower_trait_ref_from_path(&trait_ref.path, explicit_self_ty)
     }
 
@@ -988,9 +983,9 @@ impl<'a> TyLoweringContext<'a> {
         &self,
         segment: PathSegment<'_>,
         resolved: TraitId,
-        explicit_self_ty: Option<Ty>,
+        explicit_self_ty: Ty,
     ) -> Substitution {
-        self.substs_from_path_segment(segment, Some(resolved.into()), false, explicit_self_ty)
+        self.substs_from_path_segment(segment, Some(resolved.into()), false, Some(explicit_self_ty))
     }
 
     pub(crate) fn lower_where_predicate<'b>(
@@ -1041,7 +1036,7 @@ impl<'a> TyLoweringContext<'a> {
         let mut trait_ref = None;
         let clause = match bound.as_ref() {
             TypeBound::Path(path, TraitBoundModifier::None) => {
-                trait_ref = self.lower_trait_ref_from_path(path, Some(self_ty));
+                trait_ref = self.lower_trait_ref_from_path(path, self_ty);
                 trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
             }
             TypeBound::Path(path, TraitBoundModifier::Maybe) => {
@@ -1053,7 +1048,7 @@ impl<'a> TyLoweringContext<'a> {
                 // `?Sized` has no of them.
                 // If we got another trait here ignore the bound completely.
                 let trait_id = self
-                    .lower_trait_ref_from_path(path, Some(self_ty.clone()))
+                    .lower_trait_ref_from_path(path, self_ty.clone())
                     .map(|trait_ref| trait_ref.hir_trait_id());
                 if trait_id == sized_trait {
                     self.unsized_types.borrow_mut().insert(self_ty);
@@ -1062,7 +1057,7 @@ impl<'a> TyLoweringContext<'a> {
             }
             TypeBound::ForLifetime(_, path) => {
                 // FIXME Don't silently drop the hrtb lifetimes here
-                trait_ref = self.lower_trait_ref_from_path(path, Some(self_ty));
+                trait_ref = self.lower_trait_ref_from_path(path, self_ty);
                 trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
             }
             TypeBound::Lifetime(l) => {
@@ -2126,7 +2121,7 @@ pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<
         .with_type_param_mode(ParamLoweringMode::Variable);
     let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders();
     let target_trait = impl_data.target_trait.as_ref()?;
-    Some(Binders::new(binders, ctx.lower_trait_ref(target_trait, Some(self_ty))?))
+    Some(Binders::new(binders, ctx.lower_trait_ref(target_trait, self_ty)?))
 }
 
 pub(crate) fn return_type_impl_traits(
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs
index 89b2ecb1a6..0d42617d18 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -421,9 +421,25 @@ impl MirEvalError {
             }
             MirEvalError::MirLowerError(func, err) => {
                 let function_name = db.function_data(*func);
+                let self_ = match func.lookup(db.upcast()).container {
+                    ItemContainerId::ImplId(impl_id) => Some({
+                        let generics = crate::generics::generics(db.upcast(), impl_id.into());
+                        let substs = generics.placeholder_subst(db);
+                        db.impl_self_ty(impl_id)
+                            .substitute(Interner, &substs)
+                            .display(db, edition)
+                            .to_string()
+                    }),
+                    ItemContainerId::TraitId(it) => {
+                        Some(db.trait_data(it).name.display(db.upcast(), edition).to_string())
+                    }
+                    _ => None,
+                };
                 writeln!(
                     f,
-                    "MIR lowering for function `{}` ({:?}) failed due:",
+                    "MIR lowering for function `{}{}{}` ({:?}) failed due:",
+                    self_.as_deref().unwrap_or_default(),
+                    if self_.is_some() { "::" } else { "" },
                     function_name.name.display(db.upcast(), edition),
                     func
                 )?;
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index 9cee494bbe..a2cb122c54 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -94,7 +94,8 @@ pub enum MirLowerError {
     UnresolvedField,
     UnsizedTemporary(Ty),
     MissingFunctionDefinition(DefWithBodyId, ExprId),
-    TypeMismatch(Option<TypeMismatch>),
+    TypeMismatch(TypeMismatch),
+    HasErrors,
     /// This should never happen. Type mismatch should catch everything.
     TypeError(&'static str),
     NotSupported(String),
@@ -179,15 +180,13 @@ impl MirLowerError {
                     body.pretty_print_expr(db.upcast(), *owner, *it, edition)
                 )?;
             }
-            MirLowerError::TypeMismatch(e) => match e {
-                Some(e) => writeln!(
-                    f,
-                    "Type mismatch: Expected {}, found {}",
-                    e.expected.display(db, edition),
-                    e.actual.display(db, edition),
-                )?,
-                None => writeln!(f, "Type mismatch: types mismatch with {{unknown}}",)?,
-            },
+            MirLowerError::HasErrors => writeln!(f, "Type inference result contains errors")?,
+            MirLowerError::TypeMismatch(e) => writeln!(
+                f,
+                "Type mismatch: Expected {}, found {}",
+                e.expected.display(db, edition),
+                e.actual.display(db, edition),
+            )?,
             MirLowerError::GenericArgNotProvided(id, subst) => {
                 let parent = id.parent;
                 let param = &db.generic_params(parent)[id.local_id];
@@ -2184,7 +2183,7 @@ pub fn lower_to_mir(
     root_expr: ExprId,
 ) -> Result<MirBody> {
     if infer.has_errors {
-        return Err(MirLowerError::TypeMismatch(None));
+        return Err(MirLowerError::HasErrors);
     }
     let mut ctx = MirLowerCtx::new(db, owner, body, infer);
     // 0 is return local
diff --git a/crates/ide-diagnostics/src/handlers/invalid_cast.rs b/crates/ide-diagnostics/src/handlers/invalid_cast.rs
index 2f6f033f25..9eb4e618c0 100644
--- a/crates/ide-diagnostics/src/handlers/invalid_cast.rs
+++ b/crates/ide-diagnostics/src/handlers/invalid_cast.rs
@@ -831,7 +831,7 @@ fn main() {
 //- minicore: sized
 fn main() {
     _ = ((), ()) as ();
-      //^^^^^^^^^^^^^^ error: non-primitive cast: `(_, _)` as `()`
+      //^^^^^^^^^^^^^^ error: non-primitive cast: `((), ())` as `()`
 }
 "#,
         );
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index 35e1da80bf..89487aa673 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -540,7 +540,7 @@ impl GlobalState {
     }
 
     pub(crate) fn respond(&mut self, response: lsp_server::Response) {
-        if let Some((method, start)) = self.req_queue.incoming.complete(response.id.clone()) {
+        if let Some((method, start)) = self.req_queue.incoming.complete(&response.id) {
             if let Some(err) = &response.error {
                 if err.message.starts_with("server panicked") {
                     self.poke_rust_analyzer_developer(format!("{}, check the log", err.message))


Test patch:
diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs
index 203e21302c..7093fcadcb 100644
--- a/crates/hir-ty/src/consteval/tests.rs
+++ b/crates/hir-ty/src/consteval/tests.rs
@@ -1556,7 +1556,7 @@ fn builtin_derive_macro() {
         Bar,
     }
     #[derive(Clone)]
-    struct X(i32, Z, i64)
+    struct X(i32, Z, i64);
     #[derive(Clone)]
     struct Y {
         field1: i32,
@@ -1574,20 +1574,20 @@ fn builtin_derive_macro() {
     );
     check_number(
         r#"
-    //- minicore: default, derive, builtin_impls
-    #[derive(Default)]
-    struct X(i32, Y, i64)
-    #[derive(Default)]
-    struct Y {
-        field1: i32,
-        field2: u8,
-    }
+//- minicore: default, derive, builtin_impls
+#[derive(Default)]
+struct X(i32, Y, i64);
+#[derive(Default)]
+struct Y {
+    field1: i32,
+    field2: u8,
+}
 
-    const GOAL: u8 = {
-        let x = X::default();
-        x.1.field2
-    };
-    "#,
+const GOAL: u8 = {
+    let x = X::default();
+    x.1.field2
+};
+"#,
         0,
     );
 }
@@ -2828,7 +2828,7 @@ fn type_error() {
         y.0
     };
     "#,
-        |e| matches!(e, ConstEvalError::MirLowerError(MirLowerError::TypeMismatch(_))),
+        |e| matches!(e, ConstEvalError::MirLowerError(MirLowerError::HasErrors)),
     );
 }
 
diff --git a/crates/test-fixture/src/lib.rs b/crates/test-fixture/src/lib.rs
index 03e85a898a..faf9d22047 100644
--- a/crates/test-fixture/src/lib.rs
+++ b/crates/test-fixture/src/lib.rs
@@ -95,8 +95,10 @@ pub trait WithFixture: Default + ExpandDatabase + SourceRootDatabase + 'static {
     fn test_crate(&self) -> CrateId {
         let crate_graph = self.crate_graph();
         let mut it = crate_graph.iter();
-        let res = it.next().unwrap();
-        assert!(it.next().is_none());
+        let mut res = it.next().unwrap();
+        while crate_graph[res].origin.is_lang() {
+            res = it.next().unwrap();
+        }
         res
     }
 }
diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs
index fec270a556..67629fcf7c 100644
--- a/crates/test-utils/src/minicore.rs
+++ b/crates/test-utils/src/minicore.rs
@@ -171,7 +171,7 @@ pub mod default {
     macro_rules! impl_default {
         ($v:literal; $($t:ty)*) => {
             $(
-                impl const Default for $t {
+                impl Default for $t {
                     fn default() -> Self {
                         $v
                     }
@@ -686,7 +686,7 @@ pub mod ops {
     // endregion:fn
     // region:try
     mod try_ {
-        use super::super::convert::Infallible;
+        use crate::convert::Infallible;
 
         pub enum ControlFlow<B, C = ()> {
             #[lang = "Continue"]
@@ -756,7 +756,7 @@ pub mod ops {
         // endregion:option
         // region:result
         // region:from
-        use super::super::convert::From;
+        use crate::convert::From;
 
         impl<T, E> Try for Result<T, E> {
             type Output = T;
@@ -777,7 +777,7 @@ pub mod ops {
         impl<T, E, F: From<E>> FromResidual<Result<Infallible, E>> for Result<T, F> {
             fn from_residual(residual: Result<Infallible, E>) -> Self {
                 match residual {
-                    Err(e) => Err(From::from(e)),
+                    Err(e) => Err(F::from(e)),
                     Ok(_) => loop {},
                 }
             }