mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 05:45:12 +00:00
Implement CoerceMany
This commit is contained in:
parent
9779526d8f
commit
64a1b26b8d
3 changed files with 120 additions and 89 deletions
|
@ -16,6 +16,7 @@ use syntax::ast::RangeOp;
|
|||
|
||||
use crate::{
|
||||
autoderef, consteval,
|
||||
infer::coerce::CoerceMany,
|
||||
lower::lower_to_chalk_mutability,
|
||||
mapping::from_chalk,
|
||||
method_resolution, op,
|
||||
|
@ -56,11 +57,8 @@ impl<'a> InferenceContext<'a> {
|
|||
pub(super) fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty {
|
||||
let ty = self.infer_expr_inner(expr, expected);
|
||||
let ty = if let Some(target) = expected.only_has_type(&mut self.table) {
|
||||
match self.coerce(&ty, &target) {
|
||||
Ok(res) => {
|
||||
self.result.expr_adjustments.insert(expr, res.value.0);
|
||||
target
|
||||
}
|
||||
match self.coerce(Some(expr), &ty, &target) {
|
||||
Ok(res) => res.value,
|
||||
Err(_) => {
|
||||
self.result
|
||||
.type_mismatches
|
||||
|
@ -128,31 +126,32 @@ impl<'a> InferenceContext<'a> {
|
|||
let body = Arc::clone(&self.body); // avoid borrow checker problem
|
||||
let ty = match &body[tgt_expr] {
|
||||
Expr::Missing => self.err_ty(),
|
||||
Expr::If { condition, then_branch, else_branch } => {
|
||||
&Expr::If { condition, then_branch, else_branch } => {
|
||||
// if let is desugared to match, so this is always simple if
|
||||
self.infer_expr(
|
||||
*condition,
|
||||
condition,
|
||||
&Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(&Interner)),
|
||||
);
|
||||
|
||||
let condition_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
|
||||
let mut both_arms_diverge = Diverges::Always;
|
||||
|
||||
let mut result_ty = self.table.new_type_var();
|
||||
let then_ty = self.infer_expr_inner(*then_branch, expected);
|
||||
let result_ty = self.table.new_type_var();
|
||||
let then_ty = self.infer_expr_inner(then_branch, expected);
|
||||
both_arms_diverge &= mem::replace(&mut self.diverges, Diverges::Maybe);
|
||||
result_ty = self.coerce_merge_branch(Some(*then_branch), &result_ty, &then_ty);
|
||||
let mut coerce = CoerceMany::new(result_ty);
|
||||
coerce.coerce(self, Some(then_branch), &then_ty);
|
||||
let else_ty = match else_branch {
|
||||
Some(else_branch) => self.infer_expr_inner(*else_branch, expected),
|
||||
Some(else_branch) => self.infer_expr_inner(else_branch, expected),
|
||||
None => TyBuilder::unit(),
|
||||
};
|
||||
both_arms_diverge &= self.diverges;
|
||||
// FIXME: create a synthetic `else {}` so we have something to refer to here instead of None?
|
||||
result_ty = self.coerce_merge_branch(*else_branch, &result_ty, &else_ty);
|
||||
coerce.coerce(self, else_branch, &else_ty);
|
||||
|
||||
self.diverges = condition_diverges | both_arms_diverge;
|
||||
|
||||
result_ty
|
||||
coerce.complete()
|
||||
}
|
||||
Expr::Block { statements, tail, label, id: _ } => {
|
||||
let old_resolver = mem::replace(
|
||||
|
@ -193,7 +192,7 @@ impl<'a> InferenceContext<'a> {
|
|||
}
|
||||
Expr::Async { body } => {
|
||||
// Use the first type parameter as the output type of future.
|
||||
// existenail type AsyncBlockImplTrait<InnerType>: Future<Output = InnerType>
|
||||
// existential type AsyncBlockImplTrait<InnerType>: Future<Output = InnerType>
|
||||
let inner_ty = self.infer_expr(*body, &Expectation::none());
|
||||
let impl_trait_id = crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, *body);
|
||||
let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
|
||||
|
@ -223,6 +222,7 @@ impl<'a> InferenceContext<'a> {
|
|||
self.breakables.push(BreakableContext {
|
||||
may_break: false,
|
||||
break_ty: self.err_ty(),
|
||||
|
||||
label: label.map(|label| self.body[label].name.clone()),
|
||||
});
|
||||
// while let is desugared to a match loop, so this is always simple while
|
||||
|
@ -344,7 +344,7 @@ impl<'a> InferenceContext<'a> {
|
|||
|
||||
let expected = expected.adjust_for_branches(&mut self.table);
|
||||
|
||||
let mut result_ty = if arms.is_empty() {
|
||||
let result_ty = if arms.is_empty() {
|
||||
TyKind::Never.intern(&Interner)
|
||||
} else {
|
||||
match &expected {
|
||||
|
@ -352,6 +352,7 @@ impl<'a> InferenceContext<'a> {
|
|||
_ => self.table.new_type_var(),
|
||||
}
|
||||
};
|
||||
let mut coerce = CoerceMany::new(result_ty);
|
||||
|
||||
let matchee_diverges = self.diverges;
|
||||
let mut all_arms_diverge = Diverges::Always;
|
||||
|
@ -368,12 +369,12 @@ impl<'a> InferenceContext<'a> {
|
|||
|
||||
let arm_ty = self.infer_expr_inner(arm.expr, &expected);
|
||||
all_arms_diverge &= self.diverges;
|
||||
result_ty = self.coerce_merge_branch(Some(arm.expr), &result_ty, &arm_ty);
|
||||
coerce.coerce(self, Some(arm.expr), &arm_ty);
|
||||
}
|
||||
|
||||
self.diverges = matchee_diverges | all_arms_diverge;
|
||||
|
||||
result_ty
|
||||
coerce.complete()
|
||||
}
|
||||
Expr::Path(p) => {
|
||||
// FIXME this could be more efficient...
|
||||
|
@ -382,6 +383,7 @@ impl<'a> InferenceContext<'a> {
|
|||
}
|
||||
Expr::Continue { .. } => TyKind::Never.intern(&Interner),
|
||||
Expr::Break { expr, label } => {
|
||||
let expr = *expr;
|
||||
let last_ty =
|
||||
if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) {
|
||||
ctxt.break_ty.clone()
|
||||
|
@ -390,13 +392,13 @@ impl<'a> InferenceContext<'a> {
|
|||
};
|
||||
|
||||
let val_ty = if let Some(expr) = expr {
|
||||
self.infer_expr(*expr, &Expectation::none())
|
||||
self.infer_expr(expr, &Expectation::none())
|
||||
} else {
|
||||
TyBuilder::unit()
|
||||
};
|
||||
|
||||
// FIXME: create a synthetic `()` during lowering so we have something to refer to here?
|
||||
let merged_type = self.coerce_merge_branch(*expr, &last_ty, &val_ty);
|
||||
let merged_type = CoerceMany::once(self, last_ty, expr, &val_ty);
|
||||
|
||||
if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) {
|
||||
ctxt.break_ty = merged_type;
|
||||
|
@ -413,9 +415,7 @@ impl<'a> InferenceContext<'a> {
|
|||
self.infer_expr_coerce(*expr, &Expectation::has_type(self.return_ty.clone()));
|
||||
} else {
|
||||
let unit = TyBuilder::unit();
|
||||
if let Ok(ok) = self.coerce(&unit, &self.return_ty.clone()) {
|
||||
self.write_expr_adj(tgt_expr, ok.value.0);
|
||||
}
|
||||
let _ = self.coerce(Some(tgt_expr), &unit, &self.return_ty.clone());
|
||||
}
|
||||
TyKind::Never.intern(&Interner)
|
||||
}
|
||||
|
@ -744,39 +744,37 @@ impl<'a> InferenceContext<'a> {
|
|||
TyKind::Tuple(tys.len(), Substitution::from_iter(&Interner, tys)).intern(&Interner)
|
||||
}
|
||||
Expr::Array(array) => {
|
||||
let mut elem_ty =
|
||||
let elem_ty =
|
||||
match expected.to_option(&mut self.table).as_ref().map(|t| t.kind(&Interner)) {
|
||||
Some(TyKind::Array(st, _) | TyKind::Slice(st)) => st.clone(),
|
||||
_ => self.table.new_type_var(),
|
||||
};
|
||||
let mut coerce = CoerceMany::new(elem_ty.clone());
|
||||
|
||||
let expected = Expectation::has_type(elem_ty.clone());
|
||||
let len = match array {
|
||||
Array::ElementList(items) => {
|
||||
for expr in items.iter() {
|
||||
let cur_elem_ty = self.infer_expr_inner(*expr, &expected);
|
||||
elem_ty = self.coerce_merge_branch(Some(*expr), &elem_ty, &cur_elem_ty);
|
||||
for &expr in items.iter() {
|
||||
let cur_elem_ty = self.infer_expr_inner(expr, &expected);
|
||||
coerce.coerce(self, Some(expr), &cur_elem_ty);
|
||||
}
|
||||
Some(items.len() as u64)
|
||||
}
|
||||
Array::Repeat { initializer, repeat } => {
|
||||
self.infer_expr_coerce(
|
||||
*initializer,
|
||||
&Expectation::has_type(elem_ty.clone()),
|
||||
);
|
||||
&Array::Repeat { initializer, repeat } => {
|
||||
self.infer_expr_coerce(initializer, &Expectation::has_type(elem_ty));
|
||||
self.infer_expr(
|
||||
*repeat,
|
||||
repeat,
|
||||
&Expectation::has_type(
|
||||
TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner),
|
||||
),
|
||||
);
|
||||
|
||||
let repeat_expr = &self.body.exprs[*repeat];
|
||||
let repeat_expr = &self.body.exprs[repeat];
|
||||
consteval::eval_usize(repeat_expr)
|
||||
}
|
||||
};
|
||||
|
||||
TyKind::Array(elem_ty, consteval::usize_const(len)).intern(&Interner)
|
||||
TyKind::Array(coerce.complete(), consteval::usize_const(len)).intern(&Interner)
|
||||
}
|
||||
Expr::Literal(lit) => match lit {
|
||||
Literal::Bool(..) => TyKind::Scalar(Scalar::Bool).intern(&Interner),
|
||||
|
@ -872,9 +870,7 @@ impl<'a> InferenceContext<'a> {
|
|||
self.table.new_maybe_never_var()
|
||||
} else {
|
||||
if let Some(t) = expected.only_has_type(&mut self.table) {
|
||||
if let Ok(ok) = self.coerce(&TyBuilder::unit(), &t) {
|
||||
self.write_expr_adj(expr, ok.value.0);
|
||||
}
|
||||
let _ = self.coerce(Some(expr), &TyBuilder::unit(), &t);
|
||||
}
|
||||
TyBuilder::unit()
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue