Revision: 10966
Author:   [email protected]
Date:     Thu Mar  8 05:03:07 2012
Log:      Basic interface inference for modules.

All module expressions, and all variables that might refer to modules,
are assigned interfaces (module types) that are resolved using
unification. This is necessary to deal with the highly recursive
nature of ES6 modules, which does not allow any kind of bottom-up
strategy for resolving module names and paths.

Error messages are rudimental right now. Probably need to track
more information to make them nicer.

[email protected]
BUG=v8:1569
TEST=

Review URL: https://chromiumcodereview.appspot.com/9615009
http://code.google.com/p/v8/source/detail?r=10966

Added:
 /branches/bleeding_edge/src/interface.cc
 /branches/bleeding_edge/src/interface.h
 /branches/bleeding_edge/test/mjsunit/harmony/module-resolution.js
Modified:
 /branches/bleeding_edge/src/SConscript
 /branches/bleeding_edge/src/ast.cc
 /branches/bleeding_edge/src/ast.h
 /branches/bleeding_edge/src/flag-definitions.h
 /branches/bleeding_edge/src/messages.js
 /branches/bleeding_edge/src/parser.cc
 /branches/bleeding_edge/src/parser.h
 /branches/bleeding_edge/src/scopes.cc
 /branches/bleeding_edge/src/scopes.h
 /branches/bleeding_edge/src/variables.cc
 /branches/bleeding_edge/src/variables.h
 /branches/bleeding_edge/test/mjsunit/harmony/module-parsing.js
 /branches/bleeding_edge/tools/gyp/v8.gyp

=======================================
--- /dev/null
+++ /branches/bleeding_edge/src/interface.cc    Thu Mar  8 05:03:07 2012
@@ -0,0 +1,226 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "interface.h"
+
+namespace v8 {
+namespace internal {
+
+static bool Match(void* key1, void* key2) {
+  String* name1 = *static_cast<String**>(key1);
+  String* name2 = *static_cast<String**>(key2);
+  ASSERT(name1->IsSymbol());
+  ASSERT(name2->IsSymbol());
+  return name1 == name2;
+}
+
+
+Interface* Interface::Lookup(Handle<String> name) {
+  ASSERT(IsModule());
+  ZoneHashMap* map = Chase()->exports_;
+  if (map == NULL) return NULL;
+ ZoneHashMap::Entry* p = map->Lookup(name.location(), name->Hash(), false);
+  if (p == NULL) return NULL;
+  ASSERT(*static_cast<String**>(p->key) == *name);
+  ASSERT(p->value != NULL);
+  return static_cast<Interface*>(p->value);
+}
+
+
+#ifdef DEBUG
+// Current nesting depth for debug output.
+class Nesting {
+ public:
+  Nesting()  { current_ += 2; }
+  ~Nesting() { current_ -= 2; }
+  static int current() { return current_; }
+ private:
+  static int current_;
+};
+
+int Nesting::current_ = 0;
+#endif
+
+
+void Interface::DoAdd(
+    void* name, uint32_t hash, Interface* interface, bool* ok) {
+  MakeModule(ok);
+  if (!*ok) return;
+
+#ifdef DEBUG
+  if (FLAG_print_interface_details) {
+    PrintF("%*s# Adding...\n", Nesting::current(), "");
+    PrintF("%*sthis = ", Nesting::current(), "");
+    this->Print(Nesting::current());
+    PrintF("%*s%s : ", Nesting::current(), "",
+           (*reinterpret_cast<String**>(name))->ToAsciiArray());
+    interface->Print(Nesting::current());
+  }
+#endif
+
+  ZoneHashMap** map = &Chase()->exports_;
+  if (*map == NULL) *map = new ZoneHashMap(Match, 8);
+
+  ZoneHashMap::Entry* p = (*map)->Lookup(name, hash, !IsFrozen());
+  if (p == NULL) {
+    // This didn't have name but was frozen already, that's an error.
+    *ok = false;
+  } else if (p->value == NULL) {
+    p->value = interface;
+  } else {
+#ifdef DEBUG
+    Nesting nested;
+#endif
+    reinterpret_cast<Interface*>(p->value)->Unify(interface, ok);
+  }
+
+#ifdef DEBUG
+  if (FLAG_print_interface_details) {
+    PrintF("%*sthis' = ", Nesting::current(), "");
+    this->Print(Nesting::current());
+    PrintF("%*s# Added.\n", Nesting::current(), "");
+  }
+#endif
+}
+
+
+void Interface::Unify(Interface* that, bool* ok) {
+  if (this->forward_) return this->Chase()->Unify(that, ok);
+  if (that->forward_) return this->Unify(that->Chase(), ok);
+  ASSERT(this->forward_ == NULL);
+  ASSERT(that->forward_ == NULL);
+
+  *ok = true;
+  if (this == that) return;
+  if (this->IsValue()) return that->MakeValue(ok);
+  if (that->IsValue()) return this->MakeValue(ok);
+
+#ifdef DEBUG
+  if (FLAG_print_interface_details) {
+    PrintF("%*s# Unifying...\n", Nesting::current(), "");
+    PrintF("%*sthis = ", Nesting::current(), "");
+    this->Print(Nesting::current());
+    PrintF("%*sthat = ", Nesting::current(), "");
+    that->Print(Nesting::current());
+  }
+#endif
+
+  // Merge the smaller interface into the larger, for performance.
+  if (this->exports_ != NULL && (that->exports_ == NULL ||
+      this->exports_->occupancy() >= that->exports_->occupancy())) {
+    this->DoUnify(that, ok);
+  } else {
+    that->DoUnify(this, ok);
+  }
+
+#ifdef DEBUG
+  if (FLAG_print_interface_details) {
+    PrintF("%*sthis' = ", Nesting::current(), "");
+    this->Print(Nesting::current());
+    PrintF("%*sthat' = ", Nesting::current(), "");
+    that->Print(Nesting::current());
+    PrintF("%*s# Unified.\n", Nesting::current(), "");
+  }
+#endif
+}
+
+
+void Interface::DoUnify(Interface* that, bool* ok) {
+  ASSERT(this->forward_ == NULL);
+  ASSERT(that->forward_ == NULL);
+  ASSERT(!this->IsValue());
+  ASSERT(!that->IsValue());
+  ASSERT(*ok);
+
+#ifdef DEBUG
+    Nesting nested;
+#endif
+
+  // Try to merge all members from that into this.
+  ZoneHashMap* map = that->exports_;
+  if (map != NULL) {
+ for (ZoneHashMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) {
+      this->DoAdd(p->key, p->hash, static_cast<Interface*>(p->value), ok);
+      if (!*ok) return;
+    }
+  }
+
+  // If the new interface is larger than that's, then there were members in
+ // 'this' which 'that' didn't have. If 'that' was frozen that is an error.
+  int this_size = this->exports_ == NULL ? 0 : this->exports_->occupancy();
+  int that_size = map == NULL ? 0 : map->occupancy();
+  if (that->IsFrozen() && this_size > that_size) {
+    *ok = false;
+    return;
+  }
+
+  // Merge interfaces.
+  this->flags_ |= that->flags_;
+  that->forward_ = this;
+}
+
+
+#ifdef DEBUG
+void Interface::Print(int n) {
+  int n0 = n > 0 ? n : 0;
+
+  if (FLAG_print_interface_details) {
+    PrintF("%p", static_cast<void*>(this));
+ for (Interface* link = this->forward_; link != NULL; link = link->forward_)
+      PrintF("->%p", static_cast<void*>(link));
+    PrintF(" ");
+  }
+
+  if (IsUnknown()) {
+    PrintF("unknown\n");
+  } else if (IsValue()) {
+    PrintF("value\n");
+  } else if (IsModule()) {
+    PrintF("module %s{", IsFrozen() ? "" : "(unresolved) ");
+    ZoneHashMap* map = Chase()->exports_;
+    if (map == NULL || map->occupancy() == 0) {
+      PrintF("}\n");
+    } else if (n < 0 || n0 >= 2 * FLAG_print_interface_depth) {
+      // Avoid infinite recursion on cyclic types.
+      PrintF("...}\n");
+    } else {
+      PrintF("\n");
+ for (ZoneHashMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) {
+        String* name = *static_cast<String**>(p->key);
+        Interface* interface = static_cast<Interface*>(p->value);
+        PrintF("%*s%s : ", n0 + 2, "", name->ToAsciiArray());
+        interface->Print(n0 + 2);
+      }
+      PrintF("%*s}\n", n0, "");
+    }
+  }
+}
+#endif
+
+} }  // namespace v8::internal
=======================================
--- /dev/null
+++ /branches/bleeding_edge/src/interface.h     Thu Mar  8 05:03:07 2012
@@ -0,0 +1,156 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_INTERFACE_H_
+#define V8_INTERFACE_H_
+
+#include "zone-inl.h"  // For operator new.
+
+namespace v8 {
+namespace internal {
+
+
+// This class implements the following abstract grammar of interfaces
+// (i.e. module types):
+//   interface ::= UNDETERMINED | VALUE | MODULE(exports)
+//   exports ::= {name : interface, ...}
+// A frozen module type is one that is fully determined. Unification does not
+// allow adding additional exports to frozen interfaces.
+// Otherwise, unifying modules merges their exports.
+// Undetermined types are unification variables that can be unified freely.
+
+class Interface : public ZoneObject {
+ public:
+ // ---------------------------------------------------------------------------
+  // Factory methods.
+
+  static Interface* NewValue() {
+    static Interface value_interface(VALUE + FROZEN);  // Cached.
+    return &value_interface;
+  }
+
+  static Interface* NewUnknown() {
+    return new Interface(NONE);
+  }
+
+  static Interface* NewModule() {
+    return new Interface(MODULE);
+  }
+
+ // ---------------------------------------------------------------------------
+  // Mutators.
+
+  // Add a name to the list of exports. If it already exists, unify with
+  // interface, otherwise insert unless this is closed.
+  void Add(Handle<String> name, Interface* interface, bool* ok) {
+    DoAdd(name.location(), name->Hash(), interface, ok);
+  }
+
+ // Unify with another interface. If successful, both interface objects will + // represent the same type, and changes to one are reflected in the other.
+  void Unify(Interface* that, bool* ok);
+
+  // Determine this interface to be a value interface.
+  void MakeValue(bool* ok) {
+    *ok = !IsModule();
+    if (*ok) Chase()->flags_ |= VALUE;
+  }
+
+  // Determine this interface to be a module interface.
+  void MakeModule(bool* ok) {
+    *ok = !IsValue();
+    if (*ok) Chase()->flags_ |= MODULE;
+  }
+
+  // Do not allow any further refinements, directly or through unification.
+  void Freeze(bool* ok) {
+    *ok = IsValue() || IsModule();
+    if (*ok) Chase()->flags_ |= FROZEN;
+  }
+
+ // ---------------------------------------------------------------------------
+  // Accessors.
+
+  // Look up an exported name. Returns NULL if not (yet) defined.
+  Interface* Lookup(Handle<String> name);
+
+  // Check whether this is still a fully undetermined type.
+  bool IsUnknown() { return Chase()->flags_ == NONE; }
+
+  // Check whether this is a value type.
+  bool IsValue() { return Chase()->flags_ & VALUE; }
+
+  // Check whether this is a module type.
+  bool IsModule() { return Chase()->flags_ & MODULE; }
+
+  // Check whether this is closed (i.e. fully determined).
+  bool IsFrozen() { return Chase()->flags_ & FROZEN; }
+
+ // ---------------------------------------------------------------------------
+  // Debugging.
+#ifdef DEBUG
+ void Print(int n = 0); // n = indentation; n < 0 => don't print recursively
+#endif
+
+ // ---------------------------------------------------------------------------
+  // Implementation.
+ private:
+  enum Flags {    // All flags are monotonic
+    NONE = 0,
+    VALUE = 1,    // This type describes a value
+    MODULE = 2,   // This type describes a module
+    FROZEN = 4    // This type is fully determined
+  };
+
+  int flags_;
+  Interface* forward_;     // Unification link
+ ZoneHashMap* exports_; // Module exports and their types (allocated lazily)
+
+  explicit Interface(int flags)
+    : flags_(flags),
+      forward_(NULL),
+      exports_(NULL) {
+#ifdef DEBUG
+    if (FLAG_print_interface_details)
+      PrintF("# Creating %p\n", static_cast<void*>(this));
+#endif
+  }
+
+  Interface* Chase() {
+    Interface* result = this;
+    while (result->forward_ != NULL) result = result->forward_;
+    if (result != this) forward_ = result;  // On-the-fly path compression.
+    return result;
+  }
+
+  void DoAdd(void* name, uint32_t hash, Interface* interface, bool* ok);
+  void DoUnify(Interface* that, bool* ok);
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_INTERFACE_H_
=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/harmony/module-resolution.js Thu Mar 8 05:03:07 2012
@@ -0,0 +1,139 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --harmony-modules --harmony-scoping
+
+// Test basic module interface inference.
+
+"use strict";
+
+print("begin.")
+
+export let x = print("0")
+
+export module B = A.B
+
+export module A {
+  export let x = print("1")
+  export let f = function() { return B.x }
+  export module B {
+    module BB = B
+    export BB, x
+    let x = print("2")
+    let y = print("3")
+    let Ax = A.x
+    let ABx = A.B.x
+    let Ay = A.y
+    let BBx = BB.x
+    let Af = A.f
+    function f(x,y) { return x }
+  }
+  export let y = print("4")
+  let Ax = A.x
+  let Bx = B.x
+  let ABx = A.B.x
+  module C {
+    export let z = print("5")
+    export module D = B
+ // TODO(rossberg): turn these into proper negative test cases once we have
+    // suitable error messages.
+    // import C.z  // multiple declarations
+    import x from B
+  }
+  module D {
+    // TODO(rossberg): Handle import *.
+    // import A.*  // invalid forward import
+  }
+  module M {}
+  // TODO(rossberg): Handle import *.
+  // import M.*  // invalid forward import
+  let Cz = C.z
+  let CDx = C.D.x
+}
+
+export module Imports {
+  module A1 {
+    export module A2 {}
+  }
+  module B {
+    // TODO(rossberg): Handle import *.
+    // import A1.*
+    // import A2.*  // unbound variable A2
+  }
+}
+
+export module E {
+  export let xx = x
+  export y, B
+  let Bx = B.x
+  // TODO(rossberg): Handle import *.
+  // import A.*
+}
+
+export module M1 {
+  export module A2 = M2
+}
+export module M2 {
+  export module A1 = M1
+}
+
+// TODO(rossberg): turn these into proper negative test cases once we have
+// suitable error messages.
+// module W1 = W2.W
+// module W2 = { export module W = W3 }
+// module W3 = W1  // cyclic module definition
+
+// module W1 = W2.W3
+// module W2 = {
+//   export module W3 = W4
+//   export module W4 = W1
+// }  // cyclic module definition
+
+// TODO(rossberg): Handle import *.
+//module M3B = M3.B
+//export module M3 {
+//  export module B { export let x = "" }
+//  module C1 = { import M3.* }
+//  module C2 = { import M3.B.* }
+//  module C3 = { import M3B.* }
+//  module C4 = { export x import B.* }
+//// TODO(rossberg): turn these into proper negative test cases once we have
+//// suitable error messages.
+//// export module C5 = { import C5.* }  // invalid forward import
+//// export module C6 = { import M3.C6.* }  // invalid forward import
+//}
+
+export module External at "external.js"
+export module External1 = External
+export module ExternalA = External.A
+export module InnerExternal {
+  export module E at "external.js"
+}
+export module External2 = InnerExternal.E
+//export let xxx = InnerExternal.E.A.x
+
+print("end.")
=======================================
--- /branches/bleeding_edge/src/SConscript      Thu Feb 23 01:12:57 2012
+++ /branches/bleeding_edge/src/SConscript      Thu Mar  8 05:03:07 2012
@@ -84,6 +84,7 @@
     hydrogen-instructions.cc
     ic.cc
     incremental-marking.cc
+    interface.cc
     inspector.cc
     interpreter-irregexp.cc
     isolate.cc
=======================================
--- /branches/bleeding_edge/src/ast.cc  Fri Mar  2 06:15:28 2012
+++ /branches/bleeding_edge/src/ast.cc  Thu Mar  8 05:03:07 2012
@@ -76,7 +76,8 @@
       is_this_(var->is_this()),
       is_trivial_(false),
       is_lvalue_(false),
-      position_(RelocInfo::kNoPosition) {
+      position_(RelocInfo::kNoPosition),
+      interface_(var->interface()) {
   BindTo(var);
 }

@@ -84,14 +85,16 @@
 VariableProxy::VariableProxy(Isolate* isolate,
                              Handle<String> name,
                              bool is_this,
-                             int position)
+                             int position,
+                             Interface* interface)
     : Expression(isolate),
       name_(name),
       var_(NULL),
       is_this_(is_this),
       is_trivial_(false),
       is_lvalue_(false),
-      position_(position) {
+      position_(position),
+      interface_(interface) {
   // Names must be canonicalized for fast equality checks.
   ASSERT(name->IsSymbol());
 }
=======================================
--- /branches/bleeding_edge/src/ast.h   Wed Feb 29 04:12:52 2012
+++ /branches/bleeding_edge/src/ast.h   Thu Mar  8 05:03:07 2012
@@ -41,6 +41,7 @@
 #include "token.h"
 #include "utils.h"
 #include "variables.h"
+#include "interface.h"
 #include "zone-inl.h"

 namespace v8 {
@@ -589,9 +590,15 @@


 class Module: public AstNode {
-  // TODO(rossberg): stuff to come...
+ public:
+  Interface* interface() const { return interface_; }
+
  protected:
-  Module() {}
+  Module() : interface_(Interface::NewModule()) {}
+  explicit Module(Interface* interface) : interface_(interface) {}
+
+ private:
+  Interface* interface_;
 };


@@ -604,8 +611,9 @@
  protected:
   template<class> friend class AstNodeFactory;

-  explicit ModuleLiteral(Block* body)
-      : body_(body) {
+  ModuleLiteral(Block* body, Interface* interface)
+      : Module(interface),
+        body_(body) {
   }

  private:
@@ -622,9 +630,7 @@
  protected:
   template<class> friend class AstNodeFactory;

-  explicit ModuleVariable(VariableProxy* proxy)
-      : proxy_(proxy) {
-  }
+  inline explicit ModuleVariable(VariableProxy* proxy);

  private:
   VariableProxy* proxy_;
@@ -1451,6 +1457,8 @@
   Variable* var() const { return var_; }
   bool is_this() const { return is_this_; }
   int position() const { return position_; }
+  Interface* interface() const { return interface_; }
+

   void MarkAsTrivial() { is_trivial_ = true; }
   void MarkAsLValue() { is_lvalue_ = true; }
@@ -1466,7 +1474,8 @@
   VariableProxy(Isolate* isolate,
                 Handle<String> name,
                 bool is_this,
-                int position);
+                int position,
+                Interface* interface);

   Handle<String> name_;
   Variable* var_;  // resolved variable, or NULL
@@ -1476,6 +1485,7 @@
   // or with a increment/decrement operator.
   bool is_lvalue_;
   int position_;
+  Interface* interface_;
 };


@@ -2503,6 +2513,15 @@
     return instance;
   }
 };
+
+
+// ----------------------------------------------------------------------------
+// Out-of-line inline constructors (to side-step cyclic dependencies).
+
+inline ModuleVariable::ModuleVariable(VariableProxy* proxy)
+    : Module(proxy->interface()),
+      proxy_(proxy) {
+}


// ----------------------------------------------------------------------------
@@ -2639,8 +2658,8 @@
     VISIT_AND_RETURN(ExportDeclaration, decl)
   }

-  ModuleLiteral* NewModuleLiteral(Block* body) {
-    ModuleLiteral* module = new(zone_) ModuleLiteral(body);
+  ModuleLiteral* NewModuleLiteral(Block* body, Interface* interface) {
+    ModuleLiteral* module = new(zone_) ModuleLiteral(body, interface);
     VISIT_AND_RETURN(ModuleLiteral, module)
   }

@@ -2796,9 +2815,11 @@

   VariableProxy* NewVariableProxy(Handle<String> name,
                                   bool is_this,
-                                  int position = RelocInfo::kNoPosition) {
+                                  int position = RelocInfo::kNoPosition,
+                                  Interface* interface =
+                                      Interface::NewValue()) {
     VariableProxy* proxy =
-        new(zone_) VariableProxy(isolate_, name, is_this, position);
+ new(zone_) VariableProxy(isolate_, name, is_this, position, interface);
     VISIT_AND_RETURN(VariableProxy, proxy)
   }

=======================================
--- /branches/bleeding_edge/src/flag-definitions.h      Mon Mar  5 06:20:58 2012
+++ /branches/bleeding_edge/src/flag-definitions.h      Thu Mar  8 05:03:07 2012
@@ -487,6 +487,11 @@
 // ic.cc
 DEFINE_bool(trace_ic, false, "trace inline cache state transitions")

+// interface.cc
+DEFINE_bool(print_interfaces, false, "print interfaces")
+DEFINE_bool(print_interface_details, false, "print interface inference details")
+DEFINE_int(print_interface_depth, 5, "depth for printing interfaces")
+
 // objects.cc
 DEFINE_bool(trace_normalization,
             false,
=======================================
--- /branches/bleeding_edge/src/messages.js     Wed Mar  7 05:24:44 2012
+++ /branches/bleeding_edge/src/messages.js     Thu Mar  8 05:03:07 2012
@@ -246,6 +246,8 @@
"cant_prevent_ext_external_array_elements", ["Cannot prevent extension of an object with external array elements"], "redef_external_array_element", ["Cannot redefine a property of an object with external array elements"],
       "harmony_const_assign",         ["Assignment to constant variable."],
+ "invalid_module_path", ["Module does not export '", "%0", "', or export is not itself a module"], + "module_type_error", ["Module '", "%0", "' used improperly"],
     ];
     var messages = { __proto__ : null };
     for (var i = 0; i < messagesDictionary.length; i += 2) {
=======================================
--- /branches/bleeding_edge/src/parser.cc       Wed Feb 29 04:12:52 2012
+++ /branches/bleeding_edge/src/parser.cc       Thu Mar  8 05:03:07 2012
@@ -755,6 +755,12 @@
   Scanner::Location source_location = scanner().location();
   ReportMessageAt(source_location, type, args);
 }
+
+
+void Parser::ReportMessage(const char* type, Vector<Handle<String> > args) {
+  Scanner::Location source_location = scanner().location();
+  ReportMessageAt(source_location, type, args);
+}


 void Parser::ReportMessageAt(Scanner::Location source_location,
@@ -1163,6 +1169,7 @@
           this_property_assignment_finder.GetThisPropertyAssignments());
     }
   }
+
   return 0;
 }

@@ -1221,12 +1228,28 @@
   // Create new block with one expected declaration.
   Block* block = factory()->NewBlock(NULL, 1, true);
   Handle<String> name = ParseIdentifier(CHECK_OK);
+
+#ifdef DEBUG
+  if (FLAG_print_interface_details)
+    PrintF("# Module %s...\n", name->ToAsciiArray());
+#endif
+
   Module* module = ParseModule(CHECK_OK);
-  VariableProxy* proxy = NewUnresolved(name, LET);
+  VariableProxy* proxy = NewUnresolved(name, LET, module->interface());
   Declaration* declaration =
       factory()->NewModuleDeclaration(proxy, module, top_scope_);
   Declare(declaration, true, CHECK_OK);

+#ifdef DEBUG
+  if (FLAG_print_interface_details)
+    PrintF("# Module %s.\n", name->ToAsciiArray());
+
+  if (FLAG_print_interfaces) {
+    PrintF("module %s : ", name->ToAsciiArray());
+    module->interface()->Print();
+  }
+#endif
+
   // TODO(rossberg): Add initialization statement to block.

   if (names) names->Add(name);
@@ -1267,6 +1290,9 @@

   // Construct block expecting 16 statements.
   Block* body = factory()->NewBlock(NULL, 16, false);
