Auto merge of #14461 - HKalbasi:dev, r=Veykril

Use async block in async fn type inference

fix #14456

At some point we should probably go further and completely desugar async fn in hir lowering.
This commit is contained in:
bors 2023-04-01 05:19:36 +00:00
commit ffb04ae32d
7 changed files with 68 additions and 57 deletions

View File

@ -30,7 +30,6 @@ pub struct FunctionData {
pub name: Name, pub name: Name,
pub params: Vec<(Option<Name>, Interned<TypeRef>)>, pub params: Vec<(Option<Name>, Interned<TypeRef>)>,
pub ret_type: Interned<TypeRef>, pub ret_type: Interned<TypeRef>,
pub async_ret_type: Option<Interned<TypeRef>>,
pub attrs: Attrs, pub attrs: Attrs,
pub visibility: RawVisibility, pub visibility: RawVisibility,
pub abi: Option<Interned<str>>, pub abi: Option<Interned<str>>,
@ -104,7 +103,6 @@ pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<Funct
}) })
.collect(), .collect(),
ret_type: func.ret_type.clone(), ret_type: func.ret_type.clone(),
async_ret_type: func.async_ret_type.clone(),
attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()), attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
visibility, visibility,
abi: func.abi.clone(), abi: func.abi.clone(),

View File

@ -608,7 +608,6 @@ pub struct Function {
pub abi: Option<Interned<str>>, pub abi: Option<Interned<str>>,
pub params: IdxRange<Param>, pub params: IdxRange<Param>,
pub ret_type: Interned<TypeRef>, pub ret_type: Interned<TypeRef>,
pub async_ret_type: Option<Interned<TypeRef>>,
pub ast_id: FileAstId<ast::Fn>, pub ast_id: FileAstId<ast::Fn>,
pub(crate) flags: FnFlags, pub(crate) flags: FnFlags,
} }

View File

@ -364,13 +364,12 @@ fn lower_function(&mut self, func: &ast::Fn) -> Option<FileItemTreeId<Function>>
None => TypeRef::unit(), None => TypeRef::unit(),
}; };
let (ret_type, async_ret_type) = if func.async_token().is_some() { let ret_type = if func.async_token().is_some() {
let async_ret_type = ret_type.clone();
let future_impl = desugar_future_path(ret_type); let future_impl = desugar_future_path(ret_type);
let ty_bound = Interned::new(TypeBound::Path(future_impl, TraitBoundModifier::None)); let ty_bound = Interned::new(TypeBound::Path(future_impl, TraitBoundModifier::None));
(TypeRef::ImplTrait(vec![ty_bound]), Some(async_ret_type)) TypeRef::ImplTrait(vec![ty_bound])
} else { } else {
(ret_type, None) ret_type
}; };
let abi = func.abi().map(lower_abi); let abi = func.abi().map(lower_abi);
@ -404,7 +403,6 @@ fn lower_function(&mut self, func: &ast::Fn) -> Option<FileItemTreeId<Function>>
abi, abi,
params, params,
ret_type: Interned::new(ret_type), ret_type: Interned::new(ret_type),
async_ret_type: async_ret_type.map(Interned::new),
ast_id, ast_id,
flags, flags,
}; };

View File

@ -233,7 +233,6 @@ fn print_mod_item(&mut self, item: ModItem) {
abi, abi,
params, params,
ret_type, ret_type,
async_ret_type: _,
ast_id: _, ast_id: _,
flags, flags,
} = &self.tree[it]; } = &self.tree[it];

View File

@ -459,6 +459,7 @@ pub(crate) struct InferenceContext<'a> {
resume_yield_tys: Option<(Ty, Ty)>, resume_yield_tys: Option<(Ty, Ty)>,
diverges: Diverges, diverges: Diverges,
breakables: Vec<BreakableContext>, breakables: Vec<BreakableContext>,
is_async_fn: bool,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -526,6 +527,7 @@ fn new(
resolver, resolver,
diverges: Diverges::Maybe, diverges: Diverges::Maybe,
breakables: Vec::new(), breakables: Vec::new(),
is_async_fn: false,
} }
} }
@ -636,12 +638,10 @@ fn collect_fn(&mut self, func: FunctionId) {
self.infer_top_pat(*pat, &ty); self.infer_top_pat(*pat, &ty);
} }
let error_ty = &TypeRef::Error; let return_ty = &*data.ret_type;
let return_ty = if data.has_async_kw() { if data.has_async_kw() {
data.async_ret_type.as_deref().unwrap_or(error_ty) self.is_async_fn = true;
} else { }
&*data.ret_type
};
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver) let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver)
.with_impl_trait_mode(ImplTraitLoweringMode::Opaque); .with_impl_trait_mode(ImplTraitLoweringMode::Opaque);

View File

