diff --git a/src/lib.rs b/src/lib.rs index dd553212..b946d121 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -741,7 +741,8 @@ macro_rules! stack_try_pin_init { /// the following modifications is expected: /// - Fields that you want to initialize in-place have to use `<-` instead of `:`. /// - You can use `_: { /* run any user-code here */ },` anywhere where you can place fields in -/// order to run arbitrary code. +/// order to run arbitrary code. Bindings present here will be visible to field initializers that +/// follow. /// - In front of the initializer you can write `&this in` to have access to a [`NonNull`] /// pointer named `this` inside of the initializer. /// - Using struct update syntax one can place `..Zeroable::init_zeroed()` at the very end of the diff --git a/src/macros.rs b/src/macros.rs index 682c61a5..c20b94db 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1290,7 +1290,7 @@ macro_rules! __init_internal { // arbitrary code block @munch_fields(_: { $($code:tt)* }, $($rest:tt)*), ) => { - { $($code)* } + $($code)*; $crate::__init_internal!(init_slot($($use_data)?): @data($data), @slot($slot), diff --git a/tests/ui/compile-fail/init/invalid_init.stderr b/tests/ui/compile-fail/init/invalid_init.stderr index b80864de..c0096e88 100644 --- a/tests/ui/compile-fail/init/invalid_init.stderr +++ b/tests/ui/compile-fail/init/invalid_init.stderr @@ -10,7 +10,15 @@ error[E0277]: the trait bound `impl pin_init::PinInit: Init` is not sa | |______the trait `Init` is not implemented for `impl pin_init::PinInit` | required by a bound introduced by this call | - = help: the following other types implement trait `Init`: - ChainInit - Result +help: the following other types implement trait `Init` + --> src/lib.rs + | + | / unsafe impl Init for ChainInit + | | where + | | I: Init, + | | F: FnOnce(&mut T) -> Result<(), E>, + | |_______________________________________^ `ChainInit` +... + | unsafe impl Init for Result { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Result` = note: this error originates in the macro `$crate::__init_internal` which comes from the expansion of the macro `init` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/compile-fail/init/wrong_generics2.stderr b/tests/ui/compile-fail/init/wrong_generics2.stderr index e8eab623..e33b29be 100644 --- a/tests/ui/compile-fail/init/wrong_generics2.stderr +++ b/tests/ui/compile-fail/init/wrong_generics2.stderr @@ -9,12 +9,12 @@ error: struct literal body without path | = note: this error originates in the macro `$crate::__init_internal` which comes from the expansion of the macro `init` (in Nightly builds, run with -Z macro-backtrace for more info) help: you might have forgotten to add the struct literal inside the block - --> src/macros.rs - | - ~ ::core::ptr::write($slot, $t { SomeStruct { - |2 $($acc)* - ~ } }); + --> $DIR/src/macros.rs | + ~ ::core::ptr::write($slot, $t { SomeStruct { + | $($acc)* + ~ } }); + | error: expected one of `)`, `,`, `.`, `?`, or an operator, found `{` --> tests/ui/compile-fail/init/wrong_generics2.rs:7:13 diff --git a/tests/ui/compile-fail/pin_data/missing_pin.stderr b/tests/ui/compile-fail/pin_data/missing_pin.stderr index fdc96d73..e239f937 100644 --- a/tests/ui/compile-fail/pin_data/missing_pin.stderr +++ b/tests/ui/compile-fail/pin_data/missing_pin.stderr @@ -7,8 +7,12 @@ error[E0277]: the trait bound `impl PinInit: Init` is not satis 13 | | }) | |__________^ the trait `Init` is not implemented for `impl PinInit` | - = help: the trait `Init` is not implemented for `impl PinInit` - but trait `Init, Infallible>` is implemented for it +help: the trait `Init` is not implemented for `impl PinInit` + but trait `Init, Infallible>` is implemented for it + --> src/lib.rs + | + | unsafe impl Init for T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: for that trait implementation, expected `impl PinInit`, found `usize` note: required by a bound in `__ThePinData::a` --> tests/ui/compile-fail/pin_data/missing_pin.rs:4:1 diff --git a/tests/underscore.rs b/tests/underscore.rs index 583b3b39..822acf7d 100644 --- a/tests/underscore.rs +++ b/tests/underscore.rs @@ -1,7 +1,91 @@ -use pin_init::{try_init, Init}; +#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))] +use core::cell::Cell; +use pin_init::*; -pub struct Foo { - x: u64, +#[derive(Debug)] +struct Error; + +#[pin_data] +#[derive(Debug)] +struct Foo { + a: usize, + b: usize, +} + +struct Bar; + +impl Bar { + fn new() -> Result { + Ok(Self) + } + fn make_a(&self) -> usize { + 10 + } + fn make_b(&self) -> usize { + 20 + } +} + +fn error(_bar: &Bar) -> Result<(), Error> { + Err(Error) +} + +fn ok(_bar: &Bar) -> Result<(), Error> { + Ok(()) +} + +#[test] +fn delay() { + let state = &Cell::new(3); + let init = pin_init!(Foo { + _: { + let x = state.get(); + let y = x + 1; + }, + a: x, + b: y, + }); + state.set(42); + stack_pin_init!(let foo = init); + assert_eq!(foo.a, 42); + assert_eq!(foo.b, 43); +} + +#[test] +fn error_user() { + let bar = Bar; + stack_try_pin_init!(let foo = try_pin_init!(Foo { + _: { error(&bar)? }, + a: 1, + b: 2, + }? Error)); + + assert!(foo.is_err()); +} + +#[test] +fn ok_user() { + let bar = Bar; + stack_try_pin_init!(let foo = try_pin_init!(Foo { + _: { ok(&bar)? }, + a: 1, + b: 2, + }? Error)); + + assert_eq!(foo.unwrap().a, 1); +} + +#[test] +fn split() { + stack_try_pin_init!(let foo = try_pin_init!(Foo { + _: { let bar = Bar::new()? }, + a: bar.make_a(), + b: bar.make_b(), + }? Error)); + + let foo = foo.unwrap(); + assert_eq!(foo.a, 10); + assert_eq!(foo.b, 20); } fn foo() -> bool { @@ -13,19 +97,26 @@ fn bar() -> bool { } impl Foo { - pub fn new() -> impl Init { + pub fn late_error_new() -> impl Init { try_init!(Self { _: { if foo() { - return Err(()); + return Err(Error); } }, - x: 0, + a: 0, _: { if bar() { - return Err(()); + return Err(Error); } - } - }? ()) + }, + b: 0, + }? Error) } } + +#[test] +fn late_error() { + stack_try_pin_init!(let foo = Foo::late_error_new()); + assert!(foo.is_err()); +}