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.rs67
1 files changed, 60 insertions, 7 deletions
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index b1c793a1e3..a82d091cbb 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::{
@@ -924,9 +925,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