@@ -506,6 +506,56 @@ pub struct MiriResponse {
506
506
pub exit_detail : String ,
507
507
}
508
508
509
+ #[ derive( Debug , Clone ) ]
510
+ pub struct MacroExpansionRequest {
511
+ pub channel : Channel ,
512
+ pub crate_type : CrateType ,
513
+ pub edition : Edition ,
514
+ pub code : String ,
515
+ }
516
+
517
+ impl MacroExpansionRequest {
518
+ pub ( crate ) fn delete_previous_main_request ( & self ) -> DeleteFileRequest {
519
+ delete_previous_primary_file_request ( self . crate_type )
520
+ }
521
+
522
+ pub ( crate ) fn write_main_request ( & self ) -> WriteFileRequest {
523
+ write_primary_file_request ( self . crate_type , & self . code )
524
+ }
525
+
526
+ pub ( crate ) fn execute_cargo_request ( & self ) -> ExecuteCommandRequest {
527
+ ExecuteCommandRequest {
528
+ cmd : "cargo" . to_owned ( ) ,
529
+ args : [ "rustc" , "--" , "-Zunpretty=expanded" ]
530
+ . map ( str:: to_owned)
531
+ . to_vec ( ) ,
532
+ envs : Default :: default ( ) ,
533
+ cwd : None ,
534
+ }
535
+ }
536
+ }
537
+
538
+ impl CargoTomlModifier for MacroExpansionRequest {
539
+ fn modify_cargo_toml ( & self , mut cargo_toml : toml:: Value ) -> toml:: Value {
540
+ if self . edition == Edition :: Rust2024 {
541
+ cargo_toml = modify_cargo_toml:: set_feature_edition2024 ( cargo_toml) ;
542
+ }
543
+
544
+ cargo_toml = modify_cargo_toml:: set_edition ( cargo_toml, self . edition . to_cargo_toml_key ( ) ) ;
545
+
546
+ if let Some ( crate_type) = self . crate_type . to_library_cargo_toml_key ( ) {
547
+ cargo_toml = modify_cargo_toml:: set_crate_type ( cargo_toml, crate_type) ;
548
+ }
549
+ cargo_toml
550
+ }
551
+ }
552
+
553
+ #[ derive( Debug , Clone ) ]
554
+ pub struct MacroExpansionResponse {
555
+ pub success : bool ,
556
+ pub exit_detail : String ,
557
+ }
558
+
509
559
#[ derive( Debug , Clone ) ]
510
560
pub struct WithOutput < T > {
511
561
pub response : T ,
@@ -721,6 +771,33 @@ where
721
771
. await
722
772
}
723
773
774
+ pub async fn macro_expansion (
775
+ & self ,
776
+ request : MacroExpansionRequest ,
777
+ ) -> Result < WithOutput < MacroExpansionResponse > , MacroExpansionError > {
778
+ use macro_expansion_error:: * ;
779
+
780
+ self . select_channel ( request. channel )
781
+ . await
782
+ . context ( CouldNotStartContainerSnafu ) ?
783
+ . macro_expansion ( request)
784
+ . await
785
+ }
786
+
787
+ pub async fn begin_macro_expansion (
788
+ & self ,
789
+ token : CancellationToken ,
790
+ request : MacroExpansionRequest ,
791
+ ) -> Result < ActiveMacroExpansion , MacroExpansionError > {
792
+ use macro_expansion_error:: * ;
793
+
794
+ self . select_channel ( request. channel )
795
+ . await
796
+ . context ( CouldNotStartContainerSnafu ) ?
797
+ . begin_macro_expansion ( token, request)
798
+ . await
799
+ }
800
+
724
801
pub async fn idle ( & mut self ) -> Result < ( ) > {
725
802
let Self {
726
803
stable,
@@ -1217,6 +1294,78 @@ impl Container {
1217
1294
} )
1218
1295
}
1219
1296
1297
+ async fn macro_expansion (
1298
+ & self ,
1299
+ request : MacroExpansionRequest ,
1300
+ ) -> Result < WithOutput < MacroExpansionResponse > , MacroExpansionError > {
1301
+ let token = Default :: default ( ) ;
1302
+
1303
+ let ActiveMacroExpansion {
1304
+ task,
1305
+ stdout_rx,
1306
+ stderr_rx,
1307
+ } = self . begin_macro_expansion ( token, request) . await ?;
1308
+
1309
+ WithOutput :: try_absorb ( task, stdout_rx, stderr_rx) . await
1310
+ }
1311
+
1312
+ async fn begin_macro_expansion (
1313
+ & self ,
1314
+ token : CancellationToken ,
1315
+ request : MacroExpansionRequest ,
1316
+ ) -> Result < ActiveMacroExpansion , MacroExpansionError > {
1317
+ use macro_expansion_error:: * ;
1318
+
1319
+ let delete_previous_main = request. delete_previous_main_request ( ) ;
1320
+ let write_main = request. write_main_request ( ) ;
1321
+ let execute_cargo = request. execute_cargo_request ( ) ;
1322
+
1323
+ let delete_previous_main = self . commander . one ( delete_previous_main) ;
1324
+ let write_main = self . commander . one ( write_main) ;
1325
+ let modify_cargo_toml = self . modify_cargo_toml . modify_for ( & request) ;
1326
+
1327
+ let ( delete_previous_main, write_main, modify_cargo_toml) =
1328
+ join ! ( delete_previous_main, write_main, modify_cargo_toml) ;
1329
+
1330
+ delete_previous_main. context ( CouldNotDeletePreviousCodeSnafu ) ?;
1331
+ write_main. context ( CouldNotWriteCodeSnafu ) ?;
1332
+ modify_cargo_toml. context ( CouldNotModifyCargoTomlSnafu ) ?;
1333
+
1334
+ let SpawnCargo {
1335
+ task,
1336
+ stdin_tx,
1337
+ stdout_rx,
1338
+ stderr_rx,
1339
+ } = self
1340
+ . spawn_cargo_task ( token, execute_cargo)
1341
+ . await
1342
+ . context ( CouldNotStartCargoSnafu ) ?;
1343
+
1344
+ drop ( stdin_tx) ;
1345
+
1346
+ let task = async move {
1347
+ let ExecuteCommandResponse {
1348
+ success,
1349
+ exit_detail,
1350
+ } = task
1351
+ . await
1352
+ . context ( CargoTaskPanickedSnafu ) ?
1353
+ . context ( CargoFailedSnafu ) ?;
1354
+
1355
+ Ok ( MacroExpansionResponse {
1356
+ success,
1357
+ exit_detail,
1358
+ } )
1359
+ }
1360
+ . boxed ( ) ;
1361
+
1362
+ Ok ( ActiveMacroExpansion {
1363
+ task,
1364
+ stdout_rx,
1365
+ stderr_rx,
1366
+ } )
1367
+ }
1368
+
1220
1369
async fn spawn_cargo_task (
1221
1370
& self ,
1222
1371
token : CancellationToken ,
@@ -1528,6 +1677,47 @@ pub enum MiriError {
1528
1677
CargoFailed { source : SpawnCargoError } ,
1529
1678
}
1530
1679
1680
+ pub struct ActiveMacroExpansion {
1681
+ pub task : BoxFuture < ' static , Result < MacroExpansionResponse , MacroExpansionError > > ,
1682
+ pub stdout_rx : mpsc:: Receiver < String > ,
1683
+ pub stderr_rx : mpsc:: Receiver < String > ,
1684
+ }
1685
+
1686
+ impl fmt:: Debug for ActiveMacroExpansion {
1687
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1688
+ f. debug_struct ( "ActiveMacroExpansion" )
1689
+ . field ( "task" , & "<future>" )
1690
+ . field ( "stdout_rx" , & self . stdout_rx )
1691
+ . field ( "stderr_rx" , & self . stderr_rx )
1692
+ . finish ( )
1693
+ }
1694
+ }
1695
+
1696
+ #[ derive( Debug , Snafu ) ]
1697
+ #[ snafu( module) ]
1698
+ pub enum MacroExpansionError {
1699
+ #[ snafu( display( "Could not start the container" ) ) ]
1700
+ CouldNotStartContainer { source : Error } ,
1701
+
1702
+ #[ snafu( display( "Could not modify Cargo.toml" ) ) ]
1703
+ CouldNotModifyCargoToml { source : ModifyCargoTomlError } ,
1704
+
1705
+ #[ snafu( display( "Could not delete previous source code" ) ) ]
1706
+ CouldNotDeletePreviousCode { source : CommanderError } ,
1707
+
1708
+ #[ snafu( display( "Could not write source code" ) ) ]
1709
+ CouldNotWriteCode { source : CommanderError } ,
1710
+
1711
+ #[ snafu( display( "Could not start Cargo task" ) ) ]
1712
+ CouldNotStartCargo { source : SpawnCargoError } ,
1713
+
1714
+ #[ snafu( display( "The Cargo task panicked" ) ) ]
1715
+ CargoTaskPanicked { source : tokio:: task:: JoinError } ,
1716
+
1717
+ #[ snafu( display( "Cargo task failed" ) ) ]
1718
+ CargoFailed { source : SpawnCargoError } ,
1719
+ }
1720
+
1531
1721
struct SpawnCargo {
1532
1722
task : JoinHandle < Result < ExecuteCommandResponse , SpawnCargoError > > ,
1533
1723
stdin_tx : mpsc:: Sender < String > ,
@@ -3129,6 +3319,42 @@ mod tests {
3129
3319
Ok ( ( ) )
3130
3320
}
3131
3321
3322
+ const ARBITRARY_MACRO_EXPANSION_REQUEST : MacroExpansionRequest = MacroExpansionRequest {
3323
+ channel : Channel :: Nightly ,
3324
+ crate_type : CrateType :: Library ( LibraryType :: Cdylib ) ,
3325
+ edition : Edition :: Rust2018 ,
3326
+ code : String :: new ( ) ,
3327
+ } ;
3328
+
3329
+ #[ tokio:: test]
3330
+ #[ snafu:: report]
3331
+ async fn macro_expansion ( ) -> Result < ( ) > {
3332
+ let coordinator = new_coordinator ( ) . await ;
3333
+
3334
+ let req = MacroExpansionRequest {
3335
+ code : r#"
3336
+ #[derive(Debug)]
3337
+ struct Dummy;
3338
+
3339
+ fn main() { println!("Hello!"); }
3340
+ "#
3341
+ . into ( ) ,
3342
+ ..ARBITRARY_MACRO_EXPANSION_REQUEST
3343
+ } ;
3344
+
3345
+ let response = coordinator
3346
+ . macro_expansion ( req)
3347
+ . with_timeout ( )
3348
+ . await
3349
+ . unwrap ( ) ;
3350
+
3351
+ assert ! ( response. success, "stderr: {}" , response. stderr) ;
3352
+ assert_contains ! ( response. stdout, "impl ::core::fmt::Debug for Dummy" ) ;
3353
+ assert_contains ! ( response. stdout, "Formatter::write_str" ) ;
3354
+
3355
+ Ok ( ( ) )
3356
+ }
3357
+
3132
3358
// The next set of tests are broader than the functionality of a
3133
3359
// single operation.
3134
3360
0 commit comments