+#ifdef DEBUG
+  if (FLAG_print_interface_details) PrintF("# Literal ");
+#endif
   Scope* scope = NewScope(top_scope_, MODULE_SCOPE);

   Expect(Token::LBRACE, CHECK_OK);
@@ -1292,7 +1318,10 @@
   Expect(Token::RBRACE, CHECK_OK);
   scope->set_end_position(scanner().location().end_pos);
   body->set_block_scope(scope);
-  return factory()->NewModuleLiteral(body);
+
+  scope->interface()->Freeze(ok);
+  ASSERT(ok);
+  return factory()->NewModuleLiteral(body, scope->interface());
 }


@@ -1302,10 +1331,28 @@
   //    ModulePath '.' Identifier

   Module* result = ParseModuleVariable(CHECK_OK);
-
   while (Check(Token::PERIOD)) {
     Handle<String> name = ParseIdentifierName(CHECK_OK);
-    result = factory()->NewModulePath(result, name);
+#ifdef DEBUG
+    if (FLAG_print_interface_details)
+      PrintF("# Path .%s ", name->ToAsciiArray());
+#endif
+    Module* member = factory()->NewModulePath(result, name);
+    result->interface()->Add(name, member->interface(), ok);
+    if (!*ok) {
+#ifdef DEBUG
+      if (FLAG_print_interfaces) {
+        PrintF("PATH TYPE ERROR at '%s'\n", name->ToAsciiArray());
+        PrintF("result: ");
+        result->interface()->Print();
+        PrintF("member: ");
+        member->interface()->Print();
+      }
+#endif
+ ReportMessage("invalid_module_path", Vector<Handle<String> >(&name, 1));
+      return NULL;
+    }
+    result = member;
   }

   return result;
