From 414ebeaeea13d37bcd59473d11660169286b7cd5 Mon Sep 17 00:00:00 2001 From: Stephen Skeirik Date: Mon, 17 Jun 2024 17:01:38 -0400 Subject: [PATCH] add serde derive Serialize to stable_mir --- Cargo.lock | 1 + compiler/stable_mir/Cargo.toml | 1 + compiler/stable_mir/src/abi.rs | 35 ++--- compiler/stable_mir/src/crate_def.rs | 3 +- compiler/stable_mir/src/lib.rs | 10 +- compiler/stable_mir/src/mir/alloc.rs | 5 +- compiler/stable_mir/src/mir/body.rs | 81 +++++------ compiler/stable_mir/src/mir/mono.rs | 10 +- compiler/stable_mir/src/target.rs | 7 +- compiler/stable_mir/src/ty.rs | 153 ++++++++++++--------- tests/ui-fulldeps/stable-mir/smir_serde.rs | 75 ++++++++++ 11 files changed, 242 insertions(+), 139 deletions(-) create mode 100644 tests/ui-fulldeps/stable-mir/smir_serde.rs diff --git a/Cargo.lock b/Cargo.lock index 241a37588b409..24caf5cd3e67f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5254,6 +5254,7 @@ name = "stable_mir" version = "0.1.0-preview" dependencies = [ "scoped-tls", + "serde", ] [[package]] diff --git a/compiler/stable_mir/Cargo.toml b/compiler/stable_mir/Cargo.toml index 4ed6115273653..2edb3f140d7ac 100644 --- a/compiler/stable_mir/Cargo.toml +++ b/compiler/stable_mir/Cargo.toml @@ -5,3 +5,4 @@ edition = "2021" [dependencies] scoped-tls = "1.0" +serde = { version = "1.0.125", features = [ "derive" ] } diff --git a/compiler/stable_mir/src/abi.rs b/compiler/stable_mir/src/abi.rs index e1c14fe0b380b..c003ec1fbc920 100644 --- a/compiler/stable_mir/src/abi.rs +++ b/compiler/stable_mir/src/abi.rs @@ -5,12 +5,13 @@ use crate::target::{MachineInfo, MachineSize as Size}; use crate::ty::{Align, IndexedVal, Ty, VariantIdx}; use crate::Error; use crate::Opaque; +use serde::Serialize; use std::fmt::{self, Debug}; use std::num::NonZero; use std::ops::RangeInclusive; /// A function ABI definition. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub struct FnAbi { /// The types of each argument. pub args: Vec, @@ -31,7 +32,7 @@ pub struct FnAbi { } /// Information about the ABI of a function's argument, or return value. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub struct ArgAbi { pub ty: Ty, pub layout: Layout, @@ -39,7 +40,7 @@ pub struct ArgAbi { } /// How a function argument should be passed in to the target function. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub enum PassMode { /// Ignore the argument. /// @@ -60,14 +61,14 @@ pub enum PassMode { } /// The layout of a type, alongside the type itself. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub struct TyAndLayout { pub ty: Ty, pub layout: Layout, } /// The layout of a type in memory. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub struct LayoutShape { /// The fields location withing the layout pub fields: FieldsShape, @@ -108,7 +109,7 @@ impl LayoutShape { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub struct Layout(usize); impl Layout { @@ -127,7 +128,7 @@ impl IndexedVal for Layout { } /// Describes how the fields of a type are shaped in memory. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub enum FieldsShape { /// Scalar primitives and `!`, which never have fields. Primitive, @@ -177,7 +178,7 @@ impl FieldsShape { } } -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub enum VariantsShape { /// Single enum variants, structs/tuples, unions, and all non-ADTs. Single { index: VariantIdx }, @@ -196,7 +197,7 @@ pub enum VariantsShape { }, } -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub enum TagEncoding { /// The tag directly stores the discriminant, but possibly with a smaller layout /// (so converting the tag to the discriminant can require sign extension). @@ -221,7 +222,7 @@ pub enum TagEncoding { /// Describes how values of the type are passed by target ABIs, /// in terms of categories of C types there are ABI rules for. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub enum ValueAbi { Uninhabited, Scalar(Scalar), @@ -250,7 +251,7 @@ impl ValueAbi { } /// Information about one scalar component of a Rust type. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize)] pub enum Scalar { Initialized { /// The primitive type used to represent this value. @@ -280,7 +281,7 @@ impl Scalar { } /// Fundamental unit of memory access and layout. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize)] pub enum Primitive { /// The `bool` is the signedness of the `Integer` type. /// @@ -310,7 +311,7 @@ impl Primitive { } /// Enum representing the existing integer lengths. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)] pub enum IntegerLength { I8, I16, @@ -320,7 +321,7 @@ pub enum IntegerLength { } /// Enum representing the existing float lengths. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)] pub enum FloatLength { F16, F32, @@ -354,7 +355,7 @@ impl FloatLength { /// An identifier that specifies the address space that some operation /// should operate on. Special address spaces have an effect on code generation, /// depending on the target and the address spaces it implements. -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)] pub struct AddressSpace(pub u32); impl AddressSpace { @@ -369,7 +370,7 @@ impl AddressSpace { /// sequence: /// /// 254 (-2), 255 (-1), 0, 1, 2 -#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize)] pub struct WrappingRange { pub start: u128, pub end: u128, @@ -420,7 +421,7 @@ impl Debug for WrappingRange { } /// General language calling conventions. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub enum CallConvention { C, Rust, diff --git a/compiler/stable_mir/src/crate_def.rs b/compiler/stable_mir/src/crate_def.rs index 67752a5e629f3..a7cebc4c132ba 100644 --- a/compiler/stable_mir/src/crate_def.rs +++ b/compiler/stable_mir/src/crate_def.rs @@ -3,9 +3,10 @@ use crate::ty::{GenericArgs, Span, Ty}; use crate::{with, Crate, Symbol}; +use serde::Serialize; /// A unique identification number for each item accessible for the current compilation unit. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize)] pub struct DefId(pub(crate) usize); /// A trait for retrieving information about a particular definition. diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index 8385856ae532d..fe745326d819a 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -27,6 +27,7 @@ pub use crate::error::*; use crate::mir::Body; use crate::mir::Mutability; use crate::ty::{ForeignModuleDef, ImplDef, IndexedVal, Span, TraitDef, Ty}; +use serde::Serialize; pub mod abi; #[macro_use] @@ -74,7 +75,7 @@ pub type TraitDecls = Vec; pub type ImplTraitDecls = Vec; /// Holds information about a crate. -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug, Serialize)] pub struct Crate { pub id: CrateNum, pub name: Symbol, @@ -98,7 +99,7 @@ impl Crate { } } -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize)] pub enum ItemKind { Fn, Static, @@ -106,7 +107,7 @@ pub enum ItemKind { Ctor(CtorKind), } -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize)] pub enum CtorKind { Const, Fn, @@ -116,6 +117,7 @@ pub type Filename = String; crate_def_with_ty! { /// Holds information about an item in a crate. + #[derive(Serialize)] pub CrateItem; } @@ -188,7 +190,7 @@ pub fn all_trait_impls() -> ImplTraitDecls { } /// A type that provides internal information but that can still be used for debug purpose. -#[derive(Clone, PartialEq, Eq, Hash)] +#[derive(Clone, PartialEq, Eq, Hash, Serialize)] pub struct Opaque(String); impl std::fmt::Display for Opaque { diff --git a/compiler/stable_mir/src/mir/alloc.rs b/compiler/stable_mir/src/mir/alloc.rs index ef1568151f2e6..9e0cac67f0aa3 100644 --- a/compiler/stable_mir/src/mir/alloc.rs +++ b/compiler/stable_mir/src/mir/alloc.rs @@ -4,11 +4,12 @@ use crate::mir::mono::{Instance, StaticDef}; use crate::target::{Endian, MachineInfo}; use crate::ty::{Allocation, Binder, ExistentialTraitRef, IndexedVal, Ty}; use crate::{with, Error}; +use serde::Serialize; use std::io::Read; /// An allocation in the SMIR global memory can be either a function pointer, /// a static, or a "real" allocation with some data in it. -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize)] pub enum GlobalAlloc { /// The alloc ID is used as a function pointer. Function(Instance), @@ -41,7 +42,7 @@ impl GlobalAlloc { } /// A unique identification number for each provenance -#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)] pub struct AllocId(usize); impl IndexedVal for AllocId { diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index e0f9e7ae67a0f..f7457ecd38f4c 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -5,10 +5,11 @@ use crate::ty::{ TyConst, TyKind, VariantIdx, }; use crate::{Error, Opaque, Span, Symbol}; +use serde::Serialize; use std::io; /// The SMIR representation of a single function. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize)] pub struct Body { pub blocks: Vec, @@ -104,20 +105,20 @@ impl Body { type LocalDecls = Vec; -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct LocalDecl { pub ty: Ty, pub span: Span, pub mutability: Mutability, } -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug, Serialize)] pub struct BasicBlock { pub statements: Vec, pub terminator: Terminator, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct Terminator { pub kind: TerminatorKind, pub span: Span, @@ -131,7 +132,7 @@ impl Terminator { pub type Successors = Vec; -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum TerminatorKind { Goto { target: BasicBlockIdx, @@ -221,7 +222,7 @@ impl TerminatorKind { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct InlineAsmOperand { pub in_value: Option, pub out_place: Option, @@ -230,7 +231,7 @@ pub struct InlineAsmOperand { pub raw_rpr: String, } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] pub enum UnwindAction { Continue, Unreachable, @@ -238,7 +239,7 @@ pub enum UnwindAction { Cleanup(BasicBlockIdx), } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum AssertMessage { BoundsCheck { len: Operand, index: Operand }, Overflow(BinOp, Operand, Operand), @@ -307,7 +308,7 @@ impl AssertMessage { } } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] pub enum BinOp { Add, AddUnchecked, @@ -342,7 +343,7 @@ impl BinOp { } } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] pub enum UnOp { Not, Neg, @@ -357,20 +358,20 @@ impl UnOp { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum CoroutineKind { Desugared(CoroutineDesugaring, CoroutineSource), Coroutine(Movability), } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] pub enum CoroutineSource { Block, Closure, Fn, } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] pub enum CoroutineDesugaring { Async, @@ -386,7 +387,7 @@ pub(crate) type LocalDefId = Opaque; pub(crate) type Coverage = Opaque; /// The FakeReadCause describes the type of pattern why a FakeRead statement exists. -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum FakeReadCause { ForMatchGuard, ForMatchedPlace(LocalDefId), @@ -396,7 +397,7 @@ pub enum FakeReadCause { } /// Describes what kind of retag is to be performed -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub enum RetagKind { FnEntry, TwoPhase, @@ -404,7 +405,7 @@ pub enum RetagKind { Default, } -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub enum Variance { Covariant, Invariant, @@ -412,26 +413,26 @@ pub enum Variance { Bivariant, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct CopyNonOverlapping { pub src: Operand, pub dst: Operand, pub count: Operand, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum NonDivergingIntrinsic { Assume(Operand), CopyNonOverlapping(CopyNonOverlapping), } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct Statement { pub kind: StatementKind, pub span: Span, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum StatementKind { Assign(Place, Rvalue), FakeRead(FakeReadCause, Place), @@ -448,7 +449,7 @@ pub enum StatementKind { Nop, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum Rvalue { /// Creates a pointer with the indicated mutability to the place. /// @@ -622,7 +623,7 @@ impl Rvalue { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum AggregateKind { Array(Ty), Tuple, @@ -633,14 +634,14 @@ pub enum AggregateKind { RawPtr(Ty, Mutability), } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum Operand { Copy(Place), Move(Place), Constant(ConstOperand), } -#[derive(Clone, Eq, PartialEq)] +#[derive(Clone, Eq, PartialEq, Serialize)] pub struct Place { pub local: Local, /// projection out of a place (access a field, deref a pointer, etc) @@ -653,7 +654,7 @@ impl From for Place { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct ConstOperand { pub span: Span, pub user_ty: Option, @@ -661,7 +662,7 @@ pub struct ConstOperand { } /// Debug information pertaining to a user variable. -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct VarDebugInfo { /// The variable name. pub name: Symbol, @@ -703,19 +704,19 @@ impl VarDebugInfo { pub type SourceScope = u32; -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct SourceInfo { pub span: Span, pub scope: SourceScope, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct VarDebugInfoFragment { pub ty: Ty, pub projection: Vec, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum VarDebugInfoContents { Place(Place), Const(ConstOperand), @@ -726,7 +727,7 @@ pub enum VarDebugInfoContents { // ProjectionElem) and user-provided type annotations (for which the projection elements // are of type ProjectionElem<(), ()>). In SMIR we don't need this generality, so we just use // ProjectionElem for Places. -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum ProjectionElem { /// Dereference projections (e.g. `*_1`) project to the address referenced by the base place. Deref, @@ -800,7 +801,7 @@ pub enum ProjectionElem { Subtype(Ty), } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct UserTypeProjection { pub base: UserTypeAnnotationIndex, @@ -830,7 +831,7 @@ pub type FieldIdx = usize; type UserTypeAnnotationIndex = usize; /// The possible branch sites of a [TerminatorKind::SwitchInt]. -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct SwitchTargets { /// The conditional branches where the first element represents the value that guards this /// branch, and the second element is the branch target. @@ -867,7 +868,7 @@ impl SwitchTargets { } } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] pub enum BorrowKind { /// Data must be immutable and is aliasable. Shared, @@ -894,14 +895,14 @@ impl BorrowKind { } } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] pub enum MutBorrowKind { Default, TwoPhaseBorrow, ClosureCapture, } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] pub enum FakeBorrowKind { /// A shared (deep) borrow. Data must be immutable and is aliasable. Deep, @@ -912,19 +913,19 @@ pub enum FakeBorrowKind { Shallow, } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub enum Mutability { Not, Mut, } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] pub enum Safety { Safe, Unsafe, } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] pub enum PointerCoercion { /// Go from a fn-item type to a fn-pointer type. ReifyFnPointer, @@ -951,7 +952,7 @@ pub enum PointerCoercion { Unsize, } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] pub enum CastKind { // FIXME(smir-rename): rename this to PointerExposeProvenance PointerExposeAddress, @@ -967,7 +968,7 @@ pub enum CastKind { Transmute, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum NullOp { /// Returns the size of a value of that type. SizeOf, diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs index 572f1499c5a5c..c23293388f933 100644 --- a/compiler/stable_mir/src/mir/mono.rs +++ b/compiler/stable_mir/src/mir/mono.rs @@ -3,17 +3,18 @@ use crate::crate_def::CrateDef; use crate::mir::Body; use crate::ty::{Allocation, ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty}; use crate::{with, CrateItem, DefId, Error, ItemKind, Opaque, Symbol}; +use serde::Serialize; use std::fmt::{Debug, Formatter}; use std::io; -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub enum MonoItem { Fn(Instance), Static(StaticDef), GlobalAsm(Opaque), } -#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize)] pub struct Instance { /// The type of instance. pub kind: InstanceKind, @@ -22,7 +23,7 @@ pub struct Instance { pub def: InstanceDef, } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub enum InstanceKind { /// A user defined item. Item, @@ -240,7 +241,7 @@ impl From for CrateItem { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)] pub struct InstanceDef(usize); impl CrateDef for InstanceDef { @@ -251,6 +252,7 @@ impl CrateDef for InstanceDef { crate_def! { /// Holds information about a static variable definition. + #[derive(Serialize)] pub StaticDef; } diff --git a/compiler/stable_mir/src/target.rs b/compiler/stable_mir/src/target.rs index e00a418c54039..9fb5e046abc3c 100644 --- a/compiler/stable_mir/src/target.rs +++ b/compiler/stable_mir/src/target.rs @@ -1,9 +1,10 @@ //! Provide information about the machine that this is being compiled into. use crate::compiler_interface::with; +use serde::Serialize; /// The properties of the target machine being compiled into. -#[derive(Clone, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq, Serialize)] pub struct MachineInfo { pub endian: Endian, pub pointer_width: MachineSize, @@ -23,14 +24,14 @@ impl MachineInfo { } } -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy, Clone, PartialEq, Eq, Serialize)] pub enum Endian { Little, Big, } /// Represent the size of a component. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)] pub struct MachineSize { num_bits: usize, } diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 8c120a96e75b1..9c8921da52ff9 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -8,10 +8,11 @@ use crate::mir::alloc::{read_target_int, read_target_uint, AllocId}; use crate::mir::mono::StaticDef; use crate::target::MachineInfo; use crate::{Filename, Opaque}; +use serde::Serialize; use std::fmt::{self, Debug, Display, Formatter}; use std::ops::Range; -#[derive(Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize)] pub struct Ty(usize); impl Debug for Ty { @@ -100,13 +101,13 @@ impl Ty { } /// Represents a pattern in the type system -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum Pattern { Range { start: Option, end: Option, include_end: bool }, } /// Represents a constant in the type system -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct TyConst { pub(crate) kind: TyConstKind, pub id: TyConstId, @@ -133,7 +134,7 @@ impl TyConst { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum TyConstKind { Param(ParamConst), Bound(DebruijnIndex, BoundVar), @@ -144,11 +145,11 @@ pub enum TyConstKind { ZSTValue(Ty), } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] pub struct TyConstId(usize); /// Represents a constant in MIR -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct MirConst { /// The constant kind. pub(crate) kind: ConstantKind, @@ -205,17 +206,17 @@ impl MirConst { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] pub struct MirConstId(usize); type Ident = Opaque; -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct Region { pub kind: RegionKind, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum RegionKind { ReEarlyParam(EarlyParamRegion), ReBound(DebruijnIndex, BoundRegion), @@ -226,7 +227,7 @@ pub enum RegionKind { pub(crate) type DebruijnIndex = u32; -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct EarlyParamRegion { pub index: u32, pub name: Symbol, @@ -234,7 +235,7 @@ pub struct EarlyParamRegion { pub(crate) type BoundVar = u32; -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct BoundRegion { pub var: BoundVar, pub kind: BoundRegionKind, @@ -242,13 +243,13 @@ pub struct BoundRegion { pub(crate) type UniverseIndex = u32; -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct Placeholder { pub universe: UniverseIndex, pub bound: T, } -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, PartialEq, Eq, Serialize)] pub struct Span(usize); impl Debug for Span { @@ -272,7 +273,7 @@ impl Span { } } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, Serialize)] /// Information you get from `Span` in a struct form. /// Line and col start from 1. pub struct LineInfo { @@ -282,7 +283,7 @@ pub struct LineInfo { pub end_col: usize, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum TyKind { RigidTy(RigidTy), Alias(AliasKind, AliasTy), @@ -521,7 +522,7 @@ pub struct TypeAndMut { pub mutability: Mutability, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum RigidTy { Bool, Char, @@ -560,7 +561,7 @@ impl From for TyKind { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] pub enum IntTy { Isize, I8, @@ -583,7 +584,7 @@ impl IntTy { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] pub enum UintTy { Usize, U8, @@ -606,19 +607,20 @@ impl UintTy { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] pub enum FloatTy { F32, F64, } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] pub enum Movability { Static, Movable, } crate_def! { + #[derive(Serialize)] pub ForeignModuleDef; } @@ -641,6 +643,7 @@ impl ForeignModule { crate_def_with_ty! { /// Hold information about a ForeignItem in a crate. + #[derive(Serialize)] pub ForeignDef; } @@ -650,7 +653,7 @@ impl ForeignDef { } } -#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)] pub enum ForeignItemKind { Fn(FnDef), Static(StaticDef), @@ -659,6 +662,7 @@ pub enum ForeignItemKind { crate_def_with_ty! { /// Hold information about a function definition in a crate. + #[derive(Serialize)] pub FnDef; } @@ -692,6 +696,7 @@ impl FnDef { } crate_def_with_ty! { + #[derive(Serialize)] pub IntrinsicDef; } @@ -716,26 +721,31 @@ impl From for FnDef { } crate_def! { + #[derive(Serialize)] pub ClosureDef; } crate_def! { + #[derive(Serialize)] pub CoroutineDef; } crate_def! { + #[derive(Serialize)] pub ParamDef; } crate_def! { + #[derive(Serialize)] pub BrNamedDef; } -crate_def_with_ty! { +crate_def! { + #[derive(Serialize)] pub AdtDef; } -#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)] pub enum AdtKind { Enum, Union, @@ -789,7 +799,7 @@ impl AdtDef { } /// Definition of a variant, which can be either a struct / union field or an enum variant. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)] pub struct VariantDef { /// The variant index. /// @@ -818,7 +828,7 @@ impl VariantDef { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct FieldDef { /// The field definition. /// @@ -869,11 +879,13 @@ impl AdtKind { } crate_def! { + #[derive(Serialize)] pub AliasDef; } crate_def! { /// A trait's definition. + #[derive(Serialize)] pub TraitDef; } @@ -884,15 +896,18 @@ impl TraitDef { } crate_def! { + #[derive(Serialize)] pub GenericDef; } crate_def_with_ty! { + #[derive(Serialize)] pub ConstDef; } crate_def! { /// A trait impl definition. + #[derive(Serialize)] pub ImplDef; } @@ -904,15 +919,17 @@ impl ImplDef { } crate_def! { + #[derive(Serialize)] pub RegionDef; } crate_def! { + #[derive(Serialize)] pub CoroutineWitnessDef; } /// A list of generic arguments. -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct GenericArgs(pub Vec); impl std::ops::Index for GenericArgs { @@ -931,7 +948,7 @@ impl std::ops::Index for GenericArgs { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum GenericArgKind { Lifetime(Region), Type(Ty), @@ -968,13 +985,13 @@ impl GenericArgKind { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum TermKind { Type(Ty), Const(TyConst), } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum AliasKind { Projection, Inherent, @@ -982,13 +999,13 @@ pub enum AliasKind { Weak, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct AliasTy { pub def_id: AliasDef, pub args: GenericArgs, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct AliasTerm { pub def_id: AliasDef, pub args: GenericArgs, @@ -1006,7 +1023,7 @@ impl PolyFnSig { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct FnSig { pub inputs_and_output: Vec, pub c_variadic: bool, @@ -1024,7 +1041,7 @@ impl FnSig { } } -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug, Serialize)] pub enum Abi { Rust, C { unwind: bool }, @@ -1054,7 +1071,7 @@ pub enum Abi { } /// A binder represents a possibly generic type and its bound vars. -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct Binder { pub value: T, pub bound_vars: Vec, @@ -1094,38 +1111,38 @@ impl Binder { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct EarlyBinder { pub value: T, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum BoundVariableKind { Ty(BoundTyKind), Region(BoundRegionKind), Const, } -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug, Serialize)] pub enum BoundTyKind { Anon, Param(ParamDef, String), } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum BoundRegionKind { BrAnon, BrNamed(BrNamedDef, String), BrEnv, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum DynKind { Dyn, DynStar, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum ExistentialPredicate { Trait(ExistentialTraitRef), Projection(ExistentialProjection), @@ -1135,7 +1152,7 @@ pub enum ExistentialPredicate { /// An existential reference to a trait where `Self` is not included. /// /// The `generic_args` will include any other known argument. -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct ExistentialTraitRef { pub def_id: TraitDef, pub generic_args: GenericArgs, @@ -1153,20 +1170,20 @@ impl ExistentialTraitRef { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct ExistentialProjection { pub def_id: TraitDef, pub generic_args: GenericArgs, pub term: TermKind, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct ParamTy { pub index: u32, pub name: String, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct BoundTy { pub var: usize, pub kind: BoundTyKind, @@ -1177,7 +1194,7 @@ pub type Bytes = Vec>; /// Size in bytes. pub type Size = usize; -#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)] pub struct Prov(pub AllocId); pub type Align = u64; @@ -1185,14 +1202,14 @@ pub type Promoted = u32; pub type InitMaskMaterialized = Vec; /// Stores the provenance information of pointers stored in memory. -#[derive(Clone, Debug, Eq, PartialEq, Hash)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub struct ProvenanceMap { /// Provenance in this map applies from the given offset for an entire pointer-size worth of /// bytes. Two entries in this map are always at least a pointer size apart. pub ptrs: Vec<(Size, Prov)>, } -#[derive(Clone, Debug, Eq, PartialEq, Hash)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub struct Allocation { pub bytes: Bytes, pub provenance: ProvenanceMap, @@ -1268,7 +1285,7 @@ impl Allocation { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum ConstantKind { Ty(TyConst), Allocated(Allocation), @@ -1279,27 +1296,27 @@ pub enum ConstantKind { ZeroSized, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct ParamConst { pub index: u32, pub name: String, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct UnevaluatedConst { pub def: ConstDef, pub args: GenericArgs, pub promoted: Option, } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] pub enum TraitSpecializationKind { None, Marker, AlwaysApplicable, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct TraitDecl { pub def_id: TraitDef, pub safety: Safety, @@ -1332,7 +1349,7 @@ impl TraitDecl { pub type ImplTrait = EarlyBinder; /// A complete reference to a trait, i.e., one where `Self` is known. -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct TraitRef { pub def_id: TraitDef, /// The generic arguments for this definition. @@ -1366,7 +1383,7 @@ impl TraitRef { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct Generics { pub parent: Option, pub parent_count: usize, @@ -1377,14 +1394,14 @@ pub struct Generics { pub host_effect_index: Option, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum GenericParamDefKind { Lifetime, Type { has_default: bool, synthetic: bool }, Const { has_default: bool }, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct GenericParamDef { pub name: super::Symbol, pub def_id: GenericDef, @@ -1398,7 +1415,7 @@ pub struct GenericPredicates { pub predicates: Vec<(PredicateKind, Span)>, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum PredicateKind { Clause(ClauseKind), ObjectSafe(TraitDef), @@ -1409,7 +1426,7 @@ pub enum PredicateKind { AliasRelate(TermKind, TermKind, AliasRelationDirection), } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum ClauseKind { Trait(TraitPredicate), RegionOutlives(RegionOutlivesPredicate), @@ -1420,57 +1437,57 @@ pub enum ClauseKind { ConstEvaluatable(TyConst), } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum ClosureKind { Fn, FnMut, FnOnce, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct SubtypePredicate { pub a: Ty, pub b: Ty, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct CoercePredicate { pub a: Ty, pub b: Ty, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum AliasRelationDirection { Equate, Subtype, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct TraitPredicate { pub trait_ref: TraitRef, pub polarity: PredicatePolarity, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct OutlivesPredicate(pub A, pub B); pub type RegionOutlivesPredicate = OutlivesPredicate; pub type TypeOutlivesPredicate = OutlivesPredicate; -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct ProjectionPredicate { pub projection_term: AliasTerm, pub term: TermKind, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum ImplPolarity { Positive, Negative, Reservation, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum PredicatePolarity { Positive, Negative, @@ -1513,7 +1530,7 @@ index_impl!(Span); /// `a` is in the variant with the `VariantIdx` of `0`, /// `c` is in the variant with the `VariantIdx` of `1`, and /// `g` is in the variant with the `VariantIdx` of `0`. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)] pub struct VariantIdx(usize); index_impl!(VariantIdx); diff --git a/tests/ui-fulldeps/stable-mir/smir_serde.rs b/tests/ui-fulldeps/stable-mir/smir_serde.rs new file mode 100644 index 0000000000000..957d840f7a241 --- /dev/null +++ b/tests/ui-fulldeps/stable-mir/smir_serde.rs @@ -0,0 +1,75 @@ +//@ run-pass +//! Test that users are able to use serialize stable MIR constructs. + +//@ ignore-stage1 +//@ ignore-cross-compile +//@ ignore-remote +//@ ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837 +//@ edition: 2021 + +#![feature(rustc_private)] +#![feature(assert_matches)] +#![feature(control_flow_enum)] + +#[macro_use] +extern crate rustc_smir; +extern crate rustc_driver; +extern crate rustc_interface; +extern crate rustc_middle; +extern crate stable_mir; +extern crate serde; +extern crate serde_json; + +use rustc_middle::ty::TyCtxt; +use rustc_smir::rustc_internal; +use stable_mir::mir::Body; +use std::io::{Write, BufWriter}; +use std::ops::ControlFlow; +use serde_json::to_string; + + +const CRATE_NAME: &str = "input"; + +fn serialize_to_json(_tcx: TyCtxt<'_>) -> ControlFlow<()> { + let path = "output.json"; + let mut writer = BufWriter::new(std::fs::File::create(path) + .expect("Failed to create path")); + let local_crate = stable_mir::local_crate(); + let items: Vec = stable_mir::all_local_items() + .iter() + .map(|item| { item.body() }) + .collect(); + let crate_data = ( local_crate.name, items ); + writer.write_all(to_string(&crate_data) + .expect("serde_json failed") + .as_bytes()).expect("JSON serialization failed"); + ControlFlow::Continue(()) +} + +/// This test will generate and analyze a dummy crate using the stable mir. +/// For that, it will first write the dummy crate into a file. +/// Then it will create a `StableMir` using custom arguments and then +/// it will run the compiler. +fn main() { + let path = "internal_input.rs"; + generate_input(&path).unwrap(); + let args = vec![ + "rustc".to_string(), + "--crate-name".to_string(), + CRATE_NAME.to_string(), + path.to_string(), + ]; + run_with_tcx!(args, serialize_to_json).unwrap(); +} + +fn generate_input(path: &str) -> std::io::Result<()> { + let mut file = std::fs::File::create(path)?; + write!( + file, + r#" + pub fn main() {{ + }} + "# + )?; + Ok(()) +}