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.rs206
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) {