@@ -1317,8 +1364,13 @@
   //    Identifier

   Handle<String> name = ParseIdentifier(CHECK_OK);
+#ifdef DEBUG
+  if (FLAG_print_interface_details)
+    PrintF("# Module variable %s ", name->ToAsciiArray());
+#endif
   VariableProxy* proxy = top_scope_->NewUnresolved(
-      factory(), name, scanner().location().beg_pos);
+ factory(), name, scanner().location().beg_pos, Interface::NewModule());
+
   return factory()->NewModuleVariable(proxy);
 }

@@ -1330,6 +1382,11 @@
   Expect(Token::STRING, CHECK_OK);
   Handle<String> symbol = GetSymbol(CHECK_OK);

+  // TODO(ES6): Request JS resource from environment...
+
+#ifdef DEBUG
+  if (FLAG_print_interface_details) PrintF("# Url ");
+#endif
   return factory()->NewModuleUrl(symbol);
 }

@@ -1357,6 +1414,7 @@
   ZoneStringList names(1);

   Handle<String> name = ParseIdentifierName(CHECK_OK);
+  names.Add(name);
   while (peek() == Token::COMMA) {
     Consume(Token::COMMA);
     name = ParseIdentifierName(CHECK_OK);
@@ -1371,13 +1429,29 @@
   // TODO(ES6): once we implement destructuring, make that one declaration.
   Block* block = factory()->NewBlock(NULL, 1, true);
   for (int i = 0; i < names.length(); ++i) {
-    VariableProxy* proxy = NewUnresolved(names[i], LET);
+#ifdef DEBUG
+    if (FLAG_print_interface_details)
+      PrintF("# Import %s ", names[i]->ToAsciiArray());
+#endif
+    Interface* interface = Interface::NewUnknown();
+    module->interface()->Add(names[i], interface, ok);
+    if (!*ok) {
+#ifdef DEBUG
+      if (FLAG_print_interfaces) {
+        PrintF("IMPORT TYPE ERROR at '%s'\n", names[i]->ToAsciiArray());
+        PrintF("module: ");
+        module->interface()->Print();
+      }
+#endif
+ ReportMessage("invalid_module_path", Vector<Handle<String> >(&name, 1));
+      return NULL;
+    }
+    VariableProxy* proxy = NewUnresolved(names[i], LET, interface);
     Declaration* declaration =
         factory()->NewImportDeclaration(proxy, module, top_scope_);
     Declare(declaration, true, CHECK_OK);
     // TODO(rossberg): Add initialization statement to block.
   }
-

   return block;
 }
@@ -1431,12 +1505,22 @@
       return NULL;
   }

-  // Extract declared names into export declarations.
+  // Extract declared names into export declarations and interface.
+  Interface* interface = top_scope_->interface();
   for (int i = 0; i < names.length(); ++i) {
-    VariableProxy* proxy = NewUnresolved(names[i], LET);
-    Declaration* declaration =
-        factory()->NewExportDeclaration(proxy, top_scope_);
-    top_scope_->AddDeclaration(declaration);
+#ifdef DEBUG
+    if (FLAG_print_interface_details)
+      PrintF("# Export %s ", names[i]->ToAsciiArray());
+#endif
+    Interface* inner = Interface::NewUnknown();
+    interface->Add(names[i], inner, CHECK_OK);
+    VariableProxy* proxy = NewUnresolved(names[i], LET, inner);
+    USE(proxy);
+    // TODO(rossberg): Rethink whether we actually need to store export
+    // declarations (for compilation?).
+    // ExportDeclaration* declaration =
+    //     factory()->NewExportDeclaration(proxy, top_scope_);
+    // top_scope_->AddDeclaration(declaration);
   }

   ASSERT(result != NULL);
@@ -1597,19 +1681,21 @@
 }


-VariableProxy* Parser::NewUnresolved(Handle<String> name, VariableMode mode) {
+VariableProxy* Parser::NewUnresolved(
+    Handle<String> name, VariableMode mode, Interface* interface) {
// If we are inside a function, a declaration of a var/const variable is a // truly local variable, and the scope of the variable is always the function
   // scope.
// Let/const variables in harmony mode are always added to the immediately
   // enclosing scope.
   return DeclarationScope(mode)->NewUnresolved(
-      factory(), name, scanner().location().beg_pos);
+      factory(), name, scanner().location().beg_pos, interface);
 }


 void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) {
-  Handle<String> name = declaration->proxy()->name();
+  VariableProxy* proxy = declaration->proxy();
+  Handle<String> name = proxy->name();
   VariableMode mode = declaration->mode();
   Scope* declaration_scope = DeclarationScope(mode);
   Variable* var = NULL;
@@ -1627,13 +1713,14 @@
   if (declaration_scope->is_function_scope() ||
       declaration_scope->is_strict_or_extended_eval_scope() ||
       declaration_scope->is_block_scope() ||
-      declaration_scope->is_module_scope()) {
+      declaration_scope->is_module_scope() ||
+      declaration->AsModuleDeclaration() != NULL) {
     // Declare the variable in the function scope.
     var = declaration_scope->LocalLookup(name);
     if (var == NULL) {
       // Declare the name.
       var = declaration_scope->DeclareLocal(
-          name, mode, declaration->initialization());
+          name, mode, declaration->initialization(), proxy->interface());
     } else {
       // The name was declared in this scope before; check for conflicting
// re-declarations. We have a conflict if either of the declarations is
@@ -1743,7 +1830,30 @@
   // initialization code. Thus, inside the 'with' statement, we need
   // both access to the static and the dynamic context chain; the
   // runtime needs to provide both.
-  if (resolve && var != NULL) declaration->proxy()->BindTo(var);
+  if (resolve && var != NULL) {
+    proxy->BindTo(var);
+
+    if (FLAG_harmony_modules) {
+      bool ok;
+#ifdef DEBUG
+      if (FLAG_print_interface_details)
+        PrintF("# Declare %s\n", var->name()->ToAsciiArray());
+#endif
+      proxy->interface()->Unify(var->interface(), &ok);
+      if (!ok) {
+#ifdef DEBUG
+        if (FLAG_print_interfaces) {
+          PrintF("DECLARE TYPE ERROR\n");
+          PrintF("proxy: ");
+          proxy->interface()->Print();
+          PrintF("var: ");
+          var->interface()->Print();
+        }
+#endif
+ ReportMessage("module_type_error", Vector<Handle<String> >(&name, 1));
+      }
+    }
+  }
 }


@@ -3498,8 +3608,14 @@
     case Token::FUTURE_STRICT_RESERVED_WORD: {
       Handle<String> name = ParseIdentifier(CHECK_OK);
       if (fni_ != NULL) fni_->PushVariableName(name);
+ // The name may refer to a module instance object, so its type is unknown.
+#ifdef DEBUG
+      if (FLAG_print_interface_details)
+        PrintF("# Variable %s ", name->ToAsciiArray());
+#endif
+      Interface* interface = Interface::NewUnknown();
       result = top_scope_->NewUnresolved(
-          factory(), name, scanner().location().beg_pos);
+          factory(), name, scanner().location().beg_pos, interface);
       break;
     }

