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

Add a new syntax to support partial opens and includes #3369

Merged
merged 9 commits into from
Aug 14, 2024

Conversation

W95Psp
Copy link
Contributor

@W95Psp W95Psp commented Aug 10, 2024

Hi!

This PR introduces the following syntaxes:

// brings `MyModule.some_function`, `MyModule.some_type` and `MyModule.SomeConstructor` only, nothing else is visible
open MyModule { some_function, some_type, SomeConstructor }
// `include` works the same
include MyModule { some_function, some_type, SomeConstructor }
// renaming is possible
include MyModule { some_function as f, SomeConstructor as X }

I call { ... } a restriction that we impose on the open or include, maybe there's a better naming there.

This PR:

  • tags auto generated records (when type foo = | Foo {...}) with a new attribute desugar_of_variant_record (this is important, so that open Module {foo} is able to look for that attribute and bring foo__Foo__payload in scope too);
  • add a type restriction;
  • change the parser to allow the new restriction syntax;
  • tweaks DsEnv accordingly;
  • adds a module _ = Foo syntax (that desugars to open Foo {})

What do you think about this new feature?

@mtzguido, I haven't hacked on F* for a while, and I have to say having typeclasses (and tactics, seems like! 👀) within the compiler sources is fantastic! Especially something as "stupid" as showable simplifies makes debugging much much nicer!


More example in tests/restricted_includes, but here is a preview:

Given the following module:

module Definitions

type a_type = 
  | AType1: a1:int -> a2:nat -> a_type
  | AType2 of string
  | AType3 { a_type_C_field1: int
           ; a_type_C_field2: b_type }
and b_type =
  | BType1
  | BType2 of a_type
  | BType3 { b_type_F_field1: int
           ; a_type_F_field2: a_type }

type a_record = { a_record_field1: a_type; a_record_field2: int }

let fn_example x y = x + y

You can:

module Consumer

(**** Opening a type *)
// Importing an inductive `a_type` will implicitely import each data
// constructors and each associated desugared record types (here,
// `a_type` as a constructor `Type3` with a record payload: the
// implicit corresponding record type will be imported).
open Definitions {a_type}

// `a_type` and its constructors are available
let _ = a_type
let _ = AType1 0 1
let _ = AType2 "hi"
let _ = AType3 { a_type_C_field1 = 3
               ; a_type_C_field2 = Definitions.BType1 (* BType1 is not in scope *) }

// The automatically generated type `a_type__AType3__payload` is available as well
let _ = a_type__AType3__payload
let _ = Mka_type__AType3__payload
let _ = { a_type_C_field1 = 3
        ; a_type_C_field2 = Definitions.BType1 (* BType1 is not in scope *) }

// Fields projectors are imported
let _ = (AType1?.a1, AType2?._0, AType3?._0)

// The constructors of `a_type` are imported:
let _ = (AType1, AType2, AType3)

// Fields names are imported correctly
let _ = fun x -> x.a_type_C_field1

// Other definitions are not visible:
[@@expect_failure [72]] let _ = a_record
[@@expect_failure [72]] let _ = fn_example
[@@expect_failure [72]] let _ = b_type
[@@expect_failure [72]] let _ = BType1
[@@expect_failure [72]] let _ = BType2
[@@expect_failure [72]] let _ = BType3

(**** Include works as well *)
// Exactly the same syntax and expressivity works for `include` as
// well.
include Definitions {a_type}

(**** Renaming *)
include Definitions {AType2 as AnotherNicerName}
include Definitions {BType1 as RenamedBType1}
include Definitions {BType2}
include Definitions {fn_example as fn_renamed}

let _: a_type = AnotherNicerName "hello"

(**** Missing names or redundant names *)
// If a include or open exposes missing redundant names, this is an error.
[@@expect_failure [47]] open Definitions {AType2 as AType1, AType1}
[@@expect_failure [47]] open Definitions {AType1, AType1}
[@@expect_failure [47]] open Definitions {a_type, AType1}

(**** Opening a module anonymously *)
// Let's first bring in scope the method `to_int` of the typeclass `to_int_tc`:
open TypeclassDefinition {to_int}

// The module `TypeclassInstance` defines an instance of `to_int_tc`
// for `int`. I can open it without exposing any name into my scope:
open TypeclassInstance {}

// Now, I can use `to_int` on int:
let _ = to_int 3

@W95Psp W95Psp force-pushed the open-includes-restrictions branch from 25ff94b to dcb2b47 Compare August 12, 2024 10:30
Copy link
Member

@mtzguido mtzguido left a comment

Choose a reason for hiding this comment

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

Hi Lucas, this looks great and it's very useful! Thank you!

I left some tiny comments, but other than that I'd be really happy merging this.

W95Psp added 9 commits August 13, 2024 21:50
This commit introduces the following syntaxes:
```fstar
// brings `MyModule.some_function`, `MyModule.some_type` and `MyModule.SomeConstructor` only, nothing else is visible
open MyModule { some_function, some_type, SomeConstructor }
// `include` works the same
include MyModule { some_function, some_type, SomeConstructor }
// renaming is possible
include MyModule { some_function as f, SomeConstructor as X }
```

I call `{ ... }` a restriction that we impose on the open or include, maybe there's a better naming there.

This PR:
 - tags auto generated records (when `type foo = | Foo {...}`) with a new attribute `desugar_of_variant_record` (this is important, so that `open Module {foo}` is able to look for that attribute and bring `foo__Foo__payload` in scope too);
 - add a type `restriction`;
 - change the parser to allow the new restriction syntax;
 - tweaks `DsEnv` accordingly.
@W95Psp W95Psp force-pushed the open-includes-restrictions branch from 7717f9f to 07da2dd Compare August 13, 2024 19:55
@W95Psp
Copy link
Contributor Author

W95Psp commented Aug 13, 2024

Thanks for the fast review Guido! I addressed your comments, tell me if there's anything else I can do :)
Otherwise I'd be quite happy to see that merged :D

@W95Psp W95Psp requested a review from mtzguido August 13, 2024 19:59
@mtzguido mtzguido merged commit 608c8c2 into FStarLang:master Aug 14, 2024
2 checks passed
@mtzguido
Copy link
Member

Thanks Lucas! This is great.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants