Skip to content

Commit

Permalink
let/const
Browse files Browse the repository at this point in the history
Summary: This commit allows for the creation of let/const bindings and ensures
all block-scoped bindings are installed into the appropriate scope. This
involves creating new LexScopes, as outlined in `test/bindings/scope.js`.

Before this change, the environment stack, i.e., frames, changesets, and
scopes, would change in lockstep. Now, lex scopes change separately from
frames and changesets via `push_lex` and `pop_lex`.

When adding heap refinements, we may traverse over lex scopes to find
the scope where the base object was bound.

In unusual cases, like try/catch, envs may have an uneven number of
scopes when merging. The uneven scopes will always be lex. I have
updated `merge_env` to accept this imbalance.

Note that this is not a complete implementation of let/const:
- [x] switch statements should forbid rebinding lexicals between cases
- [x] functions, amazingly, are block scoped *and* hoisted in ES2015
- [ ] numerous TDZ cases, surely, which I have not yet investigated
- [x] can't update cons
Closes #784

Reviewed By: @jeffmo

Differential Revision: D2428230

Pulled By: @bhosmer
  • Loading branch information
samwgoldman authored and facebook-github-bot-6 committed Sep 17, 2015
1 parent 4a2d2c8 commit a7d2cd2
Show file tree
Hide file tree
Showing 19 changed files with 1,079 additions and 353 deletions.
15 changes: 15 additions & 0 deletions src/typing/constraint_js.ml
Original file line number Diff line number Diff line change
Expand Up @@ -745,11 +745,15 @@ module Scope = struct

and implicit_let_kinds =
| ClassNameBinding
| CatchParamBinding
| FunctionBinding

let string_of_value_kind = function
| Const -> "const"
| Let None -> "let"
| Let (Some ClassNameBinding) -> "class"
| Let (Some CatchParamBinding) -> "catch"
| Let (Some FunctionBinding) -> "function"
| Var -> "var"

type value_binding = {
Expand Down Expand Up @@ -828,6 +832,13 @@ module Scope = struct
else Value { v with specific = make_specific v.general }
| Type _ -> entry

let is_lex = function
| Type _ -> false
| Value v ->
match v.kind with
| Const -> true
| Let _ -> true
| _ -> false
end

(* keys for refinements *)
Expand Down Expand Up @@ -963,6 +974,10 @@ module Scope = struct
| Some f -> scope |> update_entries (Entry.havoc ~name f)
| None -> ()

let is_lex scope =
match scope.kind with
| LexScope -> true
| _ -> false
end

(***************************************)
Expand Down
8 changes: 7 additions & 1 deletion src/typing/constraint_js.mli
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,10 @@ module Scope: sig
val string_of_state: state -> string

type value_kind = Const | Let of implicit_let_kinds option | Var
and implicit_let_kinds = ClassNameBinding
and implicit_let_kinds =
| ClassNameBinding
| CatchParamBinding
| FunctionBinding

val string_of_value_kind: value_kind -> string

Expand Down Expand Up @@ -326,6 +329,8 @@ module Scope: sig

val string_of_kind: t -> string
val havoc: ?name:string -> (Type.t -> Type.t) -> string -> t -> t

val is_lex: t -> bool
end

module Key: sig
Expand Down Expand Up @@ -375,6 +380,7 @@ module Scope: sig

val havoc: ?name: string -> ?make_specific: (Type.t -> Type.t) -> t -> unit

val is_lex: t -> bool
end

(***************************************)
Expand Down
Loading

0 comments on commit a7d2cd2

Please sign in to comment.