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.rs47
1 files changed, 28 insertions, 19 deletions
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index e169cbef49..6f20f0dc89 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -25,7 +25,9 @@ use syntax::ast::RangeOp;
use crate::{
autoderef::{self, Autoderef},
consteval,
- infer::{coerce::CoerceMany, find_continuable, BreakableKind},
+ infer::{
+ coerce::CoerceMany, find_continuable, pat::contains_explicit_ref_binding, BreakableKind,
+ },
lower::{
const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
},
@@ -39,8 +41,8 @@ use crate::{
};
use super::{
- coerce::auto_deref_adjust_steps, find_breakable, BindingMode, BreakableContext, Diverges,
- Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch,
+ coerce::auto_deref_adjust_steps, find_breakable, BreakableContext, Diverges, Expectation,
+ InferenceContext, InferenceDiagnostic, TypeMismatch,
};
impl<'a> InferenceContext<'a> {
@@ -111,7 +113,7 @@ impl<'a> InferenceContext<'a> {
}
&Expr::Let { pat, expr } => {
let input_ty = self.infer_expr(expr, &Expectation::none());
- self.infer_pat(pat, &input_ty, BindingMode::default());
+ self.infer_top_pat(pat, &input_ty);
self.result.standard_types.bool_.clone()
}
Expr::Block { statements, tail, label, id: _ } => {
@@ -223,7 +225,7 @@ impl<'a> InferenceContext<'a> {
let pat_ty =
self.resolve_associated_type(into_iter_ty, self.resolve_iterator_item());
- self.infer_pat(pat, &pat_ty, BindingMode::default());
+ self.infer_top_pat(pat, &pat_ty);
self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| {
this.infer_expr(body, &Expectation::HasType(TyBuilder::unit()));
});
@@ -298,7 +300,7 @@ impl<'a> InferenceContext<'a> {
// Now go through the argument patterns
for (arg_pat, arg_ty) in args.iter().zip(sig_tys) {
- self.infer_pat(*arg_pat, &arg_ty, BindingMode::default());
+ self.infer_top_pat(*arg_pat, &arg_ty);
}
let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
@@ -395,7 +397,8 @@ impl<'a> InferenceContext<'a> {
for arm in arms.iter() {
self.diverges = Diverges::Maybe;
- let _pat_ty = self.infer_pat(arm.pat, &input_ty, BindingMode::default());
+ let input_ty = self.resolve_ty_shallow(&input_ty);
+ self.infer_top_pat(arm.pat, &input_ty);
if let Some(guard_expr) = arm.guard {
self.infer_expr(
guard_expr,
@@ -1142,27 +1145,33 @@ impl<'a> InferenceContext<'a> {
let decl_ty = type_ref
.as_ref()
.map(|tr| self.make_ty(tr))
- .unwrap_or_else(|| self.err_ty());
-
- // Always use the declared type when specified
- let mut ty = decl_ty.clone();
+ .unwrap_or_else(|| self.table.new_type_var());
- if let Some(expr) = initializer {
- let actual_ty =
- self.infer_expr_coerce(*expr, &Expectation::has_type(decl_ty.clone()));
- if decl_ty.is_unknown() {
- ty = actual_ty;
+ let ty = if let Some(expr) = initializer {
+ let ty = if contains_explicit_ref_binding(&self.body, *pat) {
+ self.infer_expr(*expr, &Expectation::has_type(decl_ty.clone()))
+ } else {
+ self.infer_expr_coerce(*expr, &Expectation::has_type(decl_ty.clone()))
+ };
+ if type_ref.is_some() {
+ decl_ty
+ } else {
+ ty
}
- }
+ } else {
+ decl_ty
+ };
+
+ self.infer_top_pat(*pat, &ty);
if let Some(expr) = else_branch {
+ let previous_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
self.infer_expr_coerce(
*expr,
&Expectation::HasType(self.result.standard_types.never.clone()),
);
+ self.diverges = previous_diverges;
}
-
- self.infer_pat(*pat, &ty, BindingMode::default());
}
Statement::Expr { expr, .. } => {
self.infer_expr(*expr, &Expectation::none());