From 92a6e51b204b3afe69fa4dd0c5639ab72bd05f0b Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Wed, 31 Jul 2024 02:36:44 +0900 Subject: [PATCH 1/2] fix: Errors on method call inferences with elided lifetimes --- crates/hir-ty/src/infer/expr.rs | 64 +++++++++++++++++---------- crates/hir-ty/src/tests/regression.rs | 32 ++++++++++++++ 2 files changed, 72 insertions(+), 24 deletions(-) diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index 24479a027f..3d762b174a 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/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/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs index aa7b00b8de..540e219920 100644 --- a/crates/hir-ty/src/tests/regression.rs +++ b/crates/hir-ty/src/tests/regression.rs @@ -2041,3 +2041,35 @@ 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::<&()>(); + // ^ 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>; +} +"#, + ) +} From a8717301428a53ea159d1b42d7c9bd0a6807f30b Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Wed, 31 Jul 2024 10:47:13 +0900 Subject: [PATCH 2/2] Add a test case --- crates/hir-ty/src/tests/regression.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs index 540e219920..b371e5856b 100644 --- a/crates/hir-ty/src/tests/regression.rs +++ b/crates/hir-ty/src/tests/regression.rs @@ -2051,6 +2051,8 @@ fn test() { // ^ Wrap<'?, ()> let x = S::foo::<&()>(&S); // ^ Wrap<'?, ()> + let x = S.foo::<'static, &()>(); + // ^ Wrap<'?, ()> let x = S.foo::<&()>(); // ^ Wrap<'?, ()> }