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

'Modul(term)' -> 'Modul.(term)' ; 'Dcon.prm' -> 'Dcon?.prm', 'is_Dcon' -> 'Dcon?' ; improved name resolution #772

Merged
merged 39 commits into from
Dec 2, 2016

Conversation

tahina-pro
Copy link
Member

@tahina-pro tahina-pro commented Dec 2, 2016

This long-awaited pull request introduces invasive, non-backwards-compatible syntax changes, as announced in #770.

The goal of these syntax changes is to introduce an invariant in name resolution: for any identifier (except module names) of the form Namespace.ident, Namespace shall always be a valid module name (in particular, it can no longer be a data constructor or effect name). This pull request introduces an improved name resolution with this invariant.

The improved name resolution mechanism brought by this pull request now honors shadowing in a more intuitive way, similarly to OCaml. Thus, in the following example:

module A
let x = 18

module B
let y =
  let x = 42 in
  let open A in
  x

In the above example, y will have value 18, since x now takes the value of A.x as expected, instead of the local variable x, as was the case previously.
NOTE: This may break existing code with let open FStar.UInt32 and the like, which will shadow n, since n is defined in such integer library modules.

These improvements are necessary to implement long-awaited enhancements (upcoming, not yet included in this pull request):

The goal of this syntax change is to ensure that, for any name
of the form Namespace.ident or Namespace.Name, the Namespace part
is always a valid module name (except if Namespace.Name is itself
the name of a module.)

So far, this property was not holding for the following two
cases:

- many occurrences of Some.v to project the formal parameter v
  of an option value that is known to be Some;

  Formally, whenever an inductive type t is defined:

  type t = | Datacon : param: u -> t | ...

  then, for any value vt : t {is_Datacon v} , it is valid to
  use (Datacon.param vt), of type u, to extract the value of
  the formal parameter.

  This introduces a spurious dependency on a hypothetical
  module called Some (and a clash if any Some module is
  reachable from open namespaces.)

- STATE.pre, STATE.post, and other effect members, similarly
  introducing spurious dependencies on a hypothetical STATE
  module.

As mentioned, the main consequence of those data constructor and
effect namespaces not being true modules are spurious dependency
generation and potential clashes with modules. I claim that this
current situation also gets in the way of any improvement on
name resolution, e.g. potential support for `include', currently
being discussed as `export' at:

#691

Thus, we need to introduce new syntax to change these
data constructor projector and effect member notations.
While I arbitrarily chose .. for testing purposes, discussions
about the final concrete syntax are still ongoing at:

http://doodle.com/poll/enadrtwqb6vhu2tr

However, independently of the actual choice for concrete syntax,
this syntax change implies the following deeper changes:

1. The projector for a formal parameter of a data constructor
   has been renamed, both internally and on the extracted code.

   Previously, Datacon.param was added as a fully qualified
   name for the corresponding projector. To avoid clashes with
   name resolution in open namespaces, it is now renamed as
   __proj__Datacon__item__param

   We could have used the reserved prefix uu___ (defined as
   reserved_prefix in src/basic/ident.fs), but using such
   prefix actually makes the verification of
   examples/preorders/MRefHeap.fst fail when replaying hints,
   for an unknown reason so far.

2. The fields of a record have been renamed similarly in
   extracted code.

   This is for two reasons. First, a record field is treated in
   the same way as a formal parameter of a data constructor,
   for internal purposes. In particular, given the following
   record type:

   type reco = { field: unit; ... }

   the elaborator actually turned any field access of the form
   expr.field intro (Mk_reco.field expr) where Mk_reco is the
   name of the data constructor created by transforming the
   record type into an inductive type, and so Mk_reco.field was
   exactly the data constructor projector for the 'field'
   formal parameter of the Mk_reco (unique) data constructor.
   We preserve this elaboration as a projector, but now using
   the new projector name instead.

   However, the second reason is that, since such projector
   calls are turned back to field accesses in extracted ML code,
   we do not want to rely on the extracted language's shadowing
   mechanism (for two different record types in the same module,
   each of which having a field with the same name in both),
   and so we use our field renaming as a way to resolve any such
   shadowing in advance.

3. The fields (pre, post, reflect, return, bind, and actions)
   of an effect have been renamed similarly, both internally
   and in extracted code.

   In this process, we took extra care to preserve the monad scope
   while defining the members and actions of an effect, in such
   a way that those names need not be qualified by the effect name
   while being defined. However, once defined, such a member is
   now required to be qualified with its MonadName.. instead of
   MonadName.  In particular, this new mechanism now forbids
   `open Monad' ---opening the namespace of a monad to access its
   members through unqualified names outside of the monad
   definition. Fortunately, this happens nowhere in any examples.

The main purpose of these renamings is to guarantee that, for any
global definition whose fully qualified name is of the shape
Namespace.ident, Namespace is now always a valid module, which
was not the case until now for data constructor projectors and
effect fields.
Needed by 'make -C src test', namely
'make -C examples/unit-tests sall', more exactly
examples/unit-tests/Unit1.Basic.fst
…na_projectors

Remaining conflicts on compiler files were solved by automatically
regenerating them.
Now, scopes are handled more intuitively, very much like OCaml:
local opens really shadow previous local definitions, etc.

The elaborator now relies on a cleaner implementation for name
resolution in src/parser/env.fs, based on keeping one single list
with all declarations interleaved, instead of keeping separate
lists for local definitions, recursive definitions, open
namespaces and module abbrevs.

Thus, this commit also fixes some spurious shadowings, which were
missed in some examples.

This commit heavily relies on the fact that, whenever a name of
the form Namespace.ident shows up, Namespace is always the name of
a valid module (not an effect or a data constructor). So, now,
Namespace is first separately resolved as a module, then the
definition is looked up into the given module.

This commit currently allows module name resolution at
open, let open, and module abbrevs, but I claim that this can be
easily changed and reverted to the previous behavior of requiring
fully qualified module names.
Reported by failing builds 2411 to 2413
…mana_local_open

Conflicts:
	src/parser/parse.fsi
	src/parser/parse.fsy

Resolved as "take theirs" (discard conflicting changes coming from
taramana_local_open).
…na_projectors

Conflicts:
	src/ocaml-output/FStar_Parser_AST.ml
	src/parser/parse.fsi
	src/parser/parse.fsy

Resolved as "take theirs" (discard taramana_projectors)

***NO_CI***
…mana_local_open

Conflicts resolved by regenerating the parser using:
make -C src/ocaml-output parser
 into taramana_projectors

Conflicts resolved by regenerating (make -C src/ocaml-output)
 into taramana_name_resolution

Conflicts resolved by regenerating hints with:
make -C doc/tutorial/code/solutions verify_hh-Ex11a.fst OTHERFLAGS='--record_hints' HINTS_ENABLED=''
 into taramana_projectors

Conflicts:
	doc/tutorial/code/solutions/Ex11a.fst.hints
	examples/low-level/crypto/Buffer.Utils.fst.hints
	examples/low-level/crypto/Crypto.AEAD.AES256GCM.fst.hints
	examples/low-level/crypto/Crypto.AEAD.Encoding.fst.hints
	examples/low-level/crypto/Crypto.AEAD.Invariant.fst.hints
	examples/low-level/crypto/Crypto.AEAD.Lemmas.fst.hints
	examples/low-level/crypto/Crypto.AEAD.fst.hints
	examples/low-level/crypto/Crypto.Symmetric.AES.fst.hints
	examples/low-level/crypto/Crypto.Symmetric.Bytes.fst.hints
	examples/low-level/crypto/Crypto.Symmetric.GCM.fst.hints
	examples/low-level/crypto/Crypto.Symmetric.GF128.fst.hints
	examples/low-level/crypto/Crypto.Symmetric.PRF.fst.hints
	examples/low-level/crypto/Crypto.Symmetric.Poly1305.Bignum.Lemmas.Part3.fst.hints
	examples/low-level/crypto/Crypto.Symmetric.Poly1305.Bignum.fst.hints
	examples/low-level/crypto/Crypto.Symmetric.Poly1305.Spec.fst.hints
	examples/low-level/crypto/Crypto.Symmetric.Poly1305.fst.hints
	ulib/FStar.Math.Lib.fst.hints

Resolved by discarding taramana_projectors in favor of master
(git checkout --theirs)

***CI***
At this point, Crypto.AEAD.Lemmas succeeds, but Ex07c still fails.
In fact, Ex07c succeeds if hints are disabled altogether, but even
if hints are produced when disabled (yielding the .hints file
as reflected in this commit), rechecking Ex07c with them
ultimately fails, for an unknown reason so far.
@catalin-hritcu catalin-hritcu mentioned this pull request Dec 2, 2016
49 tasks
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.

1 participant