Skip to content

Commit cc5bc48

Browse files
Merge pull request #22101 from ChayimFriedman2/port-infer-call
fix: Port call expr type checking and closure upvar inference from rustc
2 parents 8d9244a + 3d6be00 commit cc5bc48

67 files changed

Lines changed: 5169 additions & 2148 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: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,9 @@ impl ExpressionStore {
675675
f(*expr);
676676
arms.iter().for_each(|arm| {
677677
f(arm.expr);
678+
if let Some(guard) = arm.guard {
679+
f(guard);
680+
}
678681
self.walk_exprs_in_pat(arm.pat, &mut f);
679682
});
680683
}
@@ -926,6 +929,13 @@ impl ExpressionStore {
926929
// We keep the async closure exactly one expr before.
927930
ExprId::from_raw(la_arena::RawIdx::from_u32(coroutine_closure.into_raw().into_u32() - 1))
928931
}
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+
}
929939
}
930940

931941
impl Index<ExprId> for ExpressionStore {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ impl Body {
133133
expr: ExprId,
134134
edition: Edition,
135135
) -> String {
136-
pretty::print_expr_hir(db, self, owner, expr, edition)
136+
pretty::print_expr_hir(db, self, owner.into(), expr, edition)
137137
}
138138

139139
pub fn pretty_print_pat(
@@ -144,7 +144,7 @@ impl Body {
144144
oneline: bool,
145145
edition: Edition,
146146
) -> String {
147-
pretty::print_pat_hir(db, self, owner, pat, oneline, edition)
147+
pretty::print_pat_hir(db, self, owner.into(), pat, oneline, edition)
148148
}
149149
}
150150

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

Lines changed: 57 additions & 30 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

@@ -1407,9 +1425,11 @@ impl<'db> ExprCollector<'db> {
14071425
}
14081426
}
14091427
ast::Expr::ClosureExpr(e) => self.with_label_rib(RibKind::Closure, |this| {
1410-
this.with_binding_owner(|this| {
1428+
this.with_binding_owner_and_return(|this| {
14111429
let mut args = Vec::new();
14121430
let mut arg_types = Vec::new();
1431+
// For coroutine closures, the body, aka. the coroutine is the bindings owner, and not the closure.
1432+
let mut body_is_bindings_owner = false;
14131433
if let Some(pl) = e.param_list() {
14141434
let num_params = pl.params().count();
14151435
args.reserve_exact(num_params);
@@ -1448,18 +1468,12 @@ impl<'db> ExprCollector<'db> {
14481468
} else if e.async_token().is_some() {
14491469
// It's important that this expr is allocated immediately before the closure.
14501470
// We rely on it for `coroutine_for_closure()`.
1451-
body = this.alloc_expr_desugared(Expr::Closure {
1452-
args: Box::default(),
1453-
arg_types: Box::default(),
1454-
ret_type: None,
1471+
body = this.lower_async_block_with_moved_arguments(
1472+
&mut args,
14551473
body,
1456-
closure_kind: ClosureKind::AsyncBlock {
1457-
source: CoroutineSource::Closure,
1458-
},
1459-
// The block may need to capture by move, but we cannot know it now.
1460-
// It will be fixed in capture analysis.
1461-
capture_by: CaptureBy::Ref,
1462-
});
1474+
CoroutineSource::Closure,
1475+
);
1476+
body_is_bindings_owner = true;
14631477

14641478
ClosureKind::AsyncClosure
14651479
} else {
@@ -1469,7 +1483,7 @@ impl<'db> ExprCollector<'db> {
14691483
if e.move_token().is_some() { CaptureBy::Value } else { CaptureBy::Ref };
14701484
this.is_lowering_coroutine = prev_is_lowering_coroutine;
14711485
this.current_try_block = prev_try_block;
1472-
this.alloc_expr(
1486+
let closure = this.alloc_expr(
14731487
Expr::Closure {
14741488
args: args.into(),
14751489
arg_types: arg_types.into(),
@@ -1479,7 +1493,9 @@ impl<'db> ExprCollector<'db> {
14791493
capture_by,
14801494
},
14811495
syntax_ptr,
1482-
)
1496+
);
1497+
1498+
(if body_is_bindings_owner { body } else { closure }, closure)
14831499
})
14841500
}),
14851501
ast::Expr::BinExpr(e) => {
@@ -1781,13 +1797,24 @@ impl<'db> ExprCollector<'db> {
17811797
}
17821798
}
17831799

1784-
fn with_binding_owner(&mut self, create_expr: impl FnOnce(&mut Self) -> ExprId) -> ExprId {
1800+
/// The callback should return two exprs: the first is the bindings owner, the second is the expr to return.
1801+
fn with_binding_owner_and_return(
1802+
&mut self,
1803+
create_expr: impl FnOnce(&mut Self) -> (ExprId, ExprId),
1804+
) -> ExprId {
17851805
let prev_unowned_bindings_len = self.unowned_bindings.len();
1786-
let expr_id = create_expr(self);
1806+
let (bindings_owner, expr_to_return) = create_expr(self);
17871807
for binding in self.unowned_bindings.drain(prev_unowned_bindings_len..) {
1788-
self.store.binding_owners.insert(binding, expr_id);
1808+
self.store.binding_owners.insert(binding, bindings_owner);
17891809
}
1790-
expr_id
1810+
expr_to_return
1811+
}
1812+
1813+
fn with_binding_owner(&mut self, create_expr: impl FnOnce(&mut Self) -> ExprId) -> ExprId {
1814+
self.with_binding_owner_and_return(move |this| {
1815+
let expr = create_expr(this);
1816+
(expr, expr)
1817+
})
17911818
}
17921819

17931820
/// Desugar `try { <stmts>; <expr> }` into `'<new_label>: { <stmts>; ::std::ops::Try::from_output(<expr>) }`,

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ fn print_generic_params(db: &dyn DefDatabase, generic_params: &GenericParams, p:
401401
pub fn print_expr_hir(
402402
db: &dyn DefDatabase,
403403
store: &ExpressionStore,
404-
_owner: DefWithBodyId,
404+
_owner: ExpressionStoreOwnerId,
405405
expr: ExprId,
406406
edition: Edition,
407407
) -> String {
@@ -420,7 +420,7 @@ pub fn print_expr_hir(
420420
pub fn print_pat_hir(
421421
db: &dyn DefDatabase,
422422
store: &ExpressionStore,
423-
_owner: DefWithBodyId,
423+
_owner: ExpressionStoreOwnerId,
424424
pat: PatId,
425425
oneline: bool,
426426
edition: Edition,

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: 10 additions & 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;
@@ -324,6 +325,7 @@ language_item_table! { LangItems =>
324325

325326
Drop, sym::drop, TraitId;
326327
Destruct, sym::destruct, TraitId;
328+
BikeshedGuaranteedNoDrop,sym::bikeshed_guaranteed_no_drop, TraitId;
327329

328330
CoerceUnsized, sym::coerce_unsized, TraitId;
329331
DispatchFromDyn, sym::dispatch_from_dyn, TraitId;
@@ -373,6 +375,8 @@ language_item_table! { LangItems =>
373375
AsyncFn, sym::async_fn, TraitId;
374376
AsyncFnMut, sym::async_fn_mut, TraitId;
375377
AsyncFnOnce, sym::async_fn_once, TraitId;
378+
AsyncFnKindHelper, sym::async_fn_kind_helper,TraitId;
379+
AsyncFnKindUpvars, sym::async_fn_kind_upvars,TypeAliasId;
376380

377381
CallRefFuture, sym::call_ref_future, TypeAliasId;
378382
CallOnceFuture, sym::call_once_future, TypeAliasId;
@@ -489,6 +493,8 @@ language_item_table! { LangItems =>
489493
IntoIterIntoIter, sym::into_iter, FunctionId;
490494
IteratorNext, sym::next, FunctionId;
491495
Iterator, sym::iterator, TraitId;
496+
FusedIterator, sym::fused_iterator, TraitId;
497+
AsyncIterator, sym::async_iterator, TraitId;
492498

493499
PinNewUnchecked, sym::new_unchecked, FunctionId;
494500

@@ -509,6 +515,10 @@ language_item_table! { LangItems =>
509515
CStr, sym::CStr, StructId;
510516
Ordering, sym::Ordering, EnumId;
511517

518+
Field, sym::field, TraitId;
519+
FieldBase, sym::field_base, TypeAliasId;
520+
FieldType, sym::field_type, TypeAliasId;
521+
512522
@non_lang_core_traits:
513523
core::default, Default;
514524
core::fmt, Debug;

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

0 commit comments

Comments
 (0)