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.rs67
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(),