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.rs460
1 files changed, 278 insertions, 182 deletions
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index ee186673ee..33e98ac86c 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -6,37 +6,43 @@ use std::{
};
use chalk_ir::{
- cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyKind, TyVariableKind,
+ cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind,
};
use hir_def::{
- expr::{
+ generics::TypeOrConstParamData,
+ hir::{
ArithOp, Array, BinaryOp, ClosureKind, Expr, ExprId, LabelId, Literal, Statement, UnaryOp,
},
- generics::TypeOrConstParamData,
- lang_item::LangItem,
+ lang_item::{LangItem, LangItemTarget},
path::{GenericArg, GenericArgs},
- ConstParamId, FieldId, ItemContainerId, Lookup,
+ BlockId, ConstParamId, FieldId, ItemContainerId, Lookup,
};
use hir_expand::name::{name, Name};
use stdx::always;
use syntax::ast::RangeOp;
+use triomphe::Arc;
use crate::{
- autoderef::{self, Autoderef},
+ autoderef::{builtin_deref, deref_by_trait, Autoderef},
consteval,
infer::{
- coerce::CoerceMany, find_continuable, pat::contains_explicit_ref_binding, BreakableKind,
+ coerce::{CoerceMany, CoercionCause},
+ find_continuable,
+ pat::contains_explicit_ref_binding,
+ BreakableKind,
},
+ lang_items::lang_items_for_bin_op,
lower::{
const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
},
mapping::{from_chalk, ToChalk},
- method_resolution::{self, lang_items_for_bin_op, VisibleFromModule},
+ method_resolution::{self, VisibleFromModule},
primitive::{self, UintTy},
static_lifetime, to_chalk_trait_id,
+ traits::FnTrait,
utils::{generics, Generics},
Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, FnPointer, FnSig, FnSubst,
- Interner, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt,
+ Interner, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
};
use super::{
@@ -83,10 +89,10 @@ impl<'a> InferenceContext<'a> {
}
}
- pub(super) fn infer_expr_coerce_never(&mut self, expr: ExprId, expected: &Expectation) -> Ty {
+ fn infer_expr_coerce_never(&mut self, expr: ExprId, expected: &Expectation) -> Ty {
let ty = self.infer_expr_inner(expr, expected);
// While we don't allow *arbitrary* coercions here, we *do* allow
- // coercions from ! to `expected`.
+ // coercions from `!` to `expected`.
if ty.is_never() {
if let Some(adjustments) = self.result.expr_adjustments.get(&expr) {
return if let [Adjustment { kind: Adjust::NeverToAny, target }] = &**adjustments {
@@ -96,13 +102,22 @@ impl<'a> InferenceContext<'a> {
};
}
- let adj_ty = self.table.new_type_var();
- self.write_expr_adj(
- expr,
- vec![Adjustment { kind: Adjust::NeverToAny, target: adj_ty.clone() }],
- );
- adj_ty
+ if let Some(target) = expected.only_has_type(&mut self.table) {
+ self.coerce(Some(expr), &ty, &target)
+ .expect("never-to-any coercion should always succeed")
+ } else {
+ ty
+ }
} else {
+ if let Some(expected_ty) = expected.only_has_type(&mut self.table) {
+ let could_unify = self.unify(&ty, &expected_ty);
+ if !could_unify {
+ self.result.type_mismatches.insert(
+ expr.into(),
+ TypeMismatch { expected: expected_ty, actual: ty.clone() },
+ );
+ }
+ }
ty
}
}
@@ -120,24 +135,28 @@ impl<'a> InferenceContext<'a> {
);
let condition_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
- let mut both_arms_diverge = Diverges::Always;
let then_ty = self.infer_expr_inner(then_branch, expected);
- both_arms_diverge &= mem::replace(&mut self.diverges, Diverges::Maybe);
+ let then_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
let mut coerce = CoerceMany::new(expected.coercion_target_type(&mut self.table));
- coerce.coerce(self, Some(then_branch), &then_ty);
+ coerce.coerce(self, Some(then_branch), &then_ty, CoercionCause::Expr(then_branch));
match else_branch {
Some(else_branch) => {
let else_ty = self.infer_expr_inner(else_branch, expected);
- coerce.coerce(self, Some(else_branch), &else_ty);
+ let else_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
+ coerce.coerce(
+ self,
+ Some(else_branch),
+ &else_ty,
+ CoercionCause::Expr(else_branch),
+ );
+ self.diverges = condition_diverges | then_diverges & else_diverges;
}
None => {
- coerce.coerce_forced_unit(self);
+ coerce.coerce_forced_unit(self, CoercionCause::Expr(tgt_expr));
+ self.diverges = condition_diverges;
}
}
- both_arms_diverge &= self.diverges;
-
- self.diverges = condition_diverges | both_arms_diverge;
coerce.complete(self)
}
@@ -146,67 +165,21 @@ impl<'a> InferenceContext<'a> {
self.infer_top_pat(pat, &input_ty);
self.result.standard_types.bool_.clone()
}
- Expr::Block { statements, tail, label, id: _ } => {
- self.infer_block(tgt_expr, statements, *tail, *label, expected)
+ Expr::Block { statements, tail, label, id } => {
+ self.infer_block(tgt_expr, *id, statements, *tail, *label, expected)
}
- Expr::Unsafe { id: _, statements, tail } => {
- self.infer_block(tgt_expr, statements, *tail, None, expected)
+ Expr::Unsafe { id, statements, tail } => {
+ self.infer_block(tgt_expr, *id, statements, *tail, None, expected)
}
- Expr::Const { id: _, statements, tail } => {
+ Expr::Const(id) => {
self.with_breakable_ctx(BreakableKind::Border, None, None, |this| {
- this.infer_block(tgt_expr, statements, *tail, None, expected)
+ let (_, expr) = this.db.lookup_intern_anonymous_const(*id);
+ this.infer_expr(expr, expected)
})
.1
}
- Expr::TryBlock { id: _, statements, tail } => {
- // The type that is returned from the try block
- let try_ty = self.table.new_type_var();
- if let Some(ty) = expected.only_has_type(&mut self.table) {
- self.unify(&try_ty, &ty);
- }
-
- // The ok-ish type that is expected from the last expression
- let ok_ty =
- self.resolve_associated_type(try_ty.clone(), self.resolve_ops_try_output());
-
- self.infer_block(
- tgt_expr,
- statements,
- *tail,
- None,
- &Expectation::has_type(ok_ty.clone()),
- );
- try_ty
- }
- Expr::Async { id: _, statements, tail } => {
- let ret_ty = self.table.new_type_var();
- let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
- let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
- let prev_ret_coercion =
- mem::replace(&mut self.return_coercion, Some(CoerceMany::new(ret_ty.clone())));
-
- let (_, inner_ty) =
- self.with_breakable_ctx(BreakableKind::Border, None, None, |this| {
- this.infer_block(
- tgt_expr,
- statements,
- *tail,
- None,
- &Expectation::has_type(ret_ty),
- )
- });
-
- self.diverges = prev_diverges;
- self.return_ty = prev_ret_ty;
- self.return_coercion = prev_ret_coercion;
-
- // Use the first type parameter as the output type of future.
- // existential type AsyncBlockImplTrait<InnerType>: Future<Output = InnerType>
- let impl_trait_id =
- crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, tgt_expr);
- let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
- TyKind::OpaqueType(opaque_ty_id, Substitution::from1(Interner, inner_ty))
- .intern(Interner)
+ Expr::Async { id, statements, tail } => {
+ self.infer_async_block(tgt_expr, id, statements, tail)
}
&Expr::Loop { body, label } => {
// FIXME: should be:
@@ -238,25 +211,7 @@ impl<'a> InferenceContext<'a> {
self.diverges = Diverges::Maybe;
TyBuilder::unit()
}
- &Expr::For { iterable, body, pat, label } => {
- let iterable_ty = self.infer_expr(iterable, &Expectation::none());
- let into_iter_ty =
- self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
- let pat_ty = self
- .resolve_associated_type(into_iter_ty.clone(), self.resolve_iterator_item());
-
- self.result.type_of_for_iterator.insert(tgt_expr, into_iter_ty);
-
- self.infer_top_pat(pat, &pat_ty);
- self.with_breakable_ctx(BreakableKind::Loop, None, label, |this| {
- this.infer_expr(body, &Expectation::HasType(TyBuilder::unit()));
- });
-
- // the body may not run, so it diverging doesn't mean we diverge
- self.diverges = Diverges::Maybe;
- TyBuilder::unit()
- }
- Expr::Closure { body, args, ret_type, arg_types, closure_kind } => {
+ Expr::Closure { body, args, ret_type, arg_types, closure_kind, capture_by: _ } => {
assert_eq!(args.len(), arg_types.len());
let mut sig_tys = Vec::with_capacity(arg_types.len() + 1);
@@ -276,18 +231,7 @@ impl<'a> InferenceContext<'a> {
None => self.table.new_type_var(),
};
if let ClosureKind::Async = closure_kind {
- // Use the first type parameter as the output type of future.
- // existential type AsyncBlockImplTrait<InnerType>: Future<Output = InnerType>
- let impl_trait_id =
- crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, *body);
- let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
- sig_tys.push(
- TyKind::OpaqueType(
- opaque_ty_id,
- Substitution::from1(Interner, ret_ty.clone()),
- )
- .intern(Interner),
- );
+ sig_tys.push(self.lower_async_block_type_impl_trait(ret_ty.clone(), *body));
} else {
sig_tys.push(ret_ty.clone());
}
@@ -302,7 +246,7 @@ impl<'a> InferenceContext<'a> {
})
.intern(Interner);
- let (ty, resume_yield_tys) = match closure_kind {
+ let (id, ty, resume_yield_tys) = match closure_kind {
ClosureKind::Generator(_) => {
// FIXME: report error when there are more than 1 parameter.
let resume_ty = match sig_tys.first() {
@@ -322,17 +266,20 @@ impl<'a> InferenceContext<'a> {
let generator_id = self.db.intern_generator((self.owner, tgt_expr)).into();
let generator_ty = TyKind::Generator(generator_id, subst).intern(Interner);
- (generator_ty, Some((resume_ty, yield_ty)))
+ (None, generator_ty, Some((resume_ty, yield_ty)))
}
ClosureKind::Closure | ClosureKind::Async => {
let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into();
let closure_ty = TyKind::Closure(
closure_id,
- Substitution::from1(Interner, sig_ty.clone()),
+ TyBuilder::subst_for_closure(self.db, self.owner, sig_ty.clone()),
)
.intern(Interner);
-
- (closure_ty, None)
+ self.deferred_closures.entry(closure_id).or_default();
+ if let Some(c) = self.current_closure {
+ self.closure_dependencies.entry(c).or_default().push(closure_id);
+ }
+ (Some(closure_id), closure_ty, None)
}
};
@@ -348,9 +295,10 @@ impl<'a> InferenceContext<'a> {
// FIXME: lift these out into a struct
let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
+ let prev_closure = mem::replace(&mut self.current_closure, id);
let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
let prev_ret_coercion =
- mem::replace(&mut self.return_coercion, Some(CoerceMany::new(ret_ty.clone())));
+ mem::replace(&mut self.return_coercion, Some(CoerceMany::new(ret_ty)));
let prev_resume_yield_tys =
mem::replace(&mut self.resume_yield_tys, resume_yield_tys);
@@ -361,6 +309,7 @@ impl<'a> InferenceContext<'a> {
self.diverges = prev_diverges;
self.return_ty = prev_ret_ty;
self.return_coercion = prev_ret_coercion;
+ self.current_closure = prev_closure;
self.resume_yield_tys = prev_resume_yield_tys;
ty
@@ -385,16 +334,31 @@ impl<'a> InferenceContext<'a> {
|| res.is_none();
let (param_tys, ret_ty) = match res {
Some((func, params, ret_ty)) => {
- let adjustments = auto_deref_adjust_steps(&derefs);
- // FIXME: Handle call adjustments for Fn/FnMut
- self.write_expr_adj(*callee, adjustments);
- if let Some((trait_, func)) = func {
- let subst = TyBuilder::subst_for_def(self.db, trait_, None)
- .push(callee_ty.clone())
- .push(TyBuilder::tuple_with(params.iter().cloned()))
- .build();
- self.write_method_resolution(tgt_expr, func, subst.clone());
+ let mut adjustments = auto_deref_adjust_steps(&derefs);
+ if let TyKind::Closure(c, _) =
+ self.table.resolve_completely(callee_ty.clone()).kind(Interner)
+ {
+ if let Some(par) = self.current_closure {
+ self.closure_dependencies.entry(par).or_default().push(*c);
+ }
+ self.deferred_closures.entry(*c).or_default().push((
+ derefed_callee.clone(),
+ callee_ty.clone(),
+ params.clone(),
+ tgt_expr,
+ ));
}
+ if let Some(fn_x) = func {
+ self.write_fn_trait_method_resolution(
+ fn_x,
+ &derefed_callee,
+ &mut adjustments,
+ &callee_ty,
+ &params,
+ tgt_expr,
+ );
+ }
+ self.write_expr_adj(*callee, adjustments);
(params, ret_ty)
}
None => {
@@ -470,7 +434,7 @@ impl<'a> InferenceContext<'a> {
let arm_ty = self.infer_expr_inner(arm.expr, &expected);
all_arms_diverge &= self.diverges;
- coerce.coerce(self, Some(arm.expr), &arm_ty);
+ coerce.coerce(self, Some(arm.expr), &arm_ty, CoercionCause::Expr(arm.expr));
}
self.diverges = matchee_diverges | all_arms_diverge;
@@ -484,8 +448,8 @@ impl<'a> InferenceContext<'a> {
self.resolver.reset_to_guard(g);
ty
}
- Expr::Continue { label } => {
- if let None = find_continuable(&mut self.breakables, label.as_ref()) {
+ &Expr::Continue { label } => {
+ if let None = find_continuable(&mut self.breakables, label) {
self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
expr: tgt_expr,
is_break: false,
@@ -494,9 +458,9 @@ impl<'a> InferenceContext<'a> {
};
self.result.standard_types.never.clone()
}
- Expr::Break { expr, label } => {
- let val_ty = if let Some(expr) = *expr {
- let opt_coerce_to = match find_breakable(&mut self.breakables, label.as_ref()) {
+ &Expr::Break { expr, label } => {
+ let val_ty = if let Some(expr) = expr {
+ let opt_coerce_to = match find_breakable(&mut self.breakables, label) {
Some(ctxt) => match &ctxt.coerce {
Some(coerce) => coerce.expected_ty(),
None => {
@@ -515,13 +479,17 @@ impl<'a> InferenceContext<'a> {
TyBuilder::unit()
};
- match find_breakable(&mut self.breakables, label.as_ref()) {
+ match find_breakable(&mut self.breakables, label) {
Some(ctxt) => match ctxt.coerce.take() {
Some(mut coerce) => {
- coerce.coerce(self, *expr, &val_ty);
+ let cause = match expr {
+ Some(expr) => CoercionCause::Expr(expr),
+ None => CoercionCause::Expr(tgt_expr),
+ };
+ coerce.coerce(self, expr, &val_ty, cause);
// Avoiding borrowck
- let ctxt = find_breakable(&mut self.breakables, label.as_ref())
+ let ctxt = find_breakable(&mut self.breakables, label)
.expect("breakable stack changed during coercion");
ctxt.may_break = true;
ctxt.coerce = Some(coerce);
@@ -538,7 +506,7 @@ impl<'a> InferenceContext<'a> {
}
self.result.standard_types.never.clone()
}
- &Expr::Return { expr } => self.infer_expr_return(expr),
+ &Expr::Return { expr } => self.infer_expr_return(tgt_expr, expr),
Expr::Yield { expr } => {
if let Some((resume_ty, yield_ty)) = self.resume_yield_tys.clone() {
if let Some(expr) = expr {
@@ -589,6 +557,9 @@ impl<'a> InferenceContext<'a> {
let field_ty = field_def.map_or(self.err_ty(), |it| {
field_types[it.local_id].clone().substitute(Interner, &substs)
});
+ // Field type might have some unknown types
+ // FIXME: we may want to emit a single type variable for all instance of type fields?
+ let field_ty = self.insert_type_vars(field_ty);
self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty));
}
if let Some(expr) = spread {
@@ -601,26 +572,18 @@ impl<'a> InferenceContext<'a> {
let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
self.resolve_associated_type(inner_ty, self.resolve_future_future_output())
}
- Expr::Try { expr } => {
- let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
- if let Some(trait_) = self.resolve_lang_trait(LangItem::Try) {
- if let Some(func) = self.db.trait_data(trait_).method_by_name(&name!(branch)) {
- let subst = TyBuilder::subst_for_def(self.db, trait_, None)
- .push(inner_ty.clone())
- .build();
- self.write_method_resolution(tgt_expr, func, subst.clone());
- }
- let try_output = self.resolve_output_on(trait_);
- self.resolve_associated_type(inner_ty, try_output)
- } else {
- self.err_ty()
- }
- }
Expr::Cast { expr, type_ref } => {
let cast_ty = self.make_ty(type_ref);
// FIXME: propagate the "castable to" expectation
- let _inner_ty = self.infer_expr_no_expect(*expr);
- // FIXME check the cast...
+ let inner_ty = self.infer_expr_no_expect(*expr);
+ match (inner_ty.kind(Interner), cast_ty.kind(Interner)) {
+ (TyKind::Ref(_, _, inner), TyKind::Raw(_, cast)) => {
+ // FIXME: record invalid cast diagnostic in case of mismatch
+ self.unify(inner, cast);
+ }
+ // FIXME check the other kinds of cast...
+ _ => (),
+ }
cast_ty
}
Expr::Ref { expr, rawness, mutability } => {
@@ -638,7 +601,7 @@ impl<'a> InferenceContext<'a> {
// FIXME: record type error - expected reference but found ptr,
// which cannot be coerced
}
- Expectation::rvalue_hint(&mut self.table, Ty::clone(exp_inner))
+ Expectation::rvalue_hint(self, Ty::clone(exp_inner))
} else {
Expectation::none()
};
@@ -656,7 +619,25 @@ impl<'a> InferenceContext<'a> {
// FIXME: Note down method resolution her
match op {
UnaryOp::Deref => {
- autoderef::deref(&mut self.table, inner_ty).unwrap_or_else(|| self.err_ty())
+ if let Some(deref_trait) = self.resolve_lang_trait(LangItem::Deref) {
+ if let Some(deref_fn) =
+ self.db.trait_data(deref_trait).method_by_name(&name![deref])
+ {
+ // FIXME: this is wrong in multiple ways, subst is empty, and we emit it even for builtin deref (note that
+ // the mutability is not wrong, and will be fixed in `self.infer_mut`).
+ self.write_method_resolution(
+ tgt_expr,
+ deref_fn,
+ Substitution::empty(Interner),
+ );
+ }
+ }
+ if let Some(derefed) = builtin_deref(&mut self.table, &inner_ty, true) {
+ self.resolve_ty_shallow(derefed)
+ } else {
+ deref_by_trait(&mut self.table, inner_ty)
+ .unwrap_or_else(|| self.err_ty())
+ }
}
UnaryOp::Neg => {
match inner_ty.kind(Interner) {
@@ -767,14 +748,16 @@ impl<'a> InferenceContext<'a> {
let canonicalized = self.canonicalize(base_ty.clone());
let receiver_adjustments = method_resolution::resolve_indexing_op(
self.db,
- self.trait_env.clone(),
+ self.table.trait_env.clone(),
canonicalized.value,
index_trait,
);
- let (self_ty, adj) = receiver_adjustments
+ let (self_ty, mut adj) = receiver_adjustments
.map_or((self.err_ty(), Vec::new()), |adj| {
adj.apply(&mut self.table, base_ty)
});
+ // mutability will be fixed up in `InferenceContext::infer_mut`;
+ adj.push(Adjustment::borrow(Mutability::Not, self_ty.clone()));
self.write_expr_adj(*base, adj);
if let Some(func) =
self.db.trait_data(index_trait).method_by_name(&name!(index))
@@ -783,7 +766,7 @@ impl<'a> InferenceContext<'a> {
.push(self_ty.clone())
.push(index_ty.clone())
.build();
- self.write_method_resolution(tgt_expr, func, substs.clone());
+ self.write_method_resolution(tgt_expr, func, substs);
}
self.resolve_associated_type_with_params(
self_ty,
@@ -834,6 +817,20 @@ impl<'a> InferenceContext<'a> {
let array_type = TyKind::Array(byte_type, len).intern(Interner);
TyKind::Ref(Mutability::Not, static_lifetime(), array_type).intern(Interner)
}
+ Literal::CString(..) => TyKind::Ref(
+ Mutability::Not,
+ static_lifetime(),
+ self.resolve_lang_item(LangItem::CStr)
+ .and_then(LangItemTarget::as_struct)
+ .map_or_else(
+ || self.err_ty(),
+ |strukt| {
+ TyKind::Adt(AdtId(strukt.into()), Substitution::empty(Interner))
+ .intern(Interner)
+ },
+ ),
+ )
+ .intern(Interner),
Literal::Char(..) => TyKind::Scalar(Scalar::Char).intern(Interner),
Literal::Int(_v, ty) => match ty {
Some(int_ty) => {
@@ -859,9 +856,15 @@ impl<'a> InferenceContext<'a> {
},
Expr::Underscore => {
// Underscore expressions may only appear in assignee expressions,
- // which are handled by `infer_assignee_expr()`, so any underscore
- // expression reaching this branch is an error.
- self.err_ty()
+ // which are handled by `infer_assignee_expr()`.
+ // Any other underscore expression is an error, we render a specialized diagnostic
+ // to let the user know what type is expected though.
+ let expected = expected.to_option(&mut self.table).unwrap_or_else(|| self.err_ty());
+ self.push_diagnostic(InferenceDiagnostic::TypedHole {
+ expr: tgt_expr,
+ expected: expected.clone(),
+ });
+ expected
}
};
// use a new type variable if we got unknown here
@@ -874,6 +877,88 @@ impl<'a> InferenceContext<'a> {
ty
}
+ fn infer_async_block(
+ &mut self,
+ tgt_expr: ExprId,
+ id: &Option<BlockId>,
+ statements: &[Statement],
+ tail: &Option<ExprId>,
+ ) -> Ty {
+ let ret_ty = self.table.new_type_var();
+ let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
+ let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
+ let prev_ret_coercion =
+ mem::replace(&mut self.return_coercion, Some(CoerceMany::new(ret_ty.clone())));
+
+ let (_, inner_ty) = self.with_breakable_ctx(BreakableKind::Border, None, None, |this| {
+ this.infer_block(tgt_expr, *id, statements, *tail, None, &Expectation::has_type(ret_ty))
+ });
+
+ self.diverges = prev_diverges;
+ self.return_ty = prev_ret_ty;
+ self.return_coercion = prev_ret_coercion;
+
+ self.lower_async_block_type_impl_trait(inner_ty, tgt_expr)
+ }
+
+ pub(crate) fn lower_async_block_type_impl_trait(
+ &mut self,
+ inner_ty: Ty,
+ tgt_expr: ExprId,
+ ) -> Ty {
+ // Use the first type parameter as the output type of future.
+ // existential type AsyncBlockImplTrait<InnerType>: Future<Output = InnerType>
+ let impl_trait_id = crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, tgt_expr);
+ let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
+ TyKind::OpaqueType(opaque_ty_id, Substitution::from1(Interner, inner_ty)).intern(Interner)
+ }
+
+ pub(crate) fn write_fn_trait_method_resolution(
+ &mut self,
+ fn_x: FnTrait,
+ derefed_callee: &Ty,
+ adjustments: &mut Vec<Adjustment>,
+ callee_ty: &Ty,
+ params: &Vec<Ty>,
+ tgt_expr: ExprId,
+ ) {
+ match fn_x {
+ FnTrait::FnOnce => (),
+ FnTrait::FnMut => {
+ if let TyKind::Ref(Mutability::Mut, _, inner) = derefed_callee.kind(Interner) {
+ if adjustments
+ .last()
+ .map(|x| matches!(x.kind, Adjust::Borrow(_)))
+ .unwrap_or(true)
+ {
+ // prefer reborrow to move
+ adjustments
+ .push(Adjustment { kind: Adjust::Deref(None), target: inner.clone() });
+ adjustments.push(Adjustment::borrow(Mutability::Mut, inner.clone()))
+ }
+ } else {
+ adjustments.push(Adjustment::borrow(Mutability::Mut, derefed_callee.clone()));
+ }
+ }
+ FnTrait::Fn => {
+ if !matches!(derefed_callee.kind(Interner), TyKind::Ref(Mutability::Not, _, _)) {
+ adjustments.push(Adjustment::borrow(Mutability::Not, derefed_callee.clone()));
+ }
+ }
+ }
+ let Some(trait_) = fn_x.get_id(self.db, self.table.trait_env.krate) else {
+ return;
+ };
+ let trait_data = self.db.trait_data(trait_);
+ if let Some(func) = trait_data.method_by_name(&fn_x.method_name()) {
+ let subst = TyBuilder::subst_for_def(self.db, trait_, None)
+ .push(callee_ty.clone())
+ .push(TyBuilder::tuple_with(params.iter().cloned()))
+ .build();
+ self.write_method_resolution(tgt_expr, func, subst.clone());
+ }
+ }
+
fn infer_expr_array(
&mut self,
array: &Array,
@@ -892,10 +977,10 @@ impl<'a> InferenceContext<'a> {
(elem_ty, consteval::usize_const(self.db, Some(0), krate))
}
Array::ElementList { elements, .. } => {
- let mut coerce = CoerceMany::new(elem_ty.clone());
+ let mut coerce = CoerceMany::new(elem_ty);
for &expr in elements.iter() {
let cur_elem_ty = self.infer_expr_inner(expr, &expected);
- coerce.coerce(self, Some(expr), &cur_elem_ty);
+ coerce.coerce(self, Some(expr), &cur_elem_ty, CoercionCause::Expr(expr));
}
(
coerce.complete(self),
@@ -904,12 +989,13 @@ impl<'a> InferenceContext<'a> {
}
&Array::Repeat { initializer, repeat } => {
self.infer_expr_coerce(initializer, &Expectation::has_type(elem_ty.clone()));
- self.infer_expr(
- repeat,
- &Expectation::HasType(
- TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner),
- ),
- );
+ let usize = TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner);
+ match self.body[repeat] {
+ Expr::Underscore => {
+ self.write_expr_ty(repeat, usize);
+ }
+ _ => _ = self.infer_expr(repeat, &Expectation::HasType(usize)),
+ }
(
elem_ty,
@@ -928,7 +1014,8 @@ impl<'a> InferenceContext<'a> {
)
}
};
-
+ // Try to evaluate unevaluated constant, and insert variable if is not possible.
+ let len = self.table.insert_const_vars_shallow(len);
TyKind::Array(elem_ty, len).intern(Interner)
}
@@ -940,18 +1027,18 @@ impl<'a> InferenceContext<'a> {
.expected_ty();
let return_expr_ty = self.infer_expr_inner(expr, &Expectation::HasType(ret_ty));
let mut coerce_many = self.return_coercion.take().unwrap();
- coerce_many.coerce(self, Some(expr), &return_expr_ty);
+ coerce_many.coerce(self, Some(expr), &return_expr_ty, CoercionCause::Expr(expr));
self.return_coercion = Some(coerce_many);
}
- fn infer_expr_return(&mut self, expr: Option<ExprId>) -> Ty {
+ fn infer_expr_return(&mut self, ret: ExprId, expr: Option<ExprId>) -> Ty {
match self.return_coercion {
Some(_) => {
if let Some(expr) = expr {
self.infer_return(expr);
} else {
let mut coerce = self.return_coercion.take().unwrap();
- coerce.coerce_forced_unit(self);
+ coerce.coerce_forced_unit(self, CoercionCause::Expr(ret));
self.return_coercion = Some(coerce);
}
}
@@ -976,7 +1063,7 @@ impl<'a> InferenceContext<'a> {
.filter(|(e_adt, _)| e_adt == &box_id)
.map(|(_, subts)| {
let g = subts.at(Interner, 0);
- Expectation::rvalue_hint(table, Ty::clone(g.assert_ty_ref(Interner)))
+ Expectation::rvalue_hint(self, Ty::clone(g.assert_ty_ref(Interner)))
})
.unwrap_or_else(Expectation::none);
@@ -1185,6 +1272,7 @@ impl<'a> InferenceContext<'a> {
fn infer_block(
&mut self,
expr: ExprId,
+ block_id: Option<BlockId>,
statements: &[Statement],
tail: Option<ExprId>,
label: Option<LabelId>,
@@ -1192,9 +1280,14 @@ impl<'a> InferenceContext<'a> {
) -> Ty {
let coerce_ty = expected.coercion_target_type(&mut self.table);
let g = self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr);
+ let prev_env = block_id.map(|block_id| {
+ let prev_env = self.table.trait_env.clone();
+ Arc::make_mut(&mut self.table.trait_env).block = Some(block_id);
+ prev_env
+ });
let (break_ty, ty) =
- self.with_breakable_ctx(BreakableKind::Block, Some(coerce_ty.clone()), label, |this| {
+ self.with_breakable_ctx(BreakableKind::Block, Some(coerce_ty), label, |this| {
for stmt in statements {
match stmt {
Statement::Let { pat, type_ref, initializer, else_branch } => {
@@ -1280,6 +1373,9 @@ impl<'a> InferenceContext<'a> {
}
});
self.resolver.reset_to_guard(g);
+ if let Some(prev_env) = prev_env {
+ self.table.trait_env = prev_env;
+ }
break_ty.unwrap_or(ty)
}
@@ -1378,7 +1474,7 @@ impl<'a> InferenceContext<'a> {
method_resolution::lookup_method(
self.db,
&canonicalized_receiver.value,
- self.trait_env.clone(),
+ self.table.trait_env.clone(),
self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
VisibleFromModule::Filter(self.resolver.module()),
name,
@@ -1411,7 +1507,7 @@ impl<'a> InferenceContext<'a> {
let resolved = method_resolution::lookup_method(
self.db,
&canonicalized_receiver.value,
- self.trait_env.clone(),
+ self.table.trait_env.clone(),
self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
VisibleFromModule::Filter(self.resolver.module()),
method_name,
@@ -1562,7 +1658,7 @@ impl<'a> InferenceContext<'a> {
// the parameter to coerce to the expected type (for example in
// `coerce_unsize_expected_type_4`).
let param_ty = self.normalize_associated_types_in(param_ty);
- let expected = Expectation::rvalue_hint(&mut self.table, expected_ty);
+ let expected = Expectation::rvalue_hint(self, expected_ty);
// infer with the expected type we have...
let ty = self.infer_expr_inner(arg, &expected);
@@ -1575,9 +1671,10 @@ impl<'a> InferenceContext<'a> {
} else {
param_ty
};
- if !coercion_target.is_unknown()
- && self.coerce(Some(arg), &ty, &coercion_target).is_err()
- {
+ // The function signature may contain some unknown types, so we need to insert
+ // type vars here to avoid type mismatch false positive.
+ let coercion_target = self.insert_type_vars(coercion_target);
+ if self.coerce(Some(arg), &ty, &coercion_target).is_err() {
self.result.type_mismatches.insert(
arg.into(),
TypeMismatch { expected: coercion_target, actual: ty.clone() },
@@ -1868,7 +1965,6 @@ impl<'a> InferenceContext<'a> {
cb: impl FnOnce(&mut Self) -> T,
) -> (Option<Ty>, T) {
self.breakables.push({
- let label = label.map(|label| self.body[label].name.clone());
BreakableContext { kind, may_break: false, coerce: ty.map(CoerceMany::new), label }
});
let res = cb(self);