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

Honor rename-prefix for *external* Rust declarations #543

Merged
merged 5 commits into from
Feb 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
26 changes: 24 additions & 2 deletions lib/AstToMiniRust.ml
Original file line number Diff line number Diff line change
Expand Up @@ -412,8 +412,30 @@ let compress_prefix prefix =

(* Types *)

(* This is the name translation facility for things that are missing from the scope; typically,
external definitions that are to be implemented by hand.

Some background (current as of Feb 2025): things that *do* have a definition end up with Rust
name crate::foo::bar where `foo` is the file that the definition got assigned to, and `bar` is
the last component of the `lident`. So, for instance, if Hacl.Streaming.Keccak.hash_len ends up
in Rust *file* hash_sha3.rs, then it becomes crate::hash_sha3::hash_len and is emitted as `fn
hash_len` within that file. The environment knows about this. Notably, this means that
rename-prefix is completely ignored for Rust, for good reason -- there is a better namespacing
story.

Now for things that are completely external (e.g. assumed library, like LowStar.Endianness), this
is a different story -- how do we meaningfully steer the name generation towards the naming
scheme we *would like*?

So, here, for things that do not get the nice Rust namespacing, we *do* honor rename-prefix to
give the user a little more control over how things get emitted when they don't have definitions
in scope.*)
let translate_unknown_lid (m, n) =
let m = compress_prefix m in
let m =
match GlobalNames.rename_prefix (m, n) with
| Some m -> [ m ]
| None -> compress_prefix m
in
List.map String.lowercase_ascii m @ [ n ]

let borrow_kind_of_bool b: MiniRust.borrow_kind =
Expand Down Expand Up @@ -483,7 +505,7 @@ let translate_type env = translate_type_with_config env default_config
(* Expressions *)

(* Allocate a target Rust name for a definition named `lid` pertaining to file
(i.e. future rust module) `prefix`.
(i.e. future rust module) `env.prefix`.

We do something super simple: we only retain the last component of `lid` and
prefix it with the current namespace. This ensures that at Rust
Expand Down
2 changes: 2 additions & 0 deletions lib/GlobalNames.mli
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,5 @@ val camel_case: string -> string
val skip_prefix: Ast.lident -> bool

val keywords: string list

val rename_prefix: Ast.lident -> string option
6 changes: 5 additions & 1 deletion test/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ FSTAR = $(FSTAR_EXE) \
--trivial_pre_for_unannotated_effectful_fns false \
--cmi --warn_error -274

all: $(FILES) rust $(WASM_FILES) $(CUSTOM) ctypes-test sepcomp-test
all: $(FILES) rust $(WASM_FILES) $(CUSTOM) ctypes-test sepcomp-test rust-val-test

# Needs node
wasm: $(WASM_FILES)
Expand Down Expand Up @@ -267,6 +267,10 @@ sepcomp-test:
+$(MAKE) -C sepcomp
.PHONY: sepcomp-test

rust-val-test:
+$(MAKE) -C rust-val
.PHONY: rust-val-test

CTYPES_HAND_WRITTEN_FILES=Client.ml Makefile

.PHONY: $(LOWLEVEL_DIR)/Client.native
Expand Down
3 changes: 3 additions & 0 deletions test/rust-val/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*.exe
*.krml
rusttest.rs
4 changes: 4 additions & 0 deletions test/rust-val/AuxA.fsti
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module AuxA

val foo : bool -> bool

3 changes: 3 additions & 0 deletions test/rust-val/AuxB.fsti
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module AuxB

val bar : bool -> bool
70 changes: 70 additions & 0 deletions test/rust-val/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
RECENT_GCC = $(shell [ "$$(gcc -dumpversion | cut -c -1)" -ge 5 ] && echo yes)

ifeq (3.81,$(MAKE_VERSION))
$(error You seem to be using the OSX antiquated Make version. Hint: brew \
install make, then invoke gmake instead of make)
endif

FSTAR_EXE ?= fstar.exe

TEST_OPTS = -warn-error @4 -verbose -skip-makefiles
KRML_BIN = ../../_build/default/src/Karamel.exe
KRML = $(KRML_BIN) -fstar $(FSTAR_EXE) $(KOPTS) $(TEST_OPTS)
CACHE_DIR = .cache
FSTAR = $(FSTAR_EXE) --cache_checked_modules \
--cache_dir $(CACHE_DIR) \
--include ../../krmllib/compat --include ../../krmllib/obj \
--include ../../krmllib --include ../../runtime \
--ext context_pruning \
--already_cached 'Prims FStar C TestLib Spec.Loops -C.Compat -C.Nullity LowStar WasmSupport' \
--trivial_pre_for_unannotated_effectful_fns false \
--cmi --warn_error -274
SED=$(shell which gsed >/dev/null 2>&1 && echo gsed || echo sed)

all: rusttest.rust-test impl

impl:
+$(MAKE) -C $@

.PHONY: impl

FSTAR_FILES=$(wildcard *.fst *.fsti)

.PRECIOUS: %.krml

# Use F*'s dependency mechanism and fill out the missing rules.

ifndef MAKE_RESTARTS
ifndef NODEPEND
.depend: .FORCE
$(FSTAR) --dep full $(FSTAR_FILES) --extract 'krml:*,-Prims' --output_deps_to $@

.PHONY: .FORCE
.FORCE:
endif
endif

include .depend

$(CACHE_DIR)/%.checked: | .depend
$(FSTAR) $(OTHERFLAGS) $< && \
touch $@

%.krml: | .depend
$(FSTAR) $(OTHERFLAGS) --codegen krml \
--extract_module $(basename $(notdir $(subst .checked,,$<))) \
$(notdir $(subst .checked,,$<))

########
# Rust #
########

.PRECIOUS: %.rs
%.rs: $(ALL_KRML_FILES) $(KRML_BIN)
$(KRML) -minimal -bundle AuxA+AuxB=[rename=Aux,rename-prefix] -bundle $(notdir $(subst rust,Rust,$*))=\* \
-backend rust $(EXTRA) -tmpdir $(dir $@) $(filter %.krml,$^)
$(SED) -i 's/\(patterns..\)/\1\nmod aux; mod lowstar { pub mod ignore { pub fn ignore<T>(_x: T) {}}}\n/' $@
echo 'fn main () { let r = main_ (); if r != 0 { println!("main_ returned: {}\\n", r); panic!() } }' >> $@

%.rust-test: %.rs
rustc $< -o $*.exe && ./$*.exe
24 changes: 24 additions & 0 deletions test/rust-val/Rusttest.fst
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module Rusttest

module B = LowStar.Buffer
module HST = FStar.HyperStack.ST
module I32 = FStar.Int32

let test2 (b: B.buffer bool) : HST.Stack bool
(fun h -> B.live h b /\ B.length b == 1)
(fun _ _ _ -> True)
=
let x = B.index b C._zero_for_deref in
let r1 = AuxA.foo x in
let r2 = AuxB.bar x in
r1 && r2

let main_ () : HST.Stack I32.t
(fun _ -> True)
(fun _ _ _ -> True)
=
HST.push_frame ();
let b = B.alloca true 1ul in
let _ = test2 b in
HST.pop_frame ();
0l
15 changes: 15 additions & 0 deletions test/rust-val/aux.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(unused_assignments)]
#![allow(unreachable_patterns)]

