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:
commit
ffb04ae32d
@ -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(),
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
};
|
};
|
||||||
|
@ -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];
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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(
|
||||||
|
Loading…
Reference in New Issue
Block a user