about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-07-31 07:09:57 +0000
committerbors <bors@rust-lang.org>2024-07-31 07:09:57 +0000
commit9fb03f0f21e700b5470787bf76a3cf9a154472ec (patch)
treec103e3119ed5436abb832d6bec63433d657c8e7a
parent51a0dd26776bb5a15556dc63fc069a7cfb6f47c1 (diff)
parent1b058b796d5b711a13ec6918ea5a96f7031c6a5f (diff)
downloadrust-9fb03f0f21e700b5470787bf76a3cf9a154472ec.tar.gz
rust-9fb03f0f21e700b5470787bf76a3cf9a154472ec.zip
Auto merge of #17747 - ShoyuVanilla:issue-17734, r=Veykril
fix: Errors on method call inferences with elided lifetimes

Fixes #17734

Currently, we are matching non-lifetime(type or const) generic arg to liftime argument position while building substs for method calling when there are elided lifetimes.
This mismatch just make a subst for error lifetime and while this alone is not much a trouble, it also makes the mismatched type or const generic arg cannot be used in its proper place and this makes type inference failure
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs64
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs34
2 files changed, 74 insertions, 24 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
index 24479a027fd..3d762b174ac 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
@@ -12,7 +12,7 @@ use hir_def::{
         ArithOp, Array, BinaryOp, ClosureKind, Expr, ExprId, LabelId, Literal, Statement, UnaryOp,
     },
     lang_item::{LangItem, LangItemTarget},
-    path::{GenericArgs, Path},
+    path::{GenericArg, GenericArgs, Path},
     BlockId, FieldId, GenericDefId, GenericParamId, ItemContainerId, Lookup, TupleFieldId, TupleId,
 };
 use hir_expand::name::Name;
@@ -1851,29 +1851,45 @@ impl InferenceContext<'_> {
         if let Some(generic_args) = generic_args {
             // if args are provided, it should be all of them, but we can't rely on that
             let self_params = type_params + const_params + lifetime_params;
-            for (arg, kind_id) in
-                generic_args.args.iter().zip(def_generics.iter_self_id()).take(self_params)
-            {
-                let arg = generic_arg_to_chalk(
-                    self.db,
-                    kind_id,
-                    arg,
-                    self,
-                    |this, type_ref| this.make_ty(type_ref),
-                    |this, c, ty| {
-                        const_or_path_to_chalk(
-                            this.db,
-                            &this.resolver,
-                            this.owner.into(),
-                            ty,
-                            c,
-                            ParamLoweringMode::Placeholder,
-                            || this.generics(),
-                            DebruijnIndex::INNERMOST,
-                        )
-                    },
-                    |this, lt_ref| this.make_lifetime(lt_ref),
-                );
+
+            let mut args = generic_args.args.iter().peekable();
+            for kind_id in def_generics.iter_self_id().take(self_params) {
+                let arg = args.peek();
+                let arg = match (kind_id, arg) {
+                    // Lifetimes can be elided.
+                    // Once we have implemented lifetime elision correctly,
+                    // this should be handled in a proper way.
+                    (
+                        GenericParamId::LifetimeParamId(_),
+                        None | Some(GenericArg::Type(_) | GenericArg::Const(_)),
+                    ) => error_lifetime().cast(Interner),
+
+                    // If we run out of `generic_args`, stop pushing substs
+                    (_, None) => break,
+
+                    // Normal cases
+                    (_, Some(_)) => generic_arg_to_chalk(
+                        self.db,
+                        kind_id,
+                        args.next().unwrap(), // `peek()` is `Some(_)`, so guaranteed no panic
+                        self,
+                        |this, type_ref| this.make_ty(type_ref),
+                        |this, c, ty| {
+                            const_or_path_to_chalk(
+                                this.db,
+                                &this.resolver,
+                                this.owner.into(),
+                                ty,
+                                c,
+                                ParamLoweringMode::Placeholder,
+                                || this.generics(),
+                                DebruijnIndex::INNERMOST,
+                            )
+                        },
+                        |this, lt_ref| this.make_lifetime(lt_ref),
+                    ),
+                };
+
                 substs.push(arg);
             }
         };
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
index aa7b00b8deb..b371e5856b0 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
@@ -2041,3 +2041,37 @@ fn main() {
 "#,
     );
 }
+
+#[test]
+fn issue_17734() {
+    check_types(
+        r#"
+fn test() {
+    let x = S::foo::<'static, &()>(&S);
+     // ^ Wrap<'?, ()>
+    let x = S::foo::<&()>(&S);
+     // ^ Wrap<'?, ()>
+    let x = S.foo::<'static, &()>();
+     // ^ Wrap<'?, ()>
+    let x = S.foo::<&()>();
+     // ^ Wrap<'?, ()>
+}
+
+struct S;
+
+impl S {
+    pub fn foo<'a, T: Trait<'a>>(&'a self) -> T::Proj {
+        loop {}
+    }
+}
+
+struct Wrap<'a, T>(T);
+trait Trait<'a> {
+    type Proj;
+}
+impl<'a, T> Trait<'a> for &'a T {
+    type Proj = Wrap<'a, T>;
+}
+"#,
+    )
+}