=======================================
--- /branches/bleeding_edge/src/parser.h        Wed Feb 29 04:12:52 2012
+++ /branches/bleeding_edge/src/parser.h        Thu Mar  8 05:03:07 2012
@@ -557,6 +557,7 @@
   void ReportUnexpectedToken(Token::Value token);
   void ReportInvalidPreparseData(Handle<String> name, bool* ok);
   void ReportMessage(const char* message, Vector<const char*> args);
+  void ReportMessage(const char* message, Vector<Handle<String> > args);

   bool inside_with() const { return top_scope_->inside_with(); }
   Scanner& scanner()  { return scanner_; }
@@ -764,7 +765,9 @@
   void CheckConflictingVarDeclarations(Scope* scope, bool* ok);

   // Parser support
-  VariableProxy* NewUnresolved(Handle<String> name, VariableMode mode);
+  VariableProxy* NewUnresolved(Handle<String> name,
+                               VariableMode mode,
+ Interface* interface = Interface::NewValue());
   void Declare(Declaration* declaration, bool resolve, bool* ok);

   bool TargetStackContainsLabel(Handle<String> label);
=======================================
--- /branches/bleeding_edge/src/scopes.cc       Thu Feb 23 01:12:57 2012
+++ /branches/bleeding_edge/src/scopes.cc       Thu Mar  8 05:03:07 2012
@@ -67,7 +67,8 @@
     VariableMode mode,
     bool is_valid_lhs,
     Variable::Kind kind,
-    InitializationFlag initialization_flag) {
+    InitializationFlag initialization_flag,
+    Interface* interface) {
   Entry* p = ZoneHashMap::Lookup(name.location(), name->Hash(), true);
   if (p->value == NULL) {
     // The variable has not been declared yet -> insert it.
@@ -77,7 +78,8 @@
                             mode,
                             is_valid_lhs,
                             kind,
-                            initialization_flag);
+                            initialization_flag,
+                            interface);
   }
   return reinterpret_cast<Variable*>(p->value);
 }
@@ -105,6 +107,9 @@
       params_(4),
       unresolved_(16),
       decls_(4),
