Skip to content

delegation: move statements out of the first arg#157248

Open
aerooneqq wants to merge 2 commits into
rust-lang:mainfrom
aerooneqq:delegation-statements-out-of-first-arg
Open

delegation: move statements out of the first arg#157248
aerooneqq wants to merge 2 commits into
rust-lang:mainfrom
aerooneqq:delegation-statements-out-of-first-arg

Conversation

@aerooneqq
Copy link
Copy Markdown
Contributor

@aerooneqq aerooneqq commented Jun 1, 2026

This PR moves statements that precede final block expression out of the first argument, so we can apply adjustments to final block expression in more cases.

This changes behavior a bit, for example if we specify an empty block:

fn b<C>(e: C) {}
reuse b {}

// Desugaring:
fn b<C>(arg0: _) -> _ { b::<C>(arg0) }

So we generated the first arg and block is no-op.

In general scenario:

trait Trait: Sized { //~ WARN trait `Trait` is never used
    fn by_value(self, x: i32) -> i32 { x }
    fn by_ref(&self, x: i32) -> i32 { x }
    fn by_mut_ref(&mut self, x: i32) -> i32 { x }
}

struct F; //~ WARN struct `F` is never constructed
impl Trait for F {}

struct S(F); //~ WARN struct `S` is never constructed
impl Trait for S {
    reuse <F as Trait>::* {
        println!();
        // Final expression is adjusted even if it is in a block.
        self.0
    }
}

// Desugaring:
#[attr = Inline(Hint)]
fn by_value(self: _, arg1: _)
    ->
        _ {
    // Final expression is adjusted even if it is in a block.

    { ::std::io::_print(format_arguments::from_str("\n")); };
    <F as Trait>::by_value(self.0, arg1)
}
#[attr = Inline(Hint)]
fn by_ref(self: _, arg1: _)
    ->
        _ {
    { ::std::io::_print(format_arguments::from_str("\n")); };
    <F as Trait>::by_ref(self.0, arg1)
}
#[attr = Inline(Hint)]
fn by_mut_ref(self: _, arg1: _)
    ->
        _ {
    { ::std::io::_print(format_arguments::from_str("\n")); };
    <F as Trait>::by_mut_ref(self.0, arg1)
}

If we change target expression to

reuse <F as Trait>::* {
    println!();
    let x = 1;
}

// Desugaring:
#[attr = Inline(Hint)]
fn by_value(self: _, arg1: _)
    ->
        _ {

    { ::std::io::_print(format_arguments::from_str("\n")); };
    let x = 1;
    <F as Trait>::by_value(self, arg1)
}

Once again we generated default arguments for function and block is no-op now (meaning it does not affect callee arguments).

Part of #118212.
r? @petrochenkov

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jun 1, 2026
@aerooneqq aerooneqq changed the title delegation: move out statements out of the first arg delegation: move statements out of the first arg Jun 1, 2026
@aerooneqq aerooneqq force-pushed the delegation-statements-out-of-first-arg branch from aff0ceb to ba754c4 Compare June 2, 2026 05:57
@aerooneqq aerooneqq marked this pull request as ready for review June 2, 2026 05:59
@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 2, 2026
@petrochenkov petrochenkov added the F-fn_delegation `#![feature(fn_delegation)]` label Jun 2, 2026
this.ident_and_label_to_local_id.insert(pat_node_id, param.pat.hir_id.local_id);
this.lower_target_expr(&block)

// Lower with `HirId::INVALID` as we will use only expr. and stmts.
Copy link
Copy Markdown
Contributor

@petrochenkov petrochenkov Jun 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Lower with `HirId::INVALID` as we will use only expr. and stmts.
// Lower with `HirId::INVALID` as we will use only expr and stmts.

View changes since the review


statements = Some(block.stmts);

arg
Copy link
Copy Markdown
Contributor

@petrochenkov petrochenkov Jun 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
arg
if let Some(&expr) = block.expr { expr } else { generate_arg(this) }

View changes since the review

// https://github.com/rust-lang/rfcs/pull/3530#issuecomment-2197170600.
let block = this.lower_block_noalloc(HirId::INVALID, block, false);

let arg = if let Some(&expr) = block.expr { expr } else { generate_arg(this) };
Copy link
Copy Markdown
Contributor

@petrochenkov petrochenkov Jun 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new semantics "no trailing statement means the first argument is passed through" needs to be written out in a comment.
It differs from the usual behavior, which is "no trailing statement means an empty tuple is passed".

View changes since the review

let block_id = self.lower_body(|this| {
let mut parameters: Vec<hir::Param<'_>> = Vec::with_capacity(param_count);
let mut args: Vec<hir::Expr<'_>> = Vec::with_capacity(param_count);
let mut statements = None;
Copy link
Copy Markdown
Contributor

@petrochenkov petrochenkov Jun 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let mut statements = None;
let mut statements = &[];

No need for an option.

View changes since the review

let callee_path = this.arena.alloc(this.mk_expr(hir::ExprKind::Path(path), span));
let args = if let Some(block) = delegation.body.as_ref() {
this.arena.alloc_slice(&[this.lower_target_expr(block)])
this.arena.alloc_slice(&[this.lower_block_expr(block)])
Copy link
Copy Markdown
Contributor

@petrochenkov petrochenkov Jun 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit unfortunate that the behavior in the erroneous cases (here and in "If we have no params in signature...") differs from the good case, but not a big deal.

View changes since the review

@petrochenkov petrochenkov added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

F-fn_delegation `#![feature(fn_delegation)]` S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants