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
This commit is contained in:
bors 2024-07-31 07:09:57 +00:00
commit 8bbd23ade9
2 changed files with 74 additions and 24 deletions

View file

@ -12,7 +12,7 @@ use hir_def::{
ArithOp, Array, BinaryOp, ClosureKind, Expr, ExprId, LabelId, Literal, Statement, UnaryOp, ArithOp, Array, BinaryOp, ClosureKind, Expr, ExprId, LabelId, Literal, Statement, UnaryOp,
}, },
lang_item::{LangItem, LangItemTarget}, lang_item::{LangItem, LangItemTarget},
path::{GenericArgs, Path}, path::{GenericArg, GenericArgs, Path},
BlockId, FieldId, GenericDefId, GenericParamId, ItemContainerId, Lookup, TupleFieldId, TupleId, BlockId, FieldId, GenericDefId, GenericParamId, ItemContainerId, Lookup, TupleFieldId, TupleId,
}; };
use hir_expand::name::Name; use hir_expand::name::Name;
@ -1851,29 +1851,45 @@ impl InferenceContext<'_> {
if let Some(generic_args) = generic_args { if let Some(generic_args) = generic_args {
// if args are provided, it should be all of them, but we can't rely on that // 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; 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 mut args = generic_args.args.iter().peekable();
{ for kind_id in def_generics.iter_self_id().take(self_params) {
let arg = generic_arg_to_chalk( let arg = args.peek();
self.db, let arg = match (kind_id, arg) {
kind_id, // Lifetimes can be elided.
arg, // Once we have implemented lifetime elision correctly,
self, // this should be handled in a proper way.
|this, type_ref| this.make_ty(type_ref), (
|this, c, ty| { GenericParamId::LifetimeParamId(_),
const_or_path_to_chalk( None | Some(GenericArg::Type(_) | GenericArg::Const(_)),
this.db, ) => error_lifetime().cast(Interner),
&this.resolver,
this.owner.into(), // If we run out of `generic_args`, stop pushing substs
ty, (_, None) => break,
c,
ParamLoweringMode::Placeholder, // Normal cases
|| this.generics(), (_, Some(_)) => generic_arg_to_chalk(
DebruijnIndex::INNERMOST, self.db,
) kind_id,
}, args.next().unwrap(), // `peek()` is `Some(_)`, so guaranteed no panic
|this, lt_ref| this.make_lifetime(lt_ref), 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); substs.push(arg);
} }
}; };

View file

@ -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>;
}
"#,
)
}