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.rs153
1 files changed, 93 insertions, 60 deletions
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index 035f61fc18..64f37c761e 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -10,10 +10,10 @@ use chalk_ir::{
cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyKind, TyVariableKind,
};
use hir_def::{
- expr::{
+ generics::TypeOrConstParamData,
+ hir::{
ArithOp, Array, BinaryOp, ClosureKind, Expr, ExprId, LabelId, Literal, Statement, UnaryOp,
},
- generics::TypeOrConstParamData,
lang_item::LangItem,
path::{GenericArg, GenericArgs},
BlockId, ConstParamId, FieldId, ItemContainerId, Lookup,
@@ -86,10 +86,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 {
@@ -99,13 +99,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
}
}
@@ -212,7 +221,7 @@ impl<'a> InferenceContext<'a> {
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);
@@ -247,7 +256,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() {
@@ -267,7 +276,7 @@ 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();
@@ -276,8 +285,11 @@ impl<'a> InferenceContext<'a> {
Substitution::from1(Interner, 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_dependecies.entry(c).or_default().push(closure_id);
+ }
+ (Some(closure_id), closure_ty, None)
}
};
@@ -293,6 +305,7 @@ 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)));
@@ -306,6 +319,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
@@ -331,43 +345,28 @@ impl<'a> InferenceContext<'a> {
let (param_tys, ret_ty) = match res {
Some((func, params, ret_ty)) => {
let mut adjustments = auto_deref_adjust_steps(&derefs);
- if let Some(fn_x) = func {
- match fn_x {
- FnTrait::FnOnce => (),
- FnTrait::FnMut => {
- if !matches!(
- derefed_callee.kind(Interner),
- TyKind::Ref(Mutability::Mut, _, _)
- ) {
- 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 trait_ = fn_x
- .get_id(self.db, self.table.trait_env.krate)
- .expect("We just used it");
- 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)
+ if let TyKind::Closure(c, _) =
+ self.table.resolve_completely(callee_ty.clone()).kind(Interner)
+ {
+ if let Some(par) = self.current_closure {
+ self.closure_dependecies.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)
@@ -459,8 +458,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,
@@ -469,9 +468,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 => {
@@ -490,13 +489,13 @@ 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);
+ coerce.coerce(self, expr, &val_ty);
// 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);
@@ -897,6 +896,41 @@ impl<'a> InferenceContext<'a> {
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 !matches!(derefed_callee.kind(Interner), TyKind::Ref(Mutability::Mut, _, _)) {
+ 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,
@@ -1900,7 +1934,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);