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

Feat: Ability to emit sync-compatible Rust code. #6040

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
ba89c76
Feat: Ability to emit sync-compatible Rust code.
MikaelMayer Jan 10, 2025
03adc1b
Merge branch 'master' into fix-5969-sync-for-rust
MikaelMayer Jan 10, 2025
fb43df6
Added missing Cargo.toml
MikaelMayer Jan 11, 2025
1c6bb02
Merge branch 'master' into fix-5969-sync-for-rust
MikaelMayer Jan 11, 2025
7f4c46e
Fixed cargo file
MikaelMayer Jan 11, 2025
ca0e2c1
Merge branch 'fix-5969-sync-for-rust' of https://github.com/dafny-lan…
MikaelMayer Jan 11, 2025
bbaf95d
Added missing main
MikaelMayer Jan 13, 2025
d6eb4cb
Unified the two downcast methods
MikaelMayer Jan 15, 2025
cd8b320
Ensure Rc can coerce too
MikaelMayer Jan 15, 2025
d0ad506
Fixed CI test
MikaelMayer Jan 16, 2025
e661f2e
Merge branch 'master' into fix-5969-sync-for-rust
MikaelMayer Jan 16, 2025
e837fb3
fix: remove deadlock from Sequence (#6056)
ajewellamz Jan 16, 2025
be5b210
Added necessary traits for trait generation (Sync + Send)
MikaelMayer Jan 16, 2025
a03084d
Latest version
MikaelMayer Jan 16, 2025
b490b29
Merge branch 'master' into fix-5969-sync-for-rust
MikaelMayer Jan 17, 2025
72bc49d
Other version with Sync and Send on top of Any
MikaelMayer Jan 21, 2025
dfb533a
Merge branch 'fix-5969-sync-for-rust' of https://github.com/dafny-lan…
MikaelMayer Jan 21, 2025
10c60f4
Support for sync-ed functions
MikaelMayer Jan 21, 2025
7255d3d
Support for functions in sync
MikaelMayer Jan 21, 2025
d07403b
Merge branch 'master' into fix-5969-sync-for-rust
MikaelMayer Jan 22, 2025
f8225f9
Fixed functions
MikaelMayer Jan 22, 2025
7429b75
Merge branch 'master' into fix-5969-sync-for-rust
MikaelMayer Jan 23, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ module {:extern "Defs"} DafnyToRustCompilerDefinitions {
datatype PointerType = Raw | RcMut
datatype CharType = UTF16 | UTF32
datatype RootType = RootCrate | RootPath(moduleName: string)
datatype SyncType = NoSync | Sync

datatype GenTypeContext =
GenTypeContext(forTraitParents: bool)
Expand Down Expand Up @@ -594,6 +595,8 @@ module {:extern "Defs"} DafnyToRustCompilerDefinitions {
}

function CoerceImpl(
rc: R.Type -> R.Type,
Copy link
Member

Choose a reason for hiding this comment

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

Consider using a term distinct from "RC" throughout for the abstract concept that will be mapped to either Rc or Arc. It's easy to get the concepts confused here, and that might have been a factor in initially missing that IsRc was testing for the wrong thing.

rcNew: R.Expr -> R.Expr,
rTypeParamsDecls: seq<R.TypeParamDecl>,
datatypeName: string,
datatypeType: R.Type,
Expand All @@ -614,15 +617,15 @@ module {:extern "Defs"} DafnyToRustCompilerDefinitions {
"coerce", rCoerceTypeParams,
coerceArguments,
Some(
R.Rc(
rc(
R.ImplType(
R.FnType(
[datatypeType],
R.TypeApp(R.TIdentifier(datatypeName), coerceTypes))))),
Some(
R.RcNew(R.Lambda([R.Formal("this", R.SelfOwned)],
Some(R.TypeApp(R.TIdentifier(datatypeName), coerceTypes)),
coerceImplBody)))))]
rcNew(R.Lambda([R.Formal("this", R.SelfOwned)],
Some(R.TypeApp(R.TIdentifier(datatypeName), coerceTypes)),
coerceImplBody)))))]
))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ module FactorPathsOptimizationTest {
"dummy", std_any_Any.AsType(),
StmtExpr(
DeclareVar(
MUT, "doit", Some(std_rc_Rc.AsType().Apply1(TIdentifier("unknown"))),
MUT, "doit", Some(RcType.Apply1(TIdentifier("unknown"))),
Some(
Identifier("something").ApplyType(
[ DynType(std_default_Default.AsType())
Expand All @@ -95,7 +95,7 @@ module FactorPathsOptimizationTest {
NoDoc, NoAttr,
"onemodule", [
UseDecl(Use(PUB, std_any_Any)),
UseDecl(Use(PUB, std_rc_Rc)),
UseDecl(Use(PUB, RcPath)),
UseDecl(Use(PUB, std_default_Default)),
UseDecl(Use(PUB, dafny_runtime.MSel("rd"))),
UseDecl(Use(PUB, dafny_runtime.MSel("DafnyString"))),
Expand Down
21 changes: 6 additions & 15 deletions Source/DafnyCore/Backends/Rust/Dafny-compiler-rust-rast.dfy
Original file line number Diff line number Diff line change
Expand Up @@ -608,8 +608,10 @@ module RAST
const SelfBorrowedMut := BorrowedMut(SelfOwned)

const RcPath := std.MSel("rc").MSel("Rc")
const ArcPath := std.MSel("sync").MSel("Arc")

const RcType := RcPath.AsType()
const ArcType := ArcPath.AsType()

const ObjectPath: Path := dafny_runtime.MSel("Object")

Expand All @@ -629,9 +631,6 @@ module RAST
PtrPath.AsType().Apply([underlying])
}

function Rc(underlying: Type): Type {
TypeApp(RcType, [underlying])
}
function RefCell(underlying: Type): Type {
TypeApp(RefcellType, [underlying])
}
Expand Down Expand Up @@ -822,7 +821,7 @@ module RAST
|| (TMetaData? && (copySemantics || display.CanReadWithoutClone()))
}
predicate IsRcOrBorrowedRc() {
(TypeApp? && baseName == RcType) ||
IsRc() ||
(Borrowed? && underlying.IsRcOrBorrowedRc()) ||
(TSynonym? && base.IsRcOrBorrowedRc())
}
Expand Down Expand Up @@ -1054,7 +1053,7 @@ module RAST
}

predicate IsRc() {
this.TypeApp? && this.baseName == RcType && |arguments| == 1
TypeApp? && (baseName == RcType || baseName == ArcType) && |arguments| == 1
}
function RcUnderlying(): Type
requires IsRc()
Expand Down Expand Up @@ -1083,6 +1082,8 @@ module RAST
const Eq := std.MSel("cmp").MSel("Eq").AsType()
const Hash := std.MSel("hash").MSel("Hash").AsType()
const DafnyInt := dafny_runtime.MSel("DafnyInt").AsType()
const SyncType := std.MSel("marker").MSel("Sync").AsType()
const SendType := std.MSel("marker").MSel("Send").AsType()

function SystemTuple(elements: seq<Expr>): Expr {
var size := Strings.OfNat(|elements|);
Expand Down Expand Up @@ -1889,18 +1890,8 @@ module RAST
MaybePlaceboPath.FSel("from").Apply1(underlying)
}

const std_rc := std.MSel("rc")

const std_rc_Rc := std_rc.MSel("Rc")

const std_rc_Rc_new := std_rc_Rc.FSel("new")

const std_default_Default_default := std_default_Default.FSel("default").Apply0()

function RcNew(underlying: Expr): Expr {
Call(std_rc_Rc_new, [underlying])
}

function IntoUsize(underlying: Expr): Expr {
dafny_runtime.MSel("DafnyUsize").FSel("into_usize").Apply1(underlying)
}
Expand Down
72 changes: 49 additions & 23 deletions Source/DafnyCore/Backends/Rust/Dafny-compiler-rust.dfy
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ module {:extern "DCOMP"} DafnyToRustCompiler {
const charType: CharType
const pointerType: PointerType
const rootType: RootType
const syncType: SyncType

const thisFile: R.Path := if rootType.RootCrate? then R.crate else R.crate.MSel(rootType.moduleName)
const DafnyChar := if charType.UTF32? then "DafnyChar" else "DafnyCharUTF16"
Expand Down Expand Up @@ -59,15 +60,28 @@ module {:extern "DCOMP"} DafnyToRustCompiler {
const downcast :=
if pointerType.Raw? then "cast!" else "cast_object!"

const rcPath := if syncType.NoSync? then R.RcPath else R.ArcPath
const rcType := rcPath.AsType()
const rcExpr := rcPath.AsExpr()

const rc := (underlying: R.Type) => rcType.Apply([underlying])
const rcNew := (underlying: R.Expr) => rcExpr.FSel("new").Apply([underlying])
const SyncSendType := R.IntersectionType(R.SyncType, R.SendType)
const AnyTrait := if syncType.NoSync? then
R.dafny_runtime.MSel("Any").AsType()
else
R.IntersectionType(R.dafny_runtime.MSel("Any").AsType(), SyncSendType)
const DynAny := R.dafny_runtime.MSel("DynAny").AsType()

var error: Option<string>

var optimizations: seq<R.Mod -> R.Mod>

constructor(charType: CharType, pointerType: PointerType, rootType: RootType) {
constructor(charType: CharType, pointerType: PointerType, rootType: RootType, syncType: SyncType) {
this.charType := charType;
this.pointerType := pointerType;
this.rootType := rootType;
this.syncType := syncType;
this.error := None; // If error, then the generated code contains <i>Unsupported: .*</i>
this.optimizations := [
ExpressionOptimization.apply,
Expand Down Expand Up @@ -479,13 +493,13 @@ module {:extern "DCOMP"} DafnyToRustCompiler {
R.ImplDecl(
R.ImplFor(
rTypeParamsDecls,
R.dafny_runtime.MSel(Upcast).AsType().Apply([R.DynType(R.AnyTrait)]),
R.dafny_runtime.MSel(Upcast).AsType().Apply([DynAny]),
R.TypeApp(genSelfPath, rTypeParams),
[
R.ImplMemberMacro(
R.dafny_runtime
.MSel(UpcastFnMacro).AsExpr()
.Apply1(R.ExprFromType(R.DynType(R.AnyTrait))))
.Apply1(R.ExprFromType(DynAny)))
]
)
)
Expand Down Expand Up @@ -884,7 +898,7 @@ module {:extern "DCOMP"} DafnyToRustCompiler {
if |ctor.args| == 0 {
var instantiation := R.StructBuild(R.Identifier(datatypeName).FSel(escapeName(ctor.name)), []);
if IsRcWrapped(c.attributes) {
instantiation := R.RcNew(instantiation);
instantiation := rcNew(instantiation);
}
singletonConstructors := singletonConstructors + [
instantiation
Expand Down Expand Up @@ -1048,7 +1062,7 @@ module {:extern "DCOMP"} DafnyToRustCompiler {
coerceArguments := coerceArguments + [
R.Formal(
coerceFormal,
R.Rc(R.IntersectionType(R.ImplType(R.FnType([rTypeArg], rCoerceType)), R.StaticTrait)))
rc(R.IntersectionType(R.ImplType(R.FnType([rTypeArg], rCoerceType)), R.StaticTrait)))
];
}
if |unusedTypeParams| > 0 {
Expand Down Expand Up @@ -1225,14 +1239,14 @@ module {:extern "DCOMP"} DafnyToRustCompiler {
R.Identifier("this"),
coerceImplBodyCases);
s := s + [
CoerceImpl(rTypeParamsDecls, datatypeName, datatypeType, rCoerceTypeParams, coerceArguments, coerceTypes, coerceImplBody)
CoerceImpl(rc, rcNew, rTypeParamsDecls, datatypeName, datatypeType, rCoerceTypeParams, coerceArguments, coerceTypes, coerceImplBody)
];
}

if |singletonConstructors| == |c.ctors| {
var instantiationType :=
if IsRcWrapped(c.attributes) then
R.Rc(datatypeType)
rc(datatypeType)
else
datatypeType;
s := s + [
Expand Down Expand Up @@ -1388,7 +1402,7 @@ module {:extern "DCOMP"} DafnyToRustCompiler {
}
case Datatype(_) => {
if IsRcWrapped(resolved.attributes) {
s := R.Rc(s);
s := rc(s);
}
}
case Trait(GeneralTrait()) => {
Expand All @@ -1398,7 +1412,7 @@ module {:extern "DCOMP"} DafnyToRustCompiler {
}
case Trait(ObjectTrait()) => {
if resolved.path == [Ident.Ident(Name("_System")), Ident.Ident(Name("object"))] {
s := R.AnyTrait;
s := AnyTrait;
}
if !genTypeContext.forTraitParents {
s := Object(R.DynType(s));
Expand All @@ -1424,7 +1438,7 @@ module {:extern "DCOMP"} DafnyToRustCompiler {
}
}
case Object() => {
s := R.AnyTrait;
s := AnyTrait;
if !genTypeContext.forTraitParents {
s := Object(R.DynType(s));
}
Expand Down Expand Up @@ -1491,8 +1505,12 @@ module {:extern "DCOMP"} DafnyToRustCompiler {
}

var resultType := GenType(result, GenTypeContext.default());
var fnType := R.DynType(R.FnType(argTypes, resultType));
if syncType.Sync? {
fnType := R.IntersectionType(fnType, SyncSendType);
}
s :=
R.Rc(R.DynType(R.FnType(argTypes, resultType)));
rc(fnType);
}
case TypeArg(Ident(name)) => s := R.TIdentifier(escapeName(name));
case Primitive(p) => {
Expand Down Expand Up @@ -1608,7 +1626,7 @@ module {:extern "DCOMP"} DafnyToRustCompiler {
} else { // For Rc-defined datatypes
if enclosingType.UserDefined? && enclosingType.resolved.kind.Datatype?
&& IsRcWrapped(enclosingType.resolved.attributes) {
tpe := R.Borrowed(R.Rc(R.SelfOwned));
tpe := R.Borrowed(rc(R.SelfOwned));
} else if enclosingType.UserDefined? && enclosingType.resolved.kind.Newtype?
&& IsNewtypeCopy(enclosingType.resolved.kind.range) {
tpe := R.TMetaData(
Expand Down Expand Up @@ -2736,7 +2754,7 @@ module {:extern "DCOMP"} DafnyToRustCompiler {
assert !IsNewtype(fromTpe);
match (fromTpe, toTpe) {
case (Primitive(Int), Primitive(Real)) => {
r := R.RcNew(R.dafny_runtime.MSel("BigRational").AsExpr().FSel("from_integer").Apply1(r));
r := rcNew(R.dafny_runtime.MSel("BigRational").AsExpr().FSel("from_integer").Apply1(r));
r, resultingOwnership := FromOwned(r, expectedOwnership);
}
case (Primitive(Real), Primitive(Int)) => {
Expand Down Expand Up @@ -3328,7 +3346,7 @@ module {:extern "DCOMP"} DafnyToRustCompiler {
}
r := R.StructBuild(r, assignments);
if IsRcWrapped(datatypeType.attributes) {
r := R.RcNew(r);
r := rcNew(r);
}
r, resultingOwnership := FromOwned(r, expectedOwnership);
return;
Expand Down Expand Up @@ -3578,7 +3596,6 @@ module {:extern "DCOMP"} DafnyToRustCompiler {
case SelectFn(on, field, isDatatype, isStatic, isConstant, arguments) => {
// Transforms a function member into a lambda
var onExpr, onOwned, recIdents := GenExpr(on, selfIdent, env, OwnershipBorrowed);
var onString := onExpr.ToString(IND);

var lEnv := env;
var args := [];
Expand All @@ -3591,11 +3608,17 @@ module {:extern "DCOMP"} DafnyToRustCompiler {
parameters := parameters + [R.Formal(name, bTy)];
args := args + [(name, ty)];
}
var body :=
if isStatic then
onExpr.FSel(escapeVar(field))
else
R.Identifier("callTarget").Sel(escapeVar(field));
var body;
if isStatic {
body := onExpr.FSel(escapeVar(field));
} else {
body := R.Identifier("callTarget");
if !isDatatype {
body := read_macro.Apply1(body);
}
body := body.Sel(escapeVar(field));
}

if isConstant {
body := body.Apply0();
}
Expand Down Expand Up @@ -3628,10 +3651,13 @@ module {:extern "DCOMP"} DafnyToRustCompiler {
}

var typeShape := R.DynType(R.FnType(typeShapeArgs, R.TIdentifier("_")));
if syncType.Sync? {
typeShape := R.IntersectionType(typeShape, SyncSendType);
}

r := R.TypeAscription(
R.std_rc_Rc_new.Apply1(r),
R.std_rc_Rc.AsType().Apply([typeShape]));
rcNew(r),
rc(typeShape));
r, resultingOwnership := FromOwned(r, expectedOwnership);
readIdents := recIdents;
return;
Expand Down Expand Up @@ -3832,7 +3858,7 @@ module {:extern "DCOMP"} DafnyToRustCompiler {
var retTypeGen := GenType(retType, GenTypeContext.default());
r := R.Block(
allReadCloned.Then(
R.RcNew(
rcNew(
R.Lambda(params, Some(retTypeGen), R.Block(recursiveGen))
)
));
Expand Down
Loading
Loading