Skip to content

Commit a16543e

Browse files
Port call expr type checking and closure upvar inference from rustc
1 parent c6e5e8c commit a16543e

63 files changed

Lines changed: 5099 additions & 2126 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bench_data/glorious_old_parser

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//- minicore: fn
12
use crate::ast::{AngleBracketedArgs, ParenthesizedArgs, AttrStyle, BareFnTy};
23
use crate::ast::{GenericBound, TraitBoundModifier};
34
use crate::ast::Unsafety;

crates/hir-def/src/expr_store.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -929,6 +929,13 @@ impl ExpressionStore {
929929
// We keep the async closure exactly one expr before.
930930
ExprId::from_raw(la_arena::RawIdx::from_u32(coroutine_closure.into_raw().into_u32() - 1))
931931
}
932+
933+
/// The opposite of [`Self::coroutine_for_closure()`].
934+
#[inline]
935+
pub fn closure_for_coroutine(coroutine: ExprId) -> ExprId {
936+
// We keep the async closure exactly one expr before.
937+
ExprId::from_raw(la_arena::RawIdx::from_u32(coroutine.into_raw().into_u32() + 1))
938+
}
932939
}
933940

934941
impl Index<ExprId> for ExpressionStore {

crates/hir-def/src/expr_store/lower.rs

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -945,12 +945,19 @@ impl<'db> ExprCollector<'db> {
945945
})
946946
}
947947