pub fn foo(x: bool) -> bool
{
return !x;
}

pub fn bar(x: bool) -> bool
{
return x;
}
2 changes: 2 additions & 0 deletions test/rust-val/impl/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.rs
*.rlib
3 changes: 3 additions & 0 deletions test/rust-val/impl/AuxA.fst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module AuxA

let foo x = not x
3 changes: 3 additions & 0 deletions test/rust-val/impl/AuxB.fst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module AuxB

let bar x = x
64 changes: 64 additions & 0 deletions test/rust-val/impl/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
RECENT_GCC = $(shell [ "$$(gcc -dumpversion | cut -c -1)" -ge 5 ] && echo yes)

ifeq (3.81,$(MAKE_VERSION))
$(error You seem to be using the OSX antiquated Make version. Hint: brew \
install make, then invoke gmake instead of make)
endif

FSTAR_EXE ?= fstar.exe

TEST_OPTS = -warn-error @4 -verbose -skip-makefiles
KRML_BIN = ../../../_build/default/src/Karamel.exe
KRML = $(KRML_BIN) -fstar $(FSTAR_EXE) $(KOPTS) $(TEST_OPTS)
CACHE_DIR = .cache
FSTAR = $(FSTAR_EXE) --cache_checked_modules \
--cache_dir $(CACHE_DIR) \
--include ../../../krmllib/compat --include ../../../krmllib/obj \
--include ../../../krmllib --include ../../../runtime \
--include .. \
--ext context_pruning \
--already_cached 'Prims FStar C TestLib Spec.Loops -C.Compat -C.Nullity LowStar WasmSupport' \
--trivial_pre_for_unannotated_effectful_fns false \
--cmi --warn_error -274
SED=$(shell which gsed >/dev/null 2>&1 && echo gsed || echo sed)

all: aux.rust-test

FSTAR_FILES=$(wildcard *.fst *.fsti)

.PRECIOUS: %.krml

# Use F*'s dependency mechanism and fill out the missing rules.

ifndef MAKE_RESTARTS
ifndef NODEPEND
.depend: .FORCE
$(FSTAR) --dep full $(FSTAR_FILES) --extract 'krml:*,-Prims' --output_deps_to $@

.PHONY: .FORCE
.FORCE:
endif
endif

include .depend

$(CACHE_DIR)/%.checked: | .depend
$(FSTAR) $(OTHERFLAGS) $< && \
touch $@

%.krml: | .depend
$(FSTAR) $(OTHERFLAGS) --codegen krml \
--extract_module $(basename $(notdir $(subst .checked,,$<))) \
$(notdir $(subst .checked,,$<))

########
# Rust #
########

.PRECIOUS: %.rs
%.rs: $(ALL_KRML_FILES) $(KRML_BIN)
$(KRML) -minimal -bundle AuxA+AuxB=\*[rename=Aux,rename-prefix] \
-backend rust $(EXTRA) -tmpdir $(dir $@) $(filter %.krml,$^)

%.rust-test: %.rs
rustc --crate-type rlib $< -o $*.rlib