Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/infer/expr.rs')
| -rw-r--r-- | crates/hir-ty/src/infer/expr.rs | 206 |
1 files changed, 126 insertions, 80 deletions
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index 17cd322a22..2980549c23 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -12,7 +12,7 @@ use hir_def::{ expr_store::path::{GenericArg, GenericArgs, Path}, hir::{ ArithOp, Array, AsmOperand, AsmOptions, BinaryOp, Expr, ExprId, ExprOrPatId, LabelId, - Literal, Pat, PatId, Statement, UnaryOp, + Literal, Pat, PatId, Statement, UnaryOp, generics::GenericParamDataRef, }, lang_item::{LangItem, LangItemTarget}, resolver::ValueNs, @@ -24,11 +24,11 @@ use syntax::ast::RangeOp; use crate::{ Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, CallableSig, DeclContext, - DeclOrigin, Interner, Rawness, Scalar, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, - TyExt, TyKind, + DeclOrigin, IncorrectGenericsLenKind, Interner, Rawness, Scalar, Substitution, + TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, autoderef::{Autoderef, builtin_deref, deref_by_trait}, - consteval, error_lifetime, - generics::{Generics, generics}, + consteval, + generics::generics, infer::{ BreakableKind, coerce::{CoerceMany, CoerceNever, CoercionCause}, @@ -36,7 +36,10 @@ use crate::{ pat::contains_explicit_ref_binding, }, lang_items::lang_items_for_bin_op, - lower::{ParamLoweringMode, generic_arg_to_chalk, lower_to_chalk_mutability}, + lower::{ + GenericArgsPosition, ParamLoweringMode, lower_to_chalk_mutability, + path::{GenericArgsLowerer, TypeLikeConst, substs_from_args_and_bindings}, + }, mapping::{ToChalk, from_chalk}, method_resolution::{self, VisibleFromModule}, primitive::{self, UintTy}, @@ -1658,8 +1661,7 @@ impl InferenceContext<'_> { match resolved { Some((adjust, func, _)) => { let (ty, adjustments) = adjust.apply(&mut self.table, receiver_ty); - let generics = generics(self.db, func.into()); - let substs = self.substs_for_method_call(generics, None); + let substs = self.substs_for_method_call(tgt_expr, func.into(), None); self.write_expr_adj(receiver, adjustments); self.write_method_resolution(tgt_expr, func, substs.clone()); @@ -1809,8 +1811,7 @@ impl InferenceContext<'_> { let (ty, adjustments) = adjust.apply(&mut self.table, receiver_ty); self.write_expr_adj(receiver, adjustments); - let generics = generics(self.db, func.into()); - let substs = self.substs_for_method_call(generics, generic_args); + let substs = self.substs_for_method_call(tgt_expr, func.into(), generic_args); self.write_method_resolution(tgt_expr, func, substs.clone()); self.check_method_call( tgt_expr, @@ -1860,8 +1861,7 @@ impl InferenceContext<'_> { let recovered = match assoc_func_with_same_name { Some(f) => { - let generics = generics(self.db, f.into()); - let substs = self.substs_for_method_call(generics, generic_args); + let substs = self.substs_for_method_call(tgt_expr, f.into(), generic_args); let f = self .db .value_ty(f.into()) @@ -2051,83 +2051,129 @@ impl InferenceContext<'_> { fn substs_for_method_call( &mut self, - def_generics: Generics, + expr: ExprId, + def: GenericDefId, generic_args: Option<&GenericArgs>, ) -> Substitution { - let ( - parent_params, - has_self_param, - type_params, - const_params, - impl_trait_params, - lifetime_params, - ) = def_generics.provenance_split(); - assert!(!has_self_param); // method shouldn't have another Self param - let total_len = - parent_params + type_params + const_params + impl_trait_params + lifetime_params; - - let param_to_var = |id| match id { - GenericParamId::TypeParamId(_) => self.table.new_type_var().cast(Interner), - GenericParamId::ConstParamId(id) => { - self.table.new_const_var(self.db.const_param_ty(id)).cast(Interner) - } - GenericParamId::LifetimeParamId(_) => self.table.new_lifetime_var().cast(Interner), - }; + struct LowererCtx<'a, 'b> { + ctx: &'a mut InferenceContext<'b>, + expr: ExprId, + } - let mut substs: Vec<_> = def_generics.iter_parent_id().map(param_to_var).collect(); - - // handle provided arguments - 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; - - 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 inferred. - // Once we have implemented lifetime inference 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, - &self.body.store, - |this, type_ref| this.make_body_ty(type_ref), - |this, c, ty| this.make_body_const(*c, ty), - |this, path, ty| this.make_path_as_body_const(path, ty), - |this, lt_ref| this.make_body_lifetime(lt_ref), - ), - }; + impl GenericArgsLowerer for LowererCtx<'_, '_> { + fn report_len_mismatch( + &mut self, + def: GenericDefId, + provided_count: u32, + expected_count: u32, + kind: IncorrectGenericsLenKind, + ) { + self.ctx.push_diagnostic(InferenceDiagnostic::MethodCallIncorrectGenericsLen { + expr: self.expr, + provided_count, + expected_count, + kind, + def, + }); + } - substs.push(arg); + fn report_arg_mismatch( + &mut self, + param_id: GenericParamId, + arg_idx: u32, + has_self_arg: bool, + ) { + self.ctx.push_diagnostic(InferenceDiagnostic::MethodCallIncorrectGenericsOrder { + expr: self.expr, + param_id, + arg_idx, + has_self_arg, + }); } - }; - let mut param_to_var = |id| match id { - GenericParamId::TypeParamId(_) => self.table.new_type_var().cast(Interner), - GenericParamId::ConstParamId(id) => { - self.table.new_const_var(self.db.const_param_ty(id)).cast(Interner) + fn provided_kind( + &mut self, + param_id: GenericParamId, + param: GenericParamDataRef<'_>, + arg: &GenericArg, + ) -> crate::GenericArg { + match (param, arg) { + (GenericParamDataRef::LifetimeParamData(_), GenericArg::Lifetime(lifetime)) => { + self.ctx.make_body_lifetime(lifetime).cast(Interner) + } + (GenericParamDataRef::TypeParamData(_), GenericArg::Type(type_ref)) => { + self.ctx.make_body_ty(*type_ref).cast(Interner) + } + (GenericParamDataRef::ConstParamData(_), GenericArg::Const(konst)) => { + let GenericParamId::ConstParamId(const_id) = param_id else { + unreachable!("non-const param ID for const param"); + }; + let const_ty = self.ctx.db.const_param_ty(const_id); + self.ctx.make_body_const(*konst, const_ty).cast(Interner) + } + _ => unreachable!("unmatching param kinds were passed to `provided_kind()`"), + } + } + + fn provided_type_like_const( + &mut self, + const_ty: Ty, + arg: TypeLikeConst<'_>, + ) -> crate::Const { + match arg { + TypeLikeConst::Path(path) => self.ctx.make_path_as_body_const(path, const_ty), + TypeLikeConst::Infer => self.ctx.table.new_const_var(const_ty), + } } - GenericParamId::LifetimeParamId(_) => self.table.new_lifetime_var().cast(Interner), - }; - // Handle everything else as unknown. - for (id, _data) in def_generics.iter().skip(substs.len()) { - substs.push(param_to_var(id)); + fn inferred_kind( + &mut self, + _def: GenericDefId, + param_id: GenericParamId, + _param: GenericParamDataRef<'_>, + _infer_args: bool, + _preceding_args: &[crate::GenericArg], + ) -> crate::GenericArg { + // Always create an inference var, even when `infer_args == false`. This helps with diagnostics, + // and I think it's also required in the presence of `impl Trait` (that must be inferred). + match param_id { + GenericParamId::TypeParamId(_) => self.ctx.table.new_type_var().cast(Interner), + GenericParamId::ConstParamId(const_id) => self + .ctx + .table + .new_const_var(self.ctx.db.const_param_ty(const_id)) + .cast(Interner), + GenericParamId::LifetimeParamId(_) => { + self.ctx.table.new_lifetime_var().cast(Interner) + } + } + } + + fn parent_arg(&mut self, param_id: GenericParamId) -> crate::GenericArg { + match param_id { + GenericParamId::TypeParamId(_) => self.ctx.table.new_type_var().cast(Interner), + GenericParamId::ConstParamId(const_id) => self + .ctx + .table + .new_const_var(self.ctx.db.const_param_ty(const_id)) + .cast(Interner), + GenericParamId::LifetimeParamId(_) => { + self.ctx.table.new_lifetime_var().cast(Interner) + } + } + } } - assert_eq!(substs.len(), total_len); - Substitution::from_iter(Interner, substs) + + substs_from_args_and_bindings( + self.db, + self.body, + generic_args, + def, + true, + GenericArgsPosition::MethodCall, + None, + &mut LowererCtx { ctx: self, expr }, + ) } fn register_obligations_for_call(&mut self, callable_ty: &Ty) { |