Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tracking Issue for function delegation (fn_delegation, RFC 3530) #118212

Open
6 of 25 tasks
petrochenkov opened this issue Nov 23, 2023 · 6 comments
Open
6 of 25 tasks

Tracking Issue for function delegation (fn_delegation, RFC 3530) #118212

petrochenkov opened this issue Nov 23, 2023 · 6 comments
Labels
B-experimental Blocker: In-tree experiment; RFC pending or unneeded. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. F-fn_delegation `#![feature(fn_delegation)]` S-tracking-impl-incomplete Status: The implementation is incomplete. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@petrochenkov
Copy link
Contributor

petrochenkov commented Nov 23, 2023

This is a tracking issue for the RFC "Implement function delegation in rustc" (rust-lang/rfcs#3530).
The feature gate for the issue is #![feature(fn_delegation)].

The feature was accepted for experimentation in #117978 (comment).

About tracking issues

Tracking issues are used to record the overall progress of implementation.
They are also used as hubs connecting to other relevant issues, e.g., bugs or open design questions.
A tracking issue is however not meant for large scale discussion, questions, or bug reports about a feature.
Instead, open a dedicated issue for the specific matter and add the relevant feature gate label.

Steps

Unresolved Questions

Many of them in the RFC draft.

Implementation history

https://github.com/rust-lang/rust/pulls?q=is:pr label:F-fn_delegation

@petrochenkov petrochenkov added the C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. label Nov 23, 2023
@petrochenkov
Copy link
Contributor Author

cc @Bryanskiy

@fmease fmease added the T-lang Relevant to the language team, which will review and decide on the PR/issue. label Nov 23, 2023
bors added a commit to rust-lang-ci/rust that referenced this issue Jan 11, 2024
Delegation implementation: step 1

See rust-lang#118212 for more details.

r? `@petrochenkov`
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Jan 11, 2024
…ov,lcnr

Delegation implementation: step 1

See rust-lang#118212 for more details.

r? `@petrochenkov`
bors added a commit to rust-lang-ci/rust that referenced this issue Jan 11, 2024
…,lcnr

Delegation implementation: step 1

See rust-lang#118212 for more details.

r? `@petrochenkov`
bors added a commit to rust-lang-ci/rust that referenced this issue Jan 12, 2024
…,lcnr

Delegation implementation: step 1

See rust-lang#118212 for more details.

r? `@petrochenkov`
bors added a commit to rust-lang-ci/rust that referenced this issue Jan 13, 2024
…,lcnr

Delegation implementation: step 1

See rust-lang#118212 for more details.

r? `@petrochenkov`
@fmease fmease added the F-fn_delegation `#![feature(fn_delegation)]` label Jan 13, 2024
github-actions bot pushed a commit to rust-lang/miri that referenced this issue Jan 14, 2024
Delegation implementation: step 1

See rust-lang/rust#118212 for more details.

r? `@petrochenkov`
flip1995 pushed a commit to flip1995/rust-clippy that referenced this issue Jan 25, 2024
Delegation implementation: step 1

See rust-lang/rust#118212 for more details.

r? `@petrochenkov`
fmease added a commit to fmease/rust that referenced this issue Apr 24, 2024
delegation: Support renaming, and async, const, extern "ABI" and C-variadic functions

Also allow delegating to functions with opaque types (`impl Trait`).
The delegation item will refer to the original opaque type from the callee, fresh opaque type won't be created, which seems like a reasonable behavior.
(Such delegation items will cause query cycles when used in trait impls, but it can be fixed later.)

Part of rust-lang#118212.
fmease added a commit to fmease/rust that referenced this issue Apr 24, 2024
delegation: Support renaming, and async, const, extern "ABI" and C-variadic functions

Also allow delegating to functions with opaque types (`impl Trait`).
The delegation item will refer to the original opaque type from the callee, fresh opaque type won't be created, which seems like a reasonable behavior.
(Such delegation items will cause query cycles when used in trait impls, but it can be fixed later.)

Part of rust-lang#118212.
bors added a commit to rust-lang-ci/rust that referenced this issue Apr 24, 2024
delegation: Support renaming, and async, const, extern "ABI" and C-variadic functions

Also allow delegating to functions with opaque types (`impl Trait`).
The delegation item will refer to the original opaque type from the callee, fresh opaque type won't be created, which seems like a reasonable behavior.
(Such delegation items will cause query cycles when used in trait impls, but it can be fixed later.)

Part of rust-lang#118212.
github-actions bot pushed a commit to rust-lang/miri that referenced this issue Apr 25, 2024
delegation: Support renaming, and async, const, extern "ABI" and C-variadic functions

Also allow delegating to functions with opaque types (`impl Trait`).
The delegation item will refer to the original opaque type from the callee, fresh opaque type won't be created, which seems like a reasonable behavior.
(Such delegation items will cause query cycles when used in trait impls, but it can be fixed later.)

Part of rust-lang/rust#118212.
RalfJung pushed a commit to RalfJung/rust-analyzer that referenced this issue Apr 27, 2024
delegation: Support renaming, and async, const, extern "ABI" and C-variadic functions

Also allow delegating to functions with opaque types (`impl Trait`).
The delegation item will refer to the original opaque type from the callee, fresh opaque type won't be created, which seems like a reasonable behavior.
(Such delegation items will cause query cycles when used in trait impls, but it can be fixed later.)

Part of rust-lang/rust#118212.
@fmease fmease added B-experimental Blocker: In-tree experiment; RFC pending or unneeded. S-tracking-impl-incomplete Status: The implementation is incomplete. labels May 14, 2024
bors added a commit to rust-lang-ci/rust that referenced this issue May 15, 2024
delegation: Implement list delegation

```rust
reuse prefix::{a, b, c};
```

Using design described in rust-lang/rfcs#3530 (comment) (the lists are desugared at macro expansion time).
List delegations are expanded eagerly when encountered, similarly to `#[cfg]`s, and not enqueued for later resolution/expansion like regular macros or glob delegation (rust-lang#124135).

Part of rust-lang#118212.
@jdonszelmann
Copy link
Contributor

jdonszelmann commented May 19, 2024

I was looking through the code of the experimental implementation today (#117978), and I found something that surprised me. The experimental implementation of delegation has an id in it:
image

However, a Delegation is used as an ItemKind, and any ItemKind is associated with an Item. Now every Item already has an ID associated with it:
image

I looked through all the code, and I think for delegation the Item id is never used, and the Delegation specific one is always used but seems redundant.

Let me know if I'm misunderstanding something here, maybe I am, but I just wanted to let you know in case it's redundant.

@petrochenkov
Copy link
Contributor Author

@jdonszelmann
In

trait Trait { fn method(); }

impl Trait for Struct {
  reuse some::method;
}

the same Resolver::partial_res_map table keeps resolutions for both some::method and Trait::method (pointing from the impl to the trait).
The former uses the Delegation's id as a key, and the latter uses Item's id as a key, so they need different ids.

The Delegation's id can be removed if a separate table is added for associated item resolutions in impls, instead of reusing partial_res_map.

@petrochenkov
Copy link
Contributor Author

I'll update the list of subtasks in the issue a bit later, but for now I'll just post one of them for @Bryanskiy .

Suppose we want to delegate implementation of a whole trait with 10 methods, 5 of them are by ref and 5 are by mutable ref.

struct Wrapper(Inner);

impl Trait for Wrapper {
  fn ref1() { Trait::ref1(&self.0) }
  fn ref2() { Trait::ref2(&self.0) }
  fn ref3() { Trait::ref3(&self.0) }
  fn ref4() { Trait::ref4(&self.0) }
  fn ref5() { Trait::ref5(&self.0) }

  fn mut1() { Trait::mut1(&mut self.0) }
  fn mut2() { Trait::mut2(&mut self.0) }
  fn mut3() { Trait::mut3(&mut self.0) }
  fn mut4() { Trait::mut4(&mut self.0) }
  fn mut5() { Trait::mut5(&mut self.0) }
}

Right now we cannot do it using glob delegation and an explicit path, due to the difference between &self.0 and &mut self.0.
We have to write

impl Trait for Wrapper {
  reuse Trait::* { &self.0 }
  reuse Trait::{mut1, mut2, mut3, mut4, mut5} { &mut self.0 }
}

Ideally we would use just

impl Trait for Wrapper {
  reuse Trait::* { self.0 }
}

and self.0 would autoref/autoderef/coerce automatically.

For that in the generated body Trait::method(self.0) we should treat self.0 as if it was a method receiver in a method call, rather than a regular argument.
The difference with existing method calls is that in self.0.method() the method is resolved as a part of applying conversions to self.0, but in our case it is already pre-resolved to Trait::method.
The types team should know how to do it correctly.

(This was mentioned in the RFC in application to a different case - https://github.com/petrochenkov/rfcs/blob/delegation/text/0000-fn-delegation.md#the-proposed-algorithm.)

@jdonszelmann
Copy link
Contributor

@petrochenkov that makes sense. Would you like it if I gave it a comment or a slightly more descriptive name?

@petrochenkov
Copy link
Contributor Author

The separate table approach may actually be a better way.

jieyouxu added a commit to jieyouxu/rust that referenced this issue Jun 19, 2024
delegation: Implement glob delegation

Support delegating to all trait methods in one go.
Overriding globs with explicit definitions is also supported.

The implementation is generally based on the design from rust-lang/rfcs#3530 (comment), but unlike with list delegation in rust-lang#123413 we cannot expand glob delegation eagerly.
We have to enqueue it into the queue of unexpanded macros (most other macros are processed this way too), and then a glob delegation waits in that queue until its trait path is resolved, and enough code expands to generate the identifier list produced from the glob.

Glob delegation is only allowed in impls, and can only point to traits.
Supporting it in other places gives very little practical benefit, but significantly raises the implementation complexity.

Part of rust-lang#118212.
jieyouxu added a commit to jieyouxu/rust that referenced this issue Jun 19, 2024
delegation: Implement glob delegation

Support delegating to all trait methods in one go.
Overriding globs with explicit definitions is also supported.

The implementation is generally based on the design from rust-lang/rfcs#3530 (comment), but unlike with list delegation in rust-lang#123413 we cannot expand glob delegation eagerly.
We have to enqueue it into the queue of unexpanded macros (most other macros are processed this way too), and then a glob delegation waits in that queue until its trait path is resolved, and enough code expands to generate the identifier list produced from the glob.

Glob delegation is only allowed in impls, and can only point to traits.
Supporting it in other places gives very little practical benefit, but significantly raises the implementation complexity.

Part of rust-lang#118212.
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Jun 19, 2024
Rollup merge of rust-lang#124135 - petrochenkov:deleglob, r=fmease

delegation: Implement glob delegation

Support delegating to all trait methods in one go.
Overriding globs with explicit definitions is also supported.

The implementation is generally based on the design from rust-lang/rfcs#3530 (comment), but unlike with list delegation in rust-lang#123413 we cannot expand glob delegation eagerly.
We have to enqueue it into the queue of unexpanded macros (most other macros are processed this way too), and then a glob delegation waits in that queue until its trait path is resolved, and enough code expands to generate the identifier list produced from the glob.

Glob delegation is only allowed in impls, and can only point to traits.
Supporting it in other places gives very little practical benefit, but significantly raises the implementation complexity.

Part of rust-lang#118212.
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Jul 15, 2024
…etrochenkov

Delegation: support coercion for target expression

(solves rust-lang#118212 (comment))

The implementation consist of 3 parts. Firstly, method call is generated instead of fully qualified call in AST->HIR lowering if there were no generic arguments or `Qpath` were provided. These restrictions are imposed due to the loss of information after desugaring. For example in

```rust
trait Trait {
  fn foo(&self) {}
}

reuse <u8 as Trait>::foo;
```

We would like to generate such a code:

```rust
fn foo<u8: Trait>(x: &u8) {
  x.foo(x)
}
```

however, the signature is inherited during HIR analysis where `u8` was discarded.

Secondly, traits found in the callee path are also added to `trait_map`. This is done to avoid the side effects of converting body into method calls:

```rust
mod inner {
    pub trait Trait {
      fn foo(&self) {}
    }
}

reuse inner::Trait::foo; // Ok, `Trait` is in scope for implicit method call.
```

Finally, applicable candidates are filtered with pre-resolved method during method lookup.

P.S In the future, we would like to avoid restrictions on the callee path by `Self` autoref/autoderef in fully qualified calls, but at the moment it didn't work out.

r? `@petrochenkov`
tgross35 added a commit to tgross35/rust that referenced this issue Jul 16, 2024
…ompiler-errors

Delegation: support coercion for target expression

(solves rust-lang#118212 (comment))

The implementation consist of 2 parts. Firstly, method call is generated instead of fully qualified call in AST->HIR lowering if there were no generic arguments or `Qpath` were provided. These restrictions are imposed due to the loss of information after desugaring. For example in

```rust
trait Trait {
  fn foo(&self) {}
}

reuse <u8 as Trait>::foo;
```

We would like to generate such a code:

```rust
fn foo<u8: Trait>(x: &u8) {
  x.foo(x)
}
```

however, the signature is inherited during HIR analysis where `u8` was discarded.

Then, we probe the single pre-resolved method.

P.S In the future, we would like to avoid restrictions on the callee path by `Self` autoref/autoderef in fully qualified calls, but at the moment it didn't work out.

r? `@petrochenkov`
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Jul 17, 2024
Rollup merge of rust-lang#126699 - Bryanskiy:delegation-coercion, r=compiler-errors

Delegation: support coercion for target expression

(solves rust-lang#118212 (comment))

The implementation consist of 2 parts. Firstly, method call is generated instead of fully qualified call in AST->HIR lowering if there were no generic arguments or `Qpath` were provided. These restrictions are imposed due to the loss of information after desugaring. For example in

```rust
trait Trait {
  fn foo(&self) {}
}

reuse <u8 as Trait>::foo;
```

We would like to generate such a code:

```rust
fn foo<u8: Trait>(x: &u8) {
  x.foo(x)
}
```

however, the signature is inherited during HIR analysis where `u8` was discarded.

Then, we probe the single pre-resolved method.

P.S In the future, we would like to avoid restrictions on the callee path by `Self` autoref/autoderef in fully qualified calls, but at the moment it didn't work out.

r? `@petrochenkov`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
B-experimental Blocker: In-tree experiment; RFC pending or unneeded. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. F-fn_delegation `#![feature(fn_delegation)]` S-tracking-impl-incomplete Status: The implementation is incomplete. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

3 participants