Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/infer/callee.rs')
| -rw-r--r-- | crates/hir-ty/src/infer/callee.rs | 67 |
1 files changed, 53 insertions, 14 deletions
diff --git a/crates/hir-ty/src/infer/callee.rs b/crates/hir-ty/src/infer/callee.rs index a470c92124..ffdde58c48 100644 --- a/crates/hir-ty/src/infer/callee.rs +++ b/crates/hir-ty/src/infer/callee.rs @@ -5,7 +5,9 @@ use std::iter; use intern::sym; use tracing::debug; -use hir_def::{CallableDefId, hir::ExprId, signatures::FunctionSignature}; +use hir_def::{ + CallableDefId, ConstParamId, TypeOrConstParamId, hir::ExprId, signatures::FunctionSignature, +}; use rustc_type_ir::{ InferTy, Interner, inherent::{GenericArgs as _, IntoKind, Ty as _}, @@ -20,7 +22,7 @@ use crate::{ }, method_resolution::{MethodCallee, TreatNotYetDefinedOpaques}, next_solver::{ - FnSig, Ty, TyKind, + ConstKind, FnSig, Ty, TyKind, infer::{BoundRegionConversionTime, traits::ObligationCause}, }, }; @@ -82,7 +84,7 @@ impl<'db> InferenceContext<'_, 'db> { } Some(CallStep::Builtin(callee_ty)) => { - self.confirm_builtin_call(call_expr, callee_ty, arg_exprs, expected) + self.confirm_builtin_call(callee_expr, call_expr, callee_ty, arg_exprs, expected) } Some(CallStep::DeferredClosure(_def_id, fn_sig)) => { @@ -128,6 +130,7 @@ impl<'db> InferenceContext<'_, 'db> { { let closure_sig = args.as_closure().sig(); let closure_sig = autoderef.ctx().infcx().instantiate_binder_with_fresh_vars( + callee_expr.into(), BoundRegionConversionTime::FnCall, closure_sig, ); @@ -158,15 +161,16 @@ impl<'db> InferenceContext<'_, 'db> { let closure_args = args.as_coroutine_closure(); let coroutine_closure_sig = autoderef.ctx().infcx().instantiate_binder_with_fresh_vars( + callee_expr.into(), BoundRegionConversionTime::FnCall, closure_args.coroutine_closure_sig(), ); - let tupled_upvars_ty = autoderef.ctx().table.next_ty_var(); + let tupled_upvars_ty = autoderef.ctx().table.next_ty_var(call_expr.into()); // We may actually receive a coroutine back whose kind is different // from the closure that this dispatched from. This is because when // we have no captures, we automatically implement `FnOnce`. This // impl forces the closure kind to `FnOnce` i.e. `u8`. - let kind_ty = autoderef.ctx().table.next_ty_var(); + let kind_ty = autoderef.ctx().table.next_ty_var(call_expr.into()); let interner = autoderef.ctx().interner(); let call_sig = interner.mk_fn_sig( [coroutine_closure_sig.tupled_inputs_ty], @@ -297,7 +301,7 @@ impl<'db> InferenceContext<'_, 'db> { let opt_input_type = opt_arg_exprs.map(|arg_exprs| { Ty::new_tup_from_iter( self.interner(), - arg_exprs.iter().map(|_| self.table.next_ty_var()), + arg_exprs.iter().map(|&arg| self.table.next_ty_var(arg.into())), ) }); @@ -347,12 +351,26 @@ impl<'db> InferenceContext<'_, 'db> { fn check_legacy_const_generics( &mut self, callee: Option<CallableDefId>, + callee_ty: Ty<'db>, args: &[ExprId], ) -> Box<[u32]> { - let func = match callee { - Some(CallableDefId::FunctionId(func)) => func, + let (func, fn_generic_args) = match (callee, callee_ty.kind()) { + (Some(CallableDefId::FunctionId(func)), TyKind::FnDef(_, fn_generic_args)) => { + (func, fn_generic_args) + } _ => return Default::default(), }; + let generics = crate::generics::generics(self.db, func.into()); + let const_params = generics + .iter_self_type_or_consts() + .filter(|(_, param_data)| param_data.const_param().is_some()) + .map(|(idx, _)| { + ConstParamId::from_unchecked(TypeOrConstParamId { + parent: func.into(), + local_id: idx, + }) + }) + .collect::<Vec<_>>(); let data = FunctionSignature::of(self.db, func); let Some(legacy_const_generics_indices) = data.legacy_const_generics_indices(self.db, func) @@ -374,11 +392,29 @@ impl<'db> InferenceContext<'_, 'db> { } // check legacy const parameters - for arg_idx in legacy_const_generics_indices.iter().copied() { + for (const_idx, arg_idx) in legacy_const_generics_indices.iter().copied().enumerate() { if arg_idx >= args.len() as u32 { continue; } - let expected = Expectation::none(); // FIXME use actual const ty, when that is lowered correctly + + if let Some(const_arg) = fn_generic_args.get(const_idx).and_then(|it| it.konst()) + && let ConstKind::Infer(_) = const_arg.kind() + { + // Instantiate the generic arg with an error type, to prevent errors from it. + // FIXME: Actually lower the expression as const. + _ = self + .table + .at(&ObligationCause::dummy()) + .eq(self.types.consts.error, const_arg) + .map(|infer_ok| self.table.register_infer_ok(infer_ok)); + } + + let expected = if let Some(&const_param) = const_params.get(const_idx) { + Expectation::has_type(self.db.const_param_ty(const_param)) + } else { + Expectation::None + }; + self.infer_expr(args[arg_idx as usize], &expected, ExprIsRead::Yes); // FIXME: evaluate and unify with the const } @@ -388,6 +424,7 @@ impl<'db> InferenceContext<'_, 'db> { fn confirm_builtin_call( &mut self, + callee_expr: ExprId, call_expr: ExprId, callee_ty: Ty<'db>, arg_exprs: &[ExprId], @@ -411,11 +448,13 @@ impl<'db> InferenceContext<'_, 'db> { // renormalize the associated types at this point, since they // previously appeared within a `Binder<>` and hence would not // have been normalized before. - let fn_sig = self - .infcx() - .instantiate_binder_with_fresh_vars(BoundRegionConversionTime::FnCall, fn_sig); + let fn_sig = self.infcx().instantiate_binder_with_fresh_vars( + callee_expr.into(), + BoundRegionConversionTime::FnCall, + fn_sig, + ); - let indices_to_skip = self.check_legacy_const_generics(def_id, arg_exprs); + let indices_to_skip = self.check_legacy_const_generics(def_id, callee_ty, arg_exprs); self.check_call_arguments( call_expr, fn_sig.inputs(), |