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

Accept a closure for with in lieu of a path for fields #310

Merged
merged 6 commits into from
Oct 7, 2024

Conversation

TedDriggs
Copy link
Owner

Fixes #309

This has some issues, so it's not yet ready to merge:

  1. It doesn't work for all the places where with is used.
  2. I'm not thrilled with the introduction of new locals to support this, and am wondering if there's a way to write it that better encapsulates the desired behavior.

@Veetaha
Copy link
Contributor

Veetaha commented Oct 2, 2024

If you'd like to avoid using a local variable there are two ways to do that:

The naive way is to just cast the expression with as: #closure as fn(...). Although the as operator is a bit more powerful for this task, because it's meant for potential type coersions, while in this case we just need a type hint.

Another way to do that is with ::core::convert::identity::<fn(...) -> _>(#closure) which provides a hint for the expression via the identity function parameter.

I think there doesn't have to be any special case for closure/non-closure expressions. If you pass a function path to the identity function, it'll compile just fine, so there shoudln't be a special case.

@TedDriggs
Copy link
Owner Author

Using identity seems to work well. It also solves one of the main barriers to allowing arbitrary expressions in this position, though I'm still hesitant to allow arbitrary expressions until I can test the isolation and the quality of the error messages when the user does something wrong.

@TedDriggs
Copy link
Owner Author

@Veetaha I've updated this using core::convert::identity, added a compile-fail test to show what happens if you try to access locals, and renamed darling_core::codegen::Field::with_path to be the more descriptive with_callable.

Copy link
Contributor

@Veetaha Veetaha left a comment

Choose a reason for hiding this comment

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

Thanks! LGTM, except docs should need a small update

@TedDriggs
Copy link
Owner Author

@Veetaha ugh, one more question for you: Any ideas on how to fix the output of the compiletest so it will pass both locally and on CI? It seems the issue is the path on the last line of the error, potentially due to the use of $RUST vs a specified path?

@Veetaha
Copy link
Contributor

Veetaha commented Oct 7, 2024

I haven't used compiletest. I assume it's an older equivalent of trybuild, which I've been using for my tests. Maybe it will work out of the box with trybuild?

The version of trybuild, that supports 1.56 MSRV is 1.0.89 (can be found in the table here).

Try adding this test, maybe it'll work:

#[test]
fn ui() {
    let t = trybuild::TestCases::new();
    t.compile_fail("tests/compile-fail/*.rs");
}

@TedDriggs
Copy link
Owner Author

TedDriggs commented Oct 7, 2024

I'm using trybuild - the compiletests is just the test directory name, since I didn't want to confuse it by recycling the name.

It appears that locally updating trybuild to the latest version triggers this error, so my theory about it being a missing environment variable may have been wrong. Added a commit bumping trybuild to latest version.

@TedDriggs
Copy link
Owner Author

Okay, it looks like trybuild@1.0.89 is the sweet spot where builds on 1.56.0 still work, though why CI is ever trying to build with trybuild on 1.56.0 is unclear to me, as that dependency is only present for cfg(compiletests) and that's only used on 1.77.0.

@Veetaha
Copy link
Contributor

Veetaha commented Oct 7, 2024

why CI is ever trying to build with trybuild on 1.56.0 is unclear to me, as that dependency is only present for cfg(compiletests) and that's only used on 1.77.0

Do you mean this error?:

error: failed to select a version for the requirement `toml = "^0.8"`
candidate versions found which didn't match: 0.5.11, 0.5.10, 0.5.9, ...
location searched: crates.io index
required by package `trybuild v1.0.99`

If yes, then that's expected because this happens not at the building stage, but when updating the crates.io index. cargo needs to make sure the dependency exists (even if it's under a cfg), and create a single Cargo.lock file which lists the pinned dependency versions assuming all dependencies are used.

Although, I must admit, I don't understand why cargo 1.56 can't find the toml ^0.8 crate versions. There clearly are entries for these versions in the index

@TedDriggs
Copy link
Owner Author

Yes, that's the error I meant. Thanks for the explanation. For now, it seems that leaving the dependency at 1.0.89 is sufficient. If it ever breaks, that'll probably be a sign it's time to bump darling's MSRV for its next release.

I've updated examples, tests, and CHANGELOG for this feature; I didn't see any places in the actual docs where a change was needed. I do want to look at expanding this to cover the other with scenarios, though I don't think that needs to be part of this PR.

@TedDriggs TedDriggs changed the title WIP: Accept a closure for with in lieu of a path for fields Accept a closure for with in lieu of a path for fields Oct 7, 2024
@TedDriggs TedDriggs merged commit b746a0c into master Oct 7, 2024
24 checks passed
@TedDriggs TedDriggs deleted the with-closure branch October 7, 2024 17:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Accept an arbitrary expression that returns a callable object in #[darling(with)]
2 participants