+      interface_(FLAG_harmony_modules &&
+                 (type == MODULE_SCOPE || type == GLOBAL_SCOPE)
+                     ? Interface::NewModule() : NULL),
       already_resolved_(false) {
   SetDefaults(type, outer_scope, Handle<ScopeInfo>::null());
   // At some point we might want to provide outer scopes to
@@ -125,6 +130,7 @@
       params_(4),
       unresolved_(16),
       decls_(4),
+      interface_(NULL),
       already_resolved_(true) {
   SetDefaults(type, NULL, scope_info);
   if (!scope_info.is_null()) {
@@ -145,6 +151,7 @@
       params_(0),
       unresolved_(0),
       decls_(0),
+      interface_(NULL),
       already_resolved_(true) {
   SetDefaults(CATCH_SCOPE, NULL, Handle<ScopeInfo>::null());
   AddInnerScope(inner_scope);
@@ -255,7 +262,7 @@
   // Allocate the variables.
   {
     AstNodeFactory<AstNullVisitor> ast_node_factory(info->isolate());
-    top->AllocateVariables(info->global_scope(), &ast_node_factory);
+    if (!top->AllocateVariables(info, &ast_node_factory)) return false;
   }

 #ifdef DEBUG
@@ -264,6 +271,11 @@
           : FLAG_print_scopes) {
     scope->Print();
   }
+
+ if (FLAG_harmony_modules && FLAG_print_interfaces && top->is_global_scope()) {
+    PrintF("global : ");
+    top->interface()->Print();
+  }
 #endif

   if (FLAG_harmony_scoping) {
@@ -438,7 +450,8 @@

 Variable* Scope::DeclareLocal(Handle<String> name,
                               VariableMode mode,
-                              InitializationFlag init_flag) {
+                              InitializationFlag init_flag,
+                              Interface* interface) {
   ASSERT(!already_resolved());
   // This function handles VAR and CONST modes.  DYNAMIC variables are
// introduces during variable allocation, INTERNAL variables are allocated
@@ -448,8 +461,8 @@
          mode == CONST_HARMONY ||
          mode == LET);
   ++num_var_or_const_;
-  return
- variables_.Declare(this, name, mode, true, Variable::NORMAL, init_flag);
+  return variables_.Declare(
+      this, name, mode, true, Variable::NORMAL, init_flag, interface);
 }


@@ -586,7 +599,7 @@
 }


-void Scope::AllocateVariables(Scope* global_scope,
+bool Scope::AllocateVariables(CompilationInfo* info,
                               AstNodeFactory<AstNullVisitor>* factory) {
   // 1) Propagate scope information.
   bool outer_scope_calls_non_strict_eval = false;
@@ -598,10 +611,12 @@
   PropagateScopeInfo(outer_scope_calls_non_strict_eval);

   // 2) Resolve variables.
-  ResolveVariablesRecursively(global_scope, factory);
+  if (!ResolveVariablesRecursively(info, factory)) return false;

   // 3) Allocate variables.
   AllocateVariablesRecursively();
+
+  return true;
 }


@@ -916,14 +931,14 @@
 }


-void Scope::ResolveVariable(Scope* global_scope,
+bool Scope::ResolveVariable(CompilationInfo* info,
                             VariableProxy* proxy,
                             AstNodeFactory<AstNullVisitor>* factory) {
-  ASSERT(global_scope == NULL || global_scope->is_global_scope());
+  ASSERT(info->global_scope()->is_global_scope());

   // If the proxy is already resolved there's nothing to do
   // (functions and consts may be resolved by the parser).
-  if (proxy->var() != NULL) return;
+  if (proxy->var() != NULL) return true;

   // Otherwise, try to resolve the variable.
   BindingKind binding_kind;
@@ -947,8 +962,7 @@

     case UNBOUND:
       // No binding has been found. Declare a variable in global scope.
-      ASSERT(global_scope != NULL);
-      var = global_scope->DeclareGlobal(proxy->name());
+      var = info->global_scope()->DeclareGlobal(proxy->name());
       break;

     case UNBOUND_EVAL_SHADOWED:
@@ -965,23 +979,62 @@

   ASSERT(var != NULL);
   proxy->BindTo(var);
+
+  if (FLAG_harmony_modules) {
+    bool ok;
+#ifdef DEBUG
+    if (FLAG_print_interface_details)
+      PrintF("# Resolve %s:\n", var->name()->ToAsciiArray());
+#endif
+    proxy->interface()->Unify(var->interface(), &ok);
+    if (!ok) {
+#ifdef DEBUG
+      if (FLAG_print_interfaces) {
+        PrintF("SCOPES TYPE ERROR\n");
+        PrintF("proxy: ");
+        proxy->interface()->Print();
+        PrintF("var: ");
+        var->interface()->Print();
+      }
+#endif
+
+      // Inconsistent use of module. Throw a syntax error.
+      // TODO(rossberg): generate more helpful error message.
+      MessageLocation location(info->script(),
+                               proxy->position(),
+                               proxy->position());
+      Isolate* isolate = Isolate::Current();
+      Factory* factory = isolate->factory();
+      Handle<JSArray> array = factory->NewJSArray(1);
+      array->SetElement(array, 0, var->name(), NONE, kStrictMode);
+      Handle<Object> result =
+          factory->NewSyntaxError("module_type_error", array);
+      isolate->Throw(*result, &location);
+      return false;
+    }
+  }
+
+  return true;
 }


-void Scope::ResolveVariablesRecursively(
-    Scope* global_scope,
+bool Scope::ResolveVariablesRecursively(
+    CompilationInfo* info,
     AstNodeFactory<AstNullVisitor>* factory) {
-  ASSERT(global_scope == NULL || global_scope->is_global_scope());
+  ASSERT(info->global_scope()->is_global_scope());

   // Resolve unresolved variables for this scope.
   for (int i = 0; i < unresolved_.length(); i++) {
-    ResolveVariable(global_scope, unresolved_[i], factory);
+    if (!ResolveVariable(info, unresolved_[i], factory)) return false;
   }

   // Resolve unresolved variables for inner scopes.
   for (int i = 0; i < inner_scopes_.length(); i++) {
-    inner_scopes_[i]->ResolveVariablesRecursively(global_scope, factory);
-  }
+    if (!inner_scopes_[i]->ResolveVariablesRecursively(info, factory))
+      return false;
+  }
+
+  return true;
 }


=======================================
--- /branches/bleeding_edge/src/scopes.h        Wed Feb 29 07:08:02 2012
+++ /branches/bleeding_edge/src/scopes.h        Thu Mar  8 05:03:07 2012
@@ -49,7 +49,8 @@
                     VariableMode mode,
                     bool is_valid_lhs,
                     Variable::Kind kind,
-                    InitializationFlag initialization_flag);
+                    InitializationFlag initialization_flag,
+                    Interface* interface = Interface::NewValue());

   Variable* Lookup(Handle<String> name);
 };
@@ -145,7 +146,8 @@
   // declared before, the previously declared variable is returned.
   Variable* DeclareLocal(Handle<String> name,
                          VariableMode mode,
-                         InitializationFlag init_flag);
+                         InitializationFlag init_flag,
+                         Interface* interface = Interface::NewValue());

   // Declare an implicit global variable in this scope which must be a
   // global scope.  The variable was introduced (possibly from an inner
@@ -157,12 +159,14 @@
   template<class Visitor>
   VariableProxy* NewUnresolved(AstNodeFactory<Visitor>* factory,
                                Handle<String> name,
-                               int position = RelocInfo::kNoPosition) {
+                               int position = RelocInfo::kNoPosition,
+ Interface* interface = Interface::NewValue()) {
     // Note that we must not share the unresolved variables with
     // the same name because they may be removed selectively via
     // RemoveUnresolved().
     ASSERT(!already_resolved());
- VariableProxy* proxy = factory->NewVariableProxy(name, false, position);
+    VariableProxy* proxy =
+        factory->NewVariableProxy(name, false, position, interface);
     unresolved_.Add(proxy);
     return proxy;
   }
@@ -294,9 +298,6 @@
   bool inside_with() const { return scope_inside_with_; }
   // Does this scope contain a with statement.
   bool contains_with() const { return scope_contains_with_; }
-
-  // The scope immediately surrounding this scope, or NULL.
-  Scope* outer_scope() const { return outer_scope_; }

// ---------------------------------------------------------------------------
   // Accessors.
@@ -335,6 +336,12 @@

   // Inner scope list.
   ZoneList<Scope*>* inner_scopes() { return &inner_scopes_; }
+
+  // The scope immediately surrounding this scope, or NULL.
+  Scope* outer_scope() const { return outer_scope_; }
+
+  // The interface as inferred so far; only for module scopes.
+  Interface* interface() const { return interface_; }

// ---------------------------------------------------------------------------
   // Variable allocation.
@@ -345,17 +352,6 @@
   void CollectStackAndContextLocals(ZoneList<Variable*>* stack_locals,
                                     ZoneList<Variable*>* context_locals);

-  // Resolve and fill in the allocation information for all variables
-  // in this scopes. Must be called *after* all scopes have been
-  // processed (parsed) to ensure that unresolved variables can be
-  // resolved properly.
-  //
-  // In the case of code compiled and run using 'eval', the context
-  // parameter is the context in which eval was called.  In all other
-  // cases the context parameter is an empty handle.
-  void AllocateVariables(Scope* global_scope,
-                         AstNodeFactory<AstNullVisitor>* factory);
-
   // Current number of var or const locals.
   int num_var_or_const() { return num_var_or_const_; }

