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.rs113
1 files changed, 101 insertions, 12 deletions
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index 89d92ea9af..a04e7b17ae 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -9,7 +9,8 @@ use chalk_ir::{cast::Cast, fold::Shift, DebruijnIndex, Mutability, TyVariableKin
use either::Either;
use hir_def::{
hir::{
- ArithOp, Array, BinaryOp, ClosureKind, Expr, ExprId, LabelId, Literal, Statement, UnaryOp,
+ ArithOp, Array, AsmOperand, AsmOptions, BinaryOp, ClosureKind, Expr, ExprId, LabelId,
+ Literal, Statement, UnaryOp,
},
lang_item::{LangItem, LangItemTarget},
path::{GenericArg, GenericArgs, Path},
@@ -41,9 +42,9 @@ use crate::{
primitive::{self, UintTy},
static_lifetime, to_chalk_trait_id,
traits::FnTrait,
- Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, FnAbi, FnPointer, FnSig,
- FnSubst, Interner, Rawness, Scalar, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder,
- TyExt, TyKind,
+ Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, CallableSig, FnAbi, FnPointer,
+ FnSig, FnSubst, Interner, Rawness, Scalar, Substitution, TraitEnvironment, TraitRef, Ty,
+ TyBuilder, TyExt, TyKind,
};
use super::{
@@ -610,7 +611,12 @@ impl InferenceContext<'_> {
Expr::Cast { expr, type_ref } => {
let cast_ty = self.make_ty(type_ref);
let expr_ty = self.infer_expr(*expr, &Expectation::Castable(cast_ty.clone()));
- self.deferred_cast_checks.push(CastCheck::new(expr_ty, cast_ty.clone()));
+ self.deferred_cast_checks.push(CastCheck::new(
+ tgt_expr,
+ *expr,
+ expr_ty,
+ cast_ty.clone(),
+ ));
cast_ty
}
Expr::Ref { expr, rawness, mutability } => {
@@ -845,7 +851,7 @@ impl InferenceContext<'_> {
};
for (expr, ty) in exprs.iter().zip(tys.iter_mut()) {
- self.infer_expr_coerce(*expr, &Expectation::has_type(ty.clone()));
+ *ty = self.infer_expr_coerce(*expr, &Expectation::has_type(ty.clone()));
}
TyKind::Tuple(tys.len(), Substitution::from_iter(Interner, tys)).intern(Interner)
@@ -889,21 +895,52 @@ impl InferenceContext<'_> {
TyKind::Scalar(Scalar::Int(primitive::int_ty_from_builtin(*int_ty)))
.intern(Interner)
}
- None => self.table.new_integer_var(),
+ None => {
+ let expected_ty = expected.to_option(&mut self.table);
+ let opt_ty = match expected_ty.as_ref().map(|it| it.kind(Interner)) {
+ Some(TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))) => expected_ty,
+ Some(TyKind::Scalar(Scalar::Char)) => {
+ Some(TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(Interner))
+ }
+ Some(TyKind::Raw(..) | TyKind::FnDef(..) | TyKind::Function(..)) => {
+ Some(TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner))
+ }
+ _ => None,
+ };
+ opt_ty.unwrap_or_else(|| self.table.new_integer_var())
+ }
},
Literal::Uint(_v, ty) => match ty {
Some(int_ty) => {
TyKind::Scalar(Scalar::Uint(primitive::uint_ty_from_builtin(*int_ty)))
.intern(Interner)
}
- None => self.table.new_integer_var(),
+ None => {
+ let expected_ty = expected.to_option(&mut self.table);
+ let opt_ty = match expected_ty.as_ref().map(|it| it.kind(Interner)) {
+ Some(TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))) => expected_ty,
+ Some(TyKind::Scalar(Scalar::Char)) => {
+ Some(TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(Interner))
+ }
+ Some(TyKind::Raw(..) | TyKind::FnDef(..) | TyKind::Function(..)) => {
+ Some(TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner))
+ }
+ _ => None,
+ };
+ opt_ty.unwrap_or_else(|| self.table.new_integer_var())
+ }
},
Literal::Float(_v, ty) => match ty {
Some(float_ty) => {
TyKind::Scalar(Scalar::Float(primitive::float_ty_from_builtin(*float_ty)))
.intern(Interner)
}
- None => self.table.new_float_var(),
+ None => {
+ let opt_ty = expected.to_option(&mut self.table).filter(|ty| {
+ matches!(ty.kind(Interner), TyKind::Scalar(Scalar::Float(_)))
+ });
+ opt_ty.unwrap_or_else(|| self.table.new_float_var())
+ }
},
},
Expr::Underscore => {
@@ -919,9 +956,61 @@ impl InferenceContext<'_> {
expected
}
Expr::OffsetOf(_) => TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner),
- Expr::InlineAsm(it) => {
- self.infer_expr_no_expect(it.e);
- self.result.standard_types.unit.clone()
+ Expr::InlineAsm(asm) => {
+ let mut check_expr_asm_operand = |expr, is_input: bool| {
+ let ty = self.infer_expr_no_expect(expr);
+
+ // If this is an input value, we require its type to be fully resolved
+ // at this point. This allows us to provide helpful coercions which help
+ // pass the type candidate list in a later pass.
+ //
+ // We don't require output types to be resolved at this point, which
+ // allows them to be inferred based on how they are used later in the
+ // function.
+ if is_input {
+ let ty = self.resolve_ty_shallow(&ty);
+ match ty.kind(Interner) {
+ TyKind::FnDef(def, parameters) => {
+ let fnptr_ty = TyKind::Function(
+ CallableSig::from_def(self.db, *def, parameters).to_fn_ptr(),
+ )
+ .intern(Interner);
+ _ = self.coerce(Some(expr), &ty, &fnptr_ty);
+ }
+ TyKind::Ref(mutbl, _, base_ty) => {
+ let ptr_ty = TyKind::Raw(*mutbl, base_ty.clone()).intern(Interner);
+ _ = self.coerce(Some(expr), &ty, &ptr_ty);
+ }
+ _ => {}
+ }
+ }
+ };
+
+ let diverge = asm.options.contains(AsmOptions::NORETURN);
+ asm.operands.iter().for_each(|(_, operand)| match *operand {
+ AsmOperand::In { expr, .. } => check_expr_asm_operand(expr, true),
+ AsmOperand::Out { expr: Some(expr), .. } | AsmOperand::InOut { expr, .. } => {
+ check_expr_asm_operand(expr, false)
+ }
+ AsmOperand::Out { expr: None, .. } => (),
+ AsmOperand::SplitInOut { in_expr, out_expr, .. } => {
+ check_expr_asm_operand(in_expr, true);
+ if let Some(out_expr) = out_expr {
+ check_expr_asm_operand(out_expr, false);
+ }
+ }
+ // FIXME
+ AsmOperand::Label(_) => (),
+ // FIXME
+ AsmOperand::Const(_) => (),
+ // FIXME
+ AsmOperand::Sym(_) => (),
+ });
+ if diverge {
+ self.result.standard_types.never.clone()
+ } else {
+ self.result.standard_types.unit.clone()
+ }
}
};
// use a new type variable if we got unknown here