@@ -506,6 +506,56 @@ pub struct MiriResponse {
506506 pub exit_detail : String ,
507507}
508508
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+
509559#[ derive( Debug , Clone ) ]
510560pub struct WithOutput < T > {
511561 pub response : T ,
@@ -721,6 +771,33 @@ where
721771 . await
722772 }
723773
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+
724801 pub async fn idle ( & mut self ) -> Result < ( ) > {
725802 let Self {
726803 stable,
@@ -1217,6 +1294,78 @@ impl Container {
12171294 } )
12181295 }
12191296
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+
12201369 async fn spawn_cargo_task (
12211370 & self ,
12221371 token : CancellationToken ,
@@ -1528,6 +1677,47 @@ pub enum MiriError {
15281677 CargoFailed { source : SpawnCargoError } ,
15291678}
15301679
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+
15311721struct SpawnCargo {
15321722 task : JoinHandle < Result < ExecuteCommandResponse , SpawnCargoError > > ,
15331723 stdin_tx : mpsc:: Sender < String > ,
@@ -3129,6 +3319,42 @@ mod tests {
31293319 Ok ( ( ) )
31303320 }
31313321
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+
31323358 // The next set of tests are broader than the functionality of a
31333359 // single operation.
31343360
0 commit comments