948-
/// An `async fn` needs to capture all parameters in the generated `async` block, even if they have
949-
/// non-captured patterns such as wildcards (to ensure consistent drop order).
950-
fn lower_async_fn(&mut self, params: &mut Vec<PatId>, body: ExprId) -> ExprId {
948+
/// Lowers a desugared coroutine body after moving all of the arguments
949+
/// into the body. This is to make sure that the future actually owns the
950+
/// arguments that are passed to the function, and to ensure things like
951+
/// drop order are stable.
952+
fn lower_async_block_with_moved_arguments(
953+
&mut self,
954+
params: &mut [PatId],
955+
body: ExprId,
956+
coroutine_source: CoroutineSource,
957+
) -> ExprId {
951958
let mut statements = Vec::new();
952959
for param in params {
953-
let name = match self.store.pats[*param] {
960+
let (name, hygiene) = match self.store.pats[*param] {
954961
Pat::Bind { id, .. }
955962
if matches!(
956963
self.store.bindings[id].mode,
@@ -962,14 +969,16 @@ impl<'db> ExprCollector<'db> {
962969
}
963970
Pat::Bind { id, .. } => {
964971
// If this is a `ref` binding, we can't leave it as is but we can at least reuse the name, for better display.
965-
self.store.bindings[id].name.clone()
972+
(self.store.bindings[id].name.clone(), self.store.bindings[id].hygiene)
966973
}
967-
_ => self.generate_new_name(),
974+
_ => (self.generate_new_name(), HygieneId::ROOT),
968975
};
969-
let binding_id =
970-
self.alloc_binding(name.clone(), BindingAnnotation::Mutable, HygieneId::ROOT);
976+
let binding_id = self.alloc_binding(name.clone(), BindingAnnotation::Mutable, hygiene);
971977
let pat_id = self.alloc_pat_desugared(Pat::Bind { id: binding_id, subpat: None });
972978
let expr = self.alloc_expr_desugared(Expr::Path(name.into()));
979+
if !hygiene.is_root() {
980+
self.store.ident_hygiene.insert(expr.into(), hygiene);
981+
}
973982
statements.push(Statement::Let {
974983
pat: *param,
975984
type_ref: None,
@@ -980,12 +989,17 @@ impl<'db> ExprCollector<'db> {
980989
}
981990

982991
let async_ = self.async_block(
983-
CoroutineSource::Fn,
984-
CaptureBy::Value,
992+
coroutine_source,
993+
// The default capture mode here is by-ref. Later on during upvar analysis,
994+
// we will force the captured arguments to by-move, but for async closures,
995+
// we want to make sure that we avoid unnecessarily moving captures, or else
996+
// all async closures would default to `FnOnce` as their calling mode.
997+
CaptureBy::Ref,
985998
None,
986999
statements.into_boxed_slice(),
9871000
Some(body),
9881001
);
1002+
// It's important that this comes last, see the lowering of async closures for why.
9891003
self.alloc_expr_desugared(async_)
9901004
}
9911005

@@ -1010,14 +1024,18 @@ impl<'db> ExprCollector<'db> {
10101024

10111025
fn collect(
10121026
&mut self,
1013-
params: &mut Vec<PatId>,
1027+
params: &mut [PatId],
10141028
expr: Option<ast::Expr>,
10151029
awaitable: Awaitable,
10161030
) -> ExprId {
10171031
self.awaitable_context.replace(awaitable);
10181032
self.with_label_rib(RibKind::Closure, |this| {
10191033
let body = this.collect_expr_opt(expr);
1020-
if awaitable == Awaitable::Yes { this.lower_async_fn(params, body) } else { body }
1034+
if awaitable == Awaitable::Yes {
1035+
this.lower_async_block_with_moved_arguments(params, body, CoroutineSource::Fn)
1036+
} else {
1037+
body
1038+
}
10211039
})
10221040
}
10231041

@@ -1450,18 +1468,11 @@ impl<'db> ExprCollector<'db> {
14501468
} else if e.async_token().is_some() {
14511469
// It's important that this expr is allocated immediately before the closure.
14521470
// We rely on it for `coroutine_for_closure()`.
1453-
body = this.alloc_expr_desugared(Expr::Closure {
1454-
args: Box::default(),
1455-
arg_types: Box::default(),
1456-
ret_type: None,
1471+
body = this.lower_async_block_with_moved_arguments(
1472+
&mut args,
14571473
body,
1458-
closure_kind: ClosureKind::AsyncBlock {
1459-
source: CoroutineSource::Closure,
1460-
},
1461-
// The block may need to capture by move, but we cannot know it now.
1462-
// It will be fixed in capture analysis.
1463-
capture_by: CaptureBy::Ref,
1464-
});
1474+
CoroutineSource::Closure,
1475+
);
14651476
body_is_bindings_owner = true;
14661477

14671478
ClosureKind::AsyncClosure

crates/hir-def/src/expr_store/tests/body.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,7 @@ fn async_fn_weird_param_patterns() {
652652
async fn main(&self, param1: i32, ref mut param2: i32, _: i32, param4 @ _: i32, 123: i32) {}
653653
"#,
654654
expect![[r#"
655-
fn main(self, param1, mut param2, mut <ra@gennew>0, param4 @ _, mut <ra@gennew>1) async move {
655+
fn main(self, param1, mut param2, mut <ra@gennew>0, param4 @ _, mut <ra@gennew>1) async {
656656
let ref mut param2 = param2;
657657
let _ = <ra@gennew>0;
658658
let 123 = <ra@gennew>1;

crates/hir-def/src/lang_item.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ language_item_table! { LangItems =>
306306
/// Trait injected by `#[derive(Eq)]`, (i.e. "Total EQ"; no, I will not apologize).
307307
StructuralTeq, sym::structural_teq, TraitId;
308308
Copy, sym::copy, TraitId;
309+
UseCloned, sym::use_cloned, TraitId;
309310
Clone, sym::clone, TraitId;
310311
TrivialClone, sym::trivial_clone, TraitId;
311312
Sync, sym::sync, TraitId;

crates/hir-ty/src/consteval/tests.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1792,14 +1792,14 @@ const GOAL: i32 = {
17921792
fn closure_capture_unsized_type() {
17931793
check_number(
17941794
r#"
1795-
//- minicore: fn, copy, slice, index, coerce_unsized
1795+
//- minicore: fn, copy, slice, index, coerce_unsized, sized
17961796
fn f<T: A>(x: &<T as A>::Ty) -> &<T as A>::Ty {
17971797
let c = || &*x;
17981798
c()
17991799
}
18001800
18011801
trait A {
1802-
type Ty;
1802+
type Ty: ?Sized;
18031803
}
18041804
18051805
impl A for i32 {
@@ -1810,7 +1810,7 @@ fn closure_capture_unsized_type() {
18101810
let k: &[u8] = &[1, 2, 3];
18111811
let k = f::<i32>(k);
18121812
k[0] + k[1] + k[2]
1813-
}
1813+
};
18141814
"#,
18151815
6,
18161816
);

crates/hir-ty/src/diagnostics/expr.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,8 +238,7 @@ impl<'db> ExprValidator<'db> {
238238
if (pat_ty == scrut_ty
239239
|| scrut_ty
240240
.as_reference()
241-
.map(|(match_expr_ty, ..)| match_expr_ty == pat_ty)
242-
.unwrap_or(false))
241+
.is_none_or(|(match_expr_ty, ..)| match_expr_ty == pat_ty))
243242
&& types_of_subpatterns_do_match(arm.pat, self.body, self.infer)
244243
{
245244
// If we had a NotUsefulMatchArm diagnostic, we could

crates/hir-ty/src/display.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ use span::Edition;
4747
use stdx::never;
4848

4949
use crate::{
50-
CallableDefId, FnAbi, ImplTraitId, InferenceResult, MemoryMap, ParamEnvAndCrate, consteval,
50+
CallableDefId, FnAbi, ImplTraitId, MemoryMap, ParamEnvAndCrate, consteval,
5151
db::{HirDatabase, InternedClosure},
5252
generics::generics,
5353
layout::Layout,
@@ -1495,9 +1495,7 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
14951495
}
14961496
let sig = interner.signature_unclosure(substs.as_closure().sig(), Safety::Safe);
14971497
let sig = sig.skip_binder();
1498-
let InternedClosure(owner, _) = id.loc(db);
1499-
let infer = InferenceResult::of(db, owner);
1500-
let (_, kind) = infer.closure_info(id);
1498+
let kind = substs.as_closure().kind();
15011499
match f.closure_style {
15021500
ClosureStyle::ImplFn => write!(f, "impl {kind:?}(")?,
15031501
ClosureStyle::RANotation => write!(f, "|")?,

crates/hir-ty/src/drop.rs

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
//! Utilities for computing drop info about types.
22
33
use hir_def::{
4-
AdtId,
4+
AdtId, ImplId,
55
signatures::{StructFlags, StructSignature},
66
};
77
use rustc_hash::FxHashSet;
8-
use rustc_type_ir::inherent::{AdtDef, IntoKind};
8+
use rustc_type_ir::inherent::{AdtDef, GenericArgs as _, IntoKind};
99
use stdx::never;
1010

1111
use crate::{
12-
InferenceResult, consteval,
12+
consteval,
13+
db::HirDatabase,
1314
method_resolution::TraitImpls,
1415
next_solver::{
1516
DbInterner, ParamEnv, SimplifiedType, Ty, TyKind,
@@ -18,24 +19,23 @@ use crate::{
1819
},
1920
};
2021

21-
fn has_destructor(interner: DbInterner<'_>, adt: AdtId) -> bool {
22-
let db = interner.db;
22+
#[salsa::tracked]
23+
pub fn destructor(db: &dyn HirDatabase, adt: AdtId) -> Option<ImplId> {
2324
let module = match adt {
2425
AdtId::EnumId(id) => db.lookup_intern_enum(id).container,
2526
AdtId::StructId(id) => db.lookup_intern_struct(id).container,
2627
AdtId::UnionId(id) => db.lookup_intern_union(id).container,
2728
};
28-
let Some(drop_trait) = interner.lang_items().Drop else {
29-
return false;
30-
};
29+
let interner = DbInterner::new_with(db, module.krate(db));
30+
let drop_trait = interner.lang_items().Drop?;
3131
let impls = match module.block(db) {
3232
Some(block) => match TraitImpls::for_block(db, block) {
3333
Some(it) => &**it,
34-
None => return false,
34+
None => return None,
3535
},
3636
None => TraitImpls::for_crate(db, module.krate(db)),
3737
};
38-
!impls.for_trait_and_self_ty(drop_trait, &SimplifiedType::Adt(adt.into())).0.is_empty()
38+
impls.for_trait_and_self_ty(drop_trait, &SimplifiedType::Adt(adt.into())).0.first().copied()
3939
}
4040

4141
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
@@ -71,7 +71,7 @@ fn has_drop_glue_impl<'db>(
7171
match ty.kind() {
7272
TyKind::Adt(adt_def, subst) => {
7373
let adt_id = adt_def.def_id().0;
74-
if has_destructor(infcx.interner, adt_id) {
74+
if adt_def.destructor(infcx.interner).is_some() {
7575
return DropGlue::HasDropGlue;
7676
}
7777
match adt_id {
@@ -132,21 +132,17 @@ fn has_drop_glue_impl<'db>(
132132
has_drop_glue_impl(infcx, ty, env, visited)
133133
}
134134
TyKind::Slice(ty) => has_drop_glue_impl(infcx, ty, env, visited),
135-
TyKind::Closure(closure_id, subst) => {
136-
let owner = closure_id.0.loc(db).0;
137-
let infer = InferenceResult::of(db, owner);
138-
let (captures, _) = infer.closure_info(closure_id.0);
139-
let env = db.trait_environment(owner);
140-
captures
141-
.iter()
142-
.map(|capture| has_drop_glue_impl(infcx, capture.ty(db, subst), env, visited))
143-
.max()
144-
.unwrap_or(DropGlue::None)
135+
TyKind::Closure(_, args) => {
136+
has_drop_glue_impl(infcx, args.as_closure().tupled_upvars_ty(), env, visited)
145137
}
146-
// FIXME: Handle coroutines.
147-
TyKind::Coroutine(..) | TyKind::CoroutineWitness(..) | TyKind::CoroutineClosure(..) => {
148-
DropGlue::None
138+
TyKind::Coroutine(_, args) => {
139+
has_drop_glue_impl(infcx, args.as_coroutine().tupled_upvars_ty(), env, visited)
140+
}
141+
TyKind::CoroutineClosure(_, args) => {
142+
has_drop_glue_impl(infcx, args.as_coroutine_closure().tupled_upvars_ty(), env, visited)
149143
}
144+
// FIXME: Coroutine witness.
145+
TyKind::CoroutineWitness(..) => DropGlue::None,
150146
TyKind::Ref(..)
151147
| TyKind::RawPtr(..)
152148
| TyKind::FnDef(..)

0 commit comments

Comments
 (0)