mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-05 19:58:32 +00:00
Implement CoerceMany
This commit is contained in:
parent
9779526d8f
commit
64a1b26b8d
@ -25,9 +25,8 @@ impl InferenceContext<'_> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Deduction from where-clauses in scope, as well as fn-pointer coercion are handled here.
|
// Deduction from where-clauses in scope, as well as fn-pointer coercion are handled here.
|
||||||
if let Ok(res) = self.coerce(closure_ty, &expected_ty) {
|
let _ = self.coerce(Some(closure_expr), closure_ty, &expected_ty);
|
||||||
self.write_expr_adj(closure_expr, res.value.0);
|
|
||||||
}
|
|
||||||
// Deduction based on the expected `dyn Fn` is done separately.
|
// Deduction based on the expected `dyn Fn` is done separately.
|
||||||
if let TyKind::Dyn(dyn_ty) = expected_ty.kind(&Interner) {
|
if let TyKind::Dyn(dyn_ty) = expected_ty.kind(&Interner) {
|
||||||
if let Some(sig) = self.deduce_sig_from_dyn_ty(dyn_ty) {
|
if let Some(sig) = self.deduce_sig_from_dyn_ty(dyn_ty) {
|
||||||
|
@ -10,7 +10,7 @@ use hir_def::{expr::ExprId, lang_item::LangItemTarget};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
autoderef,
|
autoderef,
|
||||||
infer::{Adjust, Adjustment, AutoBorrow, PointerCast, TypeMismatch},
|
infer::{Adjust, Adjustment, AutoBorrow, InferResult, PointerCast, TypeMismatch},
|
||||||
static_lifetime, Canonical, DomainGoal, FnPointer, FnSig, Interner, Solution, Substitution, Ty,
|
static_lifetime, Canonical, DomainGoal, FnPointer, FnSig, Interner, Solution, Substitution, Ty,
|
||||||
TyBuilder, TyExt, TyKind,
|
TyBuilder, TyExt, TyKind,
|
||||||
};
|
};
|
||||||
@ -36,23 +36,25 @@ fn success(
|
|||||||
) -> CoerceResult {
|
) -> CoerceResult {
|
||||||
Ok(InferOk { goals, value: (adj, target) })
|
Ok(InferOk { goals, value: (adj, target) })
|
||||||
}
|
}
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub(super) struct CoerceMany {
|
||||||
|
expected_ty: Ty,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> InferenceContext<'a> {
|
impl CoerceMany {
|
||||||
/// Unify two types, but may coerce the first one to the second one
|
pub(super) fn new(expected: Ty) -> Self {
|
||||||
/// using "implicit coercion rules" if needed.
|
CoerceMany { expected_ty: expected }
|
||||||
pub(super) fn coerce(&mut self, from_ty: &Ty, to_ty: &Ty) -> CoerceResult {
|
|
||||||
let from_ty = self.resolve_ty_shallow(from_ty);
|
|
||||||
let to_ty = self.resolve_ty_shallow(to_ty);
|
|
||||||
match self.coerce_inner(from_ty, &to_ty) {
|
|
||||||
Ok(InferOk { value, goals }) => {
|
|
||||||
self.table.register_infer_ok(InferOk { value: (), goals });
|
|
||||||
Ok(InferOk { value, goals: Vec::new() })
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
// FIXME deal with error
|
|
||||||
Err(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn once(
|
||||||
|
ctx: &mut InferenceContext<'_>,
|
||||||
|
expected: Ty,
|
||||||
|
expr: Option<ExprId>,
|
||||||
|
expr_ty: &Ty,
|
||||||
|
) -> Ty {
|
||||||
|
let mut this = CoerceMany::new(expected);
|
||||||
|
this.coerce(ctx, expr, expr_ty);
|
||||||
|
this.complete()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Merge two types from different branches, with possible coercion.
|
/// Merge two types from different branches, with possible coercion.
|
||||||
@ -62,51 +64,88 @@ impl<'a> InferenceContext<'a> {
|
|||||||
/// coerce both to function pointers;
|
/// coerce both to function pointers;
|
||||||
/// - if we were concerned with lifetime subtyping, we'd need to look for a
|
/// - if we were concerned with lifetime subtyping, we'd need to look for a
|
||||||
/// least upper bound.
|
/// least upper bound.
|
||||||
pub(super) fn coerce_merge_branch(&mut self, id: Option<ExprId>, ty1: &Ty, ty2: &Ty) -> Ty {
|
pub(super) fn coerce(
|
||||||
// TODO
|
&mut self,
|
||||||
let ty1 = self.resolve_ty_shallow(ty1);
|
ctx: &mut InferenceContext<'_>,
|
||||||
let ty2 = self.resolve_ty_shallow(ty2);
|
expr: Option<ExprId>,
|
||||||
|
expr_ty: &Ty,
|
||||||
|
) {
|
||||||
|
let expr_ty = ctx.resolve_ty_shallow(expr_ty);
|
||||||
|
self.expected_ty = ctx.resolve_ty_shallow(&self.expected_ty);
|
||||||
|
|
||||||
// Special case: two function types. Try to coerce both to
|
// Special case: two function types. Try to coerce both to
|
||||||
// pointers to have a chance at getting a match. See
|
// pointers to have a chance at getting a match. See
|
||||||
// https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916
|
// https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916
|
||||||
let sig = match (ty1.kind(&Interner), ty2.kind(&Interner)) {
|
let sig = match (self.expected_ty.kind(&Interner), expr_ty.kind(&Interner)) {
|
||||||
(TyKind::FnDef(..) | TyKind::Closure(..), TyKind::FnDef(..) | TyKind::Closure(..)) => {
|
(TyKind::FnDef(..) | TyKind::Closure(..), TyKind::FnDef(..) | TyKind::Closure(..)) => {
|
||||||
// FIXME: we're ignoring safety here. To be more correct, if we have one FnDef and one Closure,
|
// FIXME: we're ignoring safety here. To be more correct, if we have one FnDef and one Closure,
|
||||||
// we should be coercing the closure to a fn pointer of the safety of the FnDef
|
// we should be coercing the closure to a fn pointer of the safety of the FnDef
|
||||||
cov_mark::hit!(coerce_fn_reification);
|
cov_mark::hit!(coerce_fn_reification);
|
||||||
let sig = ty1.callable_sig(self.db).expect("FnDef without callable sig");
|
let sig =
|
||||||
|
self.expected_ty.callable_sig(ctx.db).expect("FnDef without callable sig");
|
||||||
Some(sig)
|
Some(sig)
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
if let Some(sig) = sig {
|
if let Some(sig) = sig {
|
||||||
let target_ty = TyKind::Function(sig.to_fn_ptr()).intern(&Interner);
|
let target_ty = TyKind::Function(sig.to_fn_ptr()).intern(&Interner);
|
||||||
let result1 = self.coerce_inner(ty1.clone(), &target_ty);
|
let result1 = ctx.coerce_inner(self.expected_ty.clone(), &target_ty);
|
||||||
let result2 = self.coerce_inner(ty2.clone(), &target_ty);
|
let result2 = ctx.coerce_inner(expr_ty.clone(), &target_ty);
|
||||||
if let (Ok(result1), Ok(result2)) = (result1, result2) {
|
if let (Ok(result1), Ok(result2)) = (result1, result2) {
|
||||||
self.table.register_infer_ok(result1);
|
ctx.table.register_infer_ok(result1);
|
||||||
self.table.register_infer_ok(result2);
|
ctx.table.register_infer_ok(result2);
|
||||||
return target_ty;
|
return self.expected_ty = target_ty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// It might not seem like it, but order is important here: ty1 is our
|
// It might not seem like it, but order is important here: If the expected
|
||||||
// "previous" type, ty2 is the "new" one being added. If the previous
|
|
||||||
// type is a type variable and the new one is `!`, trying it the other
|
// type is a type variable and the new one is `!`, trying it the other
|
||||||
// way around first would mean we make the type variable `!`, instead of
|
// way around first would mean we make the type variable `!`, instead of
|
||||||
// just marking it as possibly diverging.
|
// just marking it as possibly diverging.
|
||||||
if self.coerce(&ty2, &ty1).is_ok() {
|
if ctx.coerce(expr, &expr_ty, &self.expected_ty).is_ok() {
|
||||||
ty1
|
/* self.expected_ty is already correct */
|
||||||
} else if self.coerce(&ty1, &ty2).is_ok() {
|
} else if ctx.coerce(expr, &self.expected_ty, &expr_ty).is_ok() {
|
||||||
ty2
|
self.expected_ty = expr_ty;
|
||||||
} else {
|
} else {
|
||||||
if let Some(id) = id {
|
if let Some(id) = expr {
|
||||||
self.result
|
ctx.result.type_mismatches.insert(
|
||||||
.type_mismatches
|
id.into(),
|
||||||
.insert(id.into(), TypeMismatch { expected: ty1.clone(), actual: ty2 });
|
TypeMismatch { expected: self.expected_ty.clone(), actual: expr_ty },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
cov_mark::hit!(coerce_merge_fail_fallback);
|
cov_mark::hit!(coerce_merge_fail_fallback);
|
||||||
ty1
|
/* self.expected_ty is already correct */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn complete(self) -> Ty {
|
||||||
|
self.expected_ty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> InferenceContext<'a> {
|
||||||
|
/// Unify two types, but may coerce the first one to the second one
|
||||||
|
/// using "implicit coercion rules" if needed.
|
||||||
|
pub(super) fn coerce(
|
||||||
|
&mut self,
|
||||||
|
expr: Option<ExprId>,
|
||||||
|
from_ty: &Ty,
|
||||||
|
to_ty: &Ty,
|
||||||
|
) -> InferResult<Ty> {
|
||||||
|
let from_ty = self.resolve_ty_shallow(from_ty);
|
||||||
|
let to_ty = self.resolve_ty_shallow(to_ty);
|
||||||
|
match self.coerce_inner(from_ty, &to_ty) {
|
||||||
|
Ok(InferOk { value: (adjustments, ty), goals }) => {
|
||||||
|
if let Some(expr) = expr {
|
||||||
|
self.write_expr_adj(expr, adjustments);
|
||||||
|
}
|
||||||
|
self.table.register_infer_ok(InferOk { value: (), goals });
|
||||||
|
Ok(InferOk { value: ty, goals: Vec::new() })
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
// FIXME deal with error
|
||||||
|
Err(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +228,6 @@ impl<'a> InferenceContext<'a> {
|
|||||||
|
|
||||||
// Check that the types which they point at are compatible.
|
// Check that the types which they point at are compatible.
|
||||||
let from_raw = TyKind::Raw(to_mt, from_inner.clone()).intern(&Interner);
|
let from_raw = TyKind::Raw(to_mt, from_inner.clone()).intern(&Interner);
|
||||||
// self.table.try_unify(&from_raw, to_ty);
|
|
||||||
|
|
||||||
// Although references and unsafe ptrs have the same
|
// Although references and unsafe ptrs have the same
|
||||||
// representation, we still register an Adjust::DerefRef so that
|
// representation, we still register an Adjust::DerefRef so that
|
||||||
@ -518,15 +556,13 @@ impl<'a> InferenceContext<'a> {
|
|||||||
// FIXME: should we accept ambiguous results here?
|
// FIXME: should we accept ambiguous results here?
|
||||||
_ => return Err(TypeError),
|
_ => return Err(TypeError),
|
||||||
};
|
};
|
||||||
// TODO: this is probably wrong?
|
let unsize =
|
||||||
let coerce_target = self.table.new_type_var();
|
Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), target: to_ty.clone() };
|
||||||
self.unify_and(&coerce_target, to_ty, |target| {
|
let adjustments = match reborrow {
|
||||||
let unsize = Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), target };
|
|
||||||
match reborrow {
|
|
||||||
None => vec![unsize],
|
None => vec![unsize],
|
||||||
Some((ref deref, ref autoref)) => vec![deref.clone(), autoref.clone(), unsize],
|
Some((deref, autoref)) => vec![deref, autoref, unsize],
|
||||||
}
|
};
|
||||||
})
|
success(adjustments, to_ty.clone(), vec![])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ use syntax::ast::RangeOp;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
autoderef, consteval,
|
autoderef, consteval,
|
||||||
|
infer::coerce::CoerceMany,
|
||||||
lower::lower_to_chalk_mutability,
|
lower::lower_to_chalk_mutability,
|
||||||
mapping::from_chalk,
|
mapping::from_chalk,
|
||||||
method_resolution, op,
|
method_resolution, op,
|
||||||
@ -56,11 +57,8 @@ impl<'a> InferenceContext<'a> {
|
|||||||
pub(super) fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty {
|
pub(super) fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty {
|
||||||
let ty = self.infer_expr_inner(expr, expected);
|
let ty = self.infer_expr_inner(expr, expected);
|
||||||
let ty = if let Some(target) = expected.only_has_type(&mut self.table) {
|
let ty = if let Some(target) = expected.only_has_type(&mut self.table) {
|
||||||
match self.coerce(&ty, &target) {
|
match self.coerce(Some(expr), &ty, &target) {
|
||||||
Ok(res) => {
|
Ok(res) => res.value,
|
||||||
self.result.expr_adjustments.insert(expr, res.value.0);
|
|
||||||
target
|
|
||||||
}
|
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
self.result
|
self.result
|
||||||
.type_mismatches
|
.type_mismatches
|
||||||
@ -128,31 +126,32 @@ impl<'a> InferenceContext<'a> {
|
|||||||
let body = Arc::clone(&self.body); // avoid borrow checker problem
|
let body = Arc::clone(&self.body); // avoid borrow checker problem
|
||||||
let ty = match &body[tgt_expr] {
|
let ty = match &body[tgt_expr] {
|
||||||
Expr::Missing => self.err_ty(),
|
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
|
// if let is desugared to match, so this is always simple if
|
||||||
self.infer_expr(
|
self.infer_expr(
|
||||||
*condition,
|
condition,
|
||||||
&Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(&Interner)),
|
&Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(&Interner)),
|
||||||
);
|
);
|
||||||
|
|
||||||
let condition_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
|
let condition_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
|
||||||
let mut both_arms_diverge = Diverges::Always;
|
let mut both_arms_diverge = Diverges::Always;
|
||||||
|
|
||||||
let mut result_ty = self.table.new_type_var();
|
let result_ty = self.table.new_type_var();
|
||||||
let then_ty = self.infer_expr_inner(*then_branch, expected);
|
let then_ty = self.infer_expr_inner(then_branch, expected);
|
||||||
both_arms_diverge &= mem::replace(&mut self.diverges, Diverges::Maybe);
|
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 {
|
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(),
|
None => TyBuilder::unit(),
|
||||||
};
|
};
|
||||||
both_arms_diverge &= self.diverges;
|
both_arms_diverge &= self.diverges;
|
||||||
// FIXME: create a synthetic `else {}` so we have something to refer to here instead of None?
|
// 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;
|
self.diverges = condition_diverges | both_arms_diverge;
|
||||||
|
|
||||||
result_ty
|
coerce.complete()
|
||||||
}
|
}
|
||||||
Expr::Block { statements, tail, label, id: _ } => {
|
Expr::Block { statements, tail, label, id: _ } => {
|
||||||
let old_resolver = mem::replace(
|
let old_resolver = mem::replace(
|
||||||
@ -193,7 +192,7 @@ impl<'a> InferenceContext<'a> {
|
|||||||
}
|
}
|
||||||
Expr::Async { body } => {
|
Expr::Async { body } => {
|
||||||
// Use the first type parameter as the output type of future.
|
// 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 inner_ty = self.infer_expr(*body, &Expectation::none());
|
||||||
let impl_trait_id = crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, *body);
|
let impl_trait_id = crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, *body);
|
||||||
let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
|
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 {
|
self.breakables.push(BreakableContext {
|
||||||
may_break: false,
|
may_break: false,
|
||||||
break_ty: self.err_ty(),
|
break_ty: self.err_ty(),
|
||||||
|
|
||||||
label: label.map(|label| self.body[label].name.clone()),
|
label: label.map(|label| self.body[label].name.clone()),
|
||||||
});
|
});
|
||||||
// while let is desugared to a match loop, so this is always simple while
|
// 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 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)
|
TyKind::Never.intern(&Interner)
|
||||||
} else {
|
} else {
|
||||||
match &expected {
|
match &expected {
|
||||||
@ -352,6 +352,7 @@ impl<'a> InferenceContext<'a> {
|
|||||||
_ => self.table.new_type_var(),
|
_ => self.table.new_type_var(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let mut coerce = CoerceMany::new(result_ty);
|
||||||
|
|
||||||
let matchee_diverges = self.diverges;
|
let matchee_diverges = self.diverges;
|
||||||
let mut all_arms_diverge = Diverges::Always;
|
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);
|
let arm_ty = self.infer_expr_inner(arm.expr, &expected);
|
||||||
all_arms_diverge &= self.diverges;
|
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;
|
self.diverges = matchee_diverges | all_arms_diverge;
|
||||||
|
|
||||||
result_ty
|
coerce.complete()
|
||||||
}
|
}
|
||||||
Expr::Path(p) => {
|
Expr::Path(p) => {
|
||||||
// FIXME this could be more efficient...
|
// FIXME this could be more efficient...
|
||||||
@ -382,6 +383,7 @@ impl<'a> InferenceContext<'a> {
|
|||||||
}
|
}
|
||||||
Expr::Continue { .. } => TyKind::Never.intern(&Interner),
|
Expr::Continue { .. } => TyKind::Never.intern(&Interner),
|
||||||
Expr::Break { expr, label } => {
|
Expr::Break { expr, label } => {
|
||||||
|
let expr = *expr;
|
||||||
let last_ty =
|
let last_ty =
|
||||||
if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) {
|
if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) {
|
||||||
ctxt.break_ty.clone()
|
ctxt.break_ty.clone()
|
||||||
@ -390,13 +392,13 @@ impl<'a> InferenceContext<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let val_ty = if let Some(expr) = expr {
|
let val_ty = if let Some(expr) = expr {
|
||||||
self.infer_expr(*expr, &Expectation::none())
|
self.infer_expr(expr, &Expectation::none())
|
||||||
} else {
|
} else {
|
||||||
TyBuilder::unit()
|
TyBuilder::unit()
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: create a synthetic `()` during lowering so we have something to refer to here?
|
// 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()) {
|
if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) {
|
||||||
ctxt.break_ty = merged_type;
|
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()));
|
self.infer_expr_coerce(*expr, &Expectation::has_type(self.return_ty.clone()));
|
||||||
} else {
|
} else {
|
||||||
let unit = TyBuilder::unit();
|
let unit = TyBuilder::unit();
|
||||||
if let Ok(ok) = self.coerce(&unit, &self.return_ty.clone()) {
|
let _ = self.coerce(Some(tgt_expr), &unit, &self.return_ty.clone());
|
||||||
self.write_expr_adj(tgt_expr, ok.value.0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
TyKind::Never.intern(&Interner)
|
TyKind::Never.intern(&Interner)
|
||||||
}
|
}
|
||||||
@ -744,39 +744,37 @@ impl<'a> InferenceContext<'a> {
|
|||||||
TyKind::Tuple(tys.len(), Substitution::from_iter(&Interner, tys)).intern(&Interner)
|
TyKind::Tuple(tys.len(), Substitution::from_iter(&Interner, tys)).intern(&Interner)
|
||||||
}
|
}
|
||||||
Expr::Array(array) => {
|
Expr::Array(array) => {
|
||||||
let mut elem_ty =
|
let elem_ty =
|
||||||
match expected.to_option(&mut self.table).as_ref().map(|t| t.kind(&Interner)) {
|
match expected.to_option(&mut self.table).as_ref().map(|t| t.kind(&Interner)) {
|
||||||
Some(TyKind::Array(st, _) | TyKind::Slice(st)) => st.clone(),
|
Some(TyKind::Array(st, _) | TyKind::Slice(st)) => st.clone(),
|
||||||
_ => self.table.new_type_var(),
|
_ => self.table.new_type_var(),
|
||||||
};
|
};
|
||||||
|
let mut coerce = CoerceMany::new(elem_ty.clone());
|
||||||
|
|
||||||
let expected = Expectation::has_type(elem_ty.clone());
|
let expected = Expectation::has_type(elem_ty.clone());
|
||||||
let len = match array {
|
let len = match array {
|
||||||
Array::ElementList(items) => {
|
Array::ElementList(items) => {
|
||||||
for expr in items.iter() {
|
for &expr in items.iter() {
|
||||||
let cur_elem_ty = self.infer_expr_inner(*expr, &expected);
|
let cur_elem_ty = self.infer_expr_inner(expr, &expected);
|
||||||
elem_ty = self.coerce_merge_branch(Some(*expr), &elem_ty, &cur_elem_ty);
|
coerce.coerce(self, Some(expr), &cur_elem_ty);
|
||||||
}
|
}
|
||||||
Some(items.len() as u64)
|
Some(items.len() as u64)
|
||||||
}
|
}
|
||||||
Array::Repeat { initializer, repeat } => {
|
&Array::Repeat { initializer, repeat } => {
|
||||||
self.infer_expr_coerce(
|
self.infer_expr_coerce(initializer, &Expectation::has_type(elem_ty));
|
||||||
*initializer,
|
|
||||||
&Expectation::has_type(elem_ty.clone()),
|
|
||||||
);
|
|
||||||
self.infer_expr(
|
self.infer_expr(
|
||||||
*repeat,
|
repeat,
|
||||||
&Expectation::has_type(
|
&Expectation::has_type(
|
||||||
TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner),
|
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)
|
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 {
|
Expr::Literal(lit) => match lit {
|
||||||
Literal::Bool(..) => TyKind::Scalar(Scalar::Bool).intern(&Interner),
|
Literal::Bool(..) => TyKind::Scalar(Scalar::Bool).intern(&Interner),
|
||||||
@ -872,9 +870,7 @@ impl<'a> InferenceContext<'a> {
|
|||||||
self.table.new_maybe_never_var()
|
self.table.new_maybe_never_var()
|
||||||
} else {
|
} else {
|
||||||
if let Some(t) = expected.only_has_type(&mut self.table) {
|
if let Some(t) = expected.only_has_type(&mut self.table) {
|
||||||
if let Ok(ok) = self.coerce(&TyBuilder::unit(), &t) {
|
let _ = self.coerce(Some(expr), &TyBuilder::unit(), &t);
|
||||||
self.write_expr_adj(expr, ok.value.0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
TyBuilder::unit()
|
TyBuilder::unit()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user