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.rs | 153 |
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, + ¶ms, + 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); |