@@ -453,6 +449,8 @@
   VariableProxy* function_;
   // Convenience variable; function scopes only.
   Variable* arguments_;
+  // Interface; module scopes only.
+  Interface* interface_;

   // Illegal redeclaration.
   Expression* illegal_redecl_;
@@ -548,10 +546,12 @@
   Variable* LookupRecursive(Handle<String> name,
                             BindingKind* binding_kind,
                             AstNodeFactory<AstNullVisitor>* factory);
-  void ResolveVariable(Scope* global_scope,
+  MUST_USE_RESULT
+  bool ResolveVariable(CompilationInfo* info,
                        VariableProxy* proxy,
                        AstNodeFactory<AstNullVisitor>* factory);
-  void ResolveVariablesRecursively(Scope* global_scope,
+  MUST_USE_RESULT
+  bool ResolveVariablesRecursively(CompilationInfo* info,
AstNodeFactory<AstNullVisitor>* factory);

   // Scope analysis.
@@ -571,6 +571,18 @@
   void AllocateNonParameterLocals();
   void AllocateVariablesRecursively();

+  // Resolve and fill in the allocation information for all variables
+  // in this scopes. Must be called *after* all scopes have been
+  // processed (parsed) to ensure that unresolved variables can be
+  // resolved properly.
+  //
+  // In the case of code compiled and run using 'eval', the context
+  // parameter is the context in which eval was called.  In all other
+  // cases the context parameter is an empty handle.
+  MUST_USE_RESULT
+  bool AllocateVariables(CompilationInfo* info,
+                         AstNodeFactory<AstNullVisitor>* factory);
+
  private:
   // Construct a scope based on the scope info.
   Scope(Scope* inner_scope, ScopeType type, Handle<ScopeInfo> scope_info);
=======================================
--- /branches/bleeding_edge/src/variables.cc    Tue Nov  8 05:28:53 2011
+++ /branches/bleeding_edge/src/variables.cc    Thu Mar  8 05:03:07 2012
@@ -59,7 +59,8 @@
                    VariableMode mode,
                    bool is_valid_LHS,
                    Kind kind,
-                   InitializationFlag initialization_flag)
+                   InitializationFlag initialization_flag,
+                   Interface* interface)
   : scope_(scope),
     name_(name),
     mode_(mode),
@@ -71,7 +72,8 @@
     is_valid_LHS_(is_valid_LHS),
     force_context_allocation_(false),
     is_used_(false),
-    initialization_flag_(initialization_flag) {
+    initialization_flag_(initialization_flag),
+    interface_(interface) {
   // Names must be canonicalized for fast equality checks.
   ASSERT(name->IsSymbol());
   // Var declared variables never need initialization.
=======================================
--- /branches/bleeding_edge/src/variables.h     Tue Nov  8 05:28:53 2011
+++ /branches/bleeding_edge/src/variables.h     Thu Mar  8 05:03:07 2012
@@ -29,6 +29,7 @@
 #define V8_VARIABLES_H_

 #include "zone.h"
+#include "interface.h"

 namespace v8 {
 namespace internal {
@@ -78,7 +79,8 @@
            VariableMode mode,
            bool is_valid_lhs,
            Kind kind,
-           InitializationFlag initialization_flag);
+           InitializationFlag initialization_flag,
+           Interface* interface = Interface::NewValue());

   // Printing support
   static const char* Mode2String(VariableMode mode);
@@ -153,6 +155,7 @@
   InitializationFlag initialization_flag() const {
     return initialization_flag_;
   }
+  Interface* interface() const { return interface_; }

   void AllocateTo(Location location, int index) {
     location_ = location;
@@ -183,6 +186,9 @@
   bool force_context_allocation_;  // set by variable resolver
   bool is_used_;
   InitializationFlag initialization_flag_;
+
+  // Module type info.
+  Interface* interface_;
 };


=======================================
--- /branches/bleeding_edge/test/mjsunit/harmony/module-parsing.js Wed Feb 29 04:12:52 2012 +++ /branches/bleeding_edge/test/mjsunit/harmony/module-parsing.js Thu Mar 8 05:03:07 2012
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
@@ -27,7 +27,7 @@

 // Flags: --harmony-modules

-// Test basic module syntax, with and without ASI.
+// Test basic module syntax, with and without automatic semicolon insertion.

 module A {}

@@ -36,8 +36,8 @@
 module A3 = A2

 module B {
-  export x
-  export y, z, c, f
+  export vx
+  export vy, lz, c, f

   var vx
   var vx, vy;
@@ -47,9 +47,11 @@
   const c = 9
   function f() {}

-  module C {
+  module C0 {}
+
+  export module C {
     let x
-    module D {}
+    export module D { export let x }
     let y
   }

@@ -67,9 +69,14 @@
   export module M3 at "http://where";

   import i0 from I
-  import i1, i2, i3 from I
+  import i1, i2, i3, M from I
   import i4, i5 from "http://where";
 }
+
+module I {
+  export let i0, i1, i2, i3;
+  export module M {}
+}

 module C1 = B.C;
 module D1 = B.C.D
@@ -80,7 +87,6 @@
 module E2 at "http://where";;
 module E3 = E1.F

-
 // Check that ASI does not interfere.

 module X
@@ -103,6 +109,7 @@
 from
 "file://local"

+
 module Wrap {
 export
 x
@@ -134,6 +141,9 @@
 {
 }
 }
+
+export A, A1, A2, A3, B, I, C1, D1, D2, D3, E1, E2, E3, X, Y, Z, Wrap, x, y, UU
+


 // Check that 'module' still works as an identifier.
=======================================
--- /branches/bleeding_edge/tools/gyp/v8.gyp    Thu Feb 23 01:12:57 2012
+++ /branches/bleeding_edge/tools/gyp/v8.gyp    Thu Mar  8 05:03:07 2012
@@ -342,6 +342,8 @@
             '../../src/incremental-marking.h',
             '../../src/inspector.cc',
             '../../src/inspector.h',
+            '../../src/interface.cc',
+            '../../src/interface.h',
             '../../src/interpreter-irregexp.cc',
             '../../src/interpreter-irregexp.h',
             '../../src/json-parser.h',

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to