@ -162,35 +162,7 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
.1 .1
} }
Expr::Async { id, statements, tail } => { Expr::Async { id, statements, tail } => {
let ret_ty = self.table.new_type_var(); self.infer_async_block(tgt_expr, id, statements, tail)
let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
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.clone())));
let (_, inner_ty) =
self.with_breakable_ctx(BreakableKind::Border, None, None, |this| {
this.infer_block(
tgt_expr,
*id,
statements,
*tail,
None,
&Expectation::has_type(ret_ty),
)
});
self.diverges = prev_diverges;
self.return_ty = prev_ret_ty;
self.return_coercion = prev_ret_coercion;
// Use the first type parameter as the output type of future.
// existential type AsyncBlockImplTrait<InnerType>: Future<Output = InnerType>
let impl_trait_id =
crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, tgt_expr);
let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
TyKind::OpaqueType(opaque_ty_id, Substitution::from1(Interner, inner_ty))
.intern(Interner)
} }
&Expr::Loop { body, label } => { &Expr::Loop { body, label } => {
// FIXME: should be: // FIXME: should be:
@ -260,18 +232,7 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
None => self.table.new_type_var(), None => self.table.new_type_var(),
}; };
if let ClosureKind::Async = closure_kind { if let ClosureKind::Async = closure_kind {
// Use the first type parameter as the output type of future. sig_tys.push(self.lower_async_block_type_impl_trait(ret_ty.clone(), *body));
// existential type AsyncBlockImplTrait<InnerType>: Future<Output = InnerType>
let impl_trait_id =
crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, *body);
let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
sig_tys.push(
TyKind::OpaqueType(
opaque_ty_id,
Substitution::from1(Interner, ret_ty.clone()),
)
.intern(Interner),
);
} else { } else {
sig_tys.push(ret_ty.clone()); sig_tys.push(ret_ty.clone());
} }
@ -332,6 +293,7 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
// FIXME: lift these out into a struct // FIXME: lift these out into a struct
let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
let prev_is_async_fn = mem::replace(&mut self.is_async_fn, false);
let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone()); let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
let prev_ret_coercion = let prev_ret_coercion =
mem::replace(&mut self.return_coercion, Some(CoerceMany::new(ret_ty))); mem::replace(&mut self.return_coercion, Some(CoerceMany::new(ret_ty)));
@ -345,6 +307,7 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
self.diverges = prev_diverges; self.diverges = prev_diverges;
self.return_ty = prev_ret_ty; self.return_ty = prev_ret_ty;
self.return_coercion = prev_ret_coercion; self.return_coercion = prev_ret_coercion;
self.is_async_fn = prev_is_async_fn;
self.resume_yield_tys = prev_resume_yield_tys; self.resume_yield_tys = prev_resume_yield_tys;
ty ty
@ -900,6 +863,42 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
ty ty
} }
fn infer_async_block(
&mut self,
tgt_expr: ExprId,
id: &Option<BlockId>,
statements: &[Statement],
tail: &Option<ExprId>,
) -> Ty {
let ret_ty = self.table.new_type_var();
let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
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.clone())));
let (_, inner_ty) = self.with_breakable_ctx(BreakableKind::Border, None, None, |this| {
this.infer_block(tgt_expr, *id, statements, *tail, None, &Expectation::has_type(ret_ty))
});
self.diverges = prev_diverges;
self.return_ty = prev_ret_ty;
self.return_coercion = prev_ret_coercion;
self.lower_async_block_type_impl_trait(inner_ty, tgt_expr)
}
pub(crate) fn lower_async_block_type_impl_trait(
&mut self,
inner_ty: Ty,
tgt_expr: ExprId,
) -> Ty {
// Use the first type parameter as the output type of future.
// existential type AsyncBlockImplTrait<InnerType>: Future<Output = InnerType>
let impl_trait_id = crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, tgt_expr);
let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
TyKind::OpaqueType(opaque_ty_id, Substitution::from1(Interner, inner_ty)).intern(Interner)
}
fn infer_expr_array( fn infer_expr_array(
&mut self, &mut self,
array: &Array, array: &Array,
@ -964,7 +963,11 @@ pub(super) fn infer_return(&mut self, expr: ExprId) {
.as_mut() .as_mut()
.expect("infer_return called outside function body") .expect("infer_return called outside function body")
.expected_ty(); .expected_ty();
let return_expr_ty = self.infer_expr_inner(expr, &Expectation::HasType(ret_ty)); let return_expr_ty = if self.is_async_fn {
self.infer_async_block(expr, &None, &[], &Some(expr))
} else {
self.infer_expr_inner(expr, &Expectation::HasType(ret_ty))
};
let mut coerce_many = self.return_coercion.take().unwrap(); let mut coerce_many = self.return_coercion.take().unwrap();
coerce_many.coerce(self, Some(expr), &return_expr_ty); coerce_many.coerce(self, Some(expr), &return_expr_ty);
self.return_coercion = Some(coerce_many); self.return_coercion = Some(coerce_many);

View File

@ -1757,6 +1757,20 @@ trait Tr {}
); );
} }
#[test]
fn regression_14456() {
check_no_mismatches(
r#"
//- minicore: future
async fn x() {}
fn f() {
let fut = x();
let t = [0u8; 2 + 2];
}
"#,
);
}
#[test] #[test]
fn regression_14164() { fn regression_14164() {
check_types( check_types(