VM: [Kernel] Set types on [LocalVariable] if they were introduced by [VariableDeclaration]s

R=vegorov@google.com

Review URL: https://codereview.chromium.org/2477563003 .
diff --git a/runtime/vm/kernel_to_il.cc b/runtime/vm/kernel_to_il.cc
index 38900f1..02f5437 100644
--- a/runtime/vm/kernel_to_il.cc
+++ b/runtime/vm/kernel_to_il.cc
@@ -30,6 +30,33 @@
 #define I Isolate::Current()
 
 
+static void DiscoverEnclosingElements(Zone* zone,
+                                      const Function& function,
+                                      Function* outermost_function,
+                                      TreeNode** outermost_node,
+                                      Class** klass) {
+  // Find out if there is an enclosing kernel class (which will be used to
+  // resolve type parameters).
+  *outermost_function = function.raw();
+  while (outermost_function->parent_function() != Object::null()) {
+    *outermost_function = outermost_function->parent_function();
+  }
+  *outermost_node =
+      static_cast<TreeNode*>(outermost_function->kernel_function());
+  if (*outermost_node != NULL) {
+    TreeNode* parent = NULL;
+    if ((*outermost_node)->IsProcedure()) {
+      parent = Procedure::Cast(*outermost_node)->parent();
+    } else if ((*outermost_node)->IsConstructor()) {
+      parent = Constructor::Cast(*outermost_node)->parent();
+    } else if ((*outermost_node)->IsField()) {
+      parent = Field::Cast(*outermost_node)->parent();
+    }
+    if (parent != NULL && parent->IsClass()) *klass = Class::Cast(parent);
+  }
+}
+
+
 void ScopeBuilder::EnterScope(TreeNode* node) {
   scope_ = new (Z) LocalScope(scope_, depth_.function_, depth_.loop_);
   result_->scopes.Insert(node, scope_);
@@ -39,17 +66,8 @@
 void ScopeBuilder::ExitScope() { scope_ = scope_->parent(); }
 
 
-LocalVariable* ScopeBuilder::MakeVariable(const dart::String& name) {
-  return new (Z)
-      LocalVariable(TokenPosition::kNoSource,
-                    TokenPosition::kNoSource,
-                    name,
-                    Object::dynamic_type());
-}
-
-
 LocalVariable* ScopeBuilder::MakeVariable(const dart::String& name,
-                                          const Type& type) {
+                                          const AbstractType& type) {
   return new (Z) LocalVariable(TokenPosition::kNoSource,
                                TokenPosition::kNoSource,
                                name,
@@ -71,7 +89,9 @@
 
 void ScopeBuilder::AddParameter(VariableDeclaration* declaration,
                                 intptr_t pos) {
-  LocalVariable* variable = MakeVariable(H.DartSymbol(declaration->name()));
+  LocalVariable* variable =
+      MakeVariable(H.DartSymbol(declaration->name()),
+                   T.TranslateVariableType(declaration));
   if (declaration->IsFinal()) {
     variable->set_is_final();
   }
@@ -117,7 +137,8 @@
   // If variable was not lifted by the transformer introduce a new
   // one into the current function scope.
   if (v == NULL) {
-    v = MakeVariable(GenerateName(prefix, nesting_depth - 1));
+    v = MakeVariable(GenerateName(prefix, nesting_depth - 1),
+                     AbstractType::dynamic_type());
 
     // If transformer did not lift the variable then there is no need
     // to lift it into the context when we encouter a YieldStatement.
@@ -149,7 +170,8 @@
 
   ASSERT(result_->iterator_variables.length() == depth_.for_in_ - 1);
   LocalVariable* iterator =
-      MakeVariable(GenerateName(":iterator", depth_.for_in_ - 1));
+      MakeVariable(GenerateName(":iterator", depth_.for_in_ - 1),
+                   AbstractType::dynamic_type());
   current_function_scope_->AddVariable(iterator);
   result_->iterator_variables.Add(iterator);
 }
@@ -213,7 +235,8 @@
   const dart::String& name = declaration->name()->is_empty()
                                  ? GenerateName(":var", name_index_++)
                                  : H.DartSymbol(declaration->name());
-  LocalVariable* variable = MakeVariable(name);
+  LocalVariable* variable =
+      MakeVariable(name, T.TranslateVariableType(declaration));
   if (declaration->IsFinal()) {
     variable->set_is_final();
   }
@@ -238,6 +261,25 @@
   ParsedFunction* parsed_function = parsed_function_;
   const dart::Function& function = parsed_function->function();
 
+  // Setup a [ActiveClassScope] and a [ActiveMemberScope] which will be used
+  // e.g. for type translation.
+  const dart::Class& klass =
+      dart::Class::Handle(zone_, parsed_function_->function().Owner());
+  Function& outermost_function = Function::Handle(Z);
+  TreeNode* outermost_node = NULL;
+  Class* kernel_klass = NULL;
+  DiscoverEnclosingElements(
+      Z, function, &outermost_function, &outermost_node, &kernel_klass);
+  // Use [klass]/[kernel_klass] as active class.  Type parameters will get
+  // resolved via [kernel_klass] unless we are nested inside a static factory
+  // in which case we will use [member].
+  ActiveClassScope active_class_scope(&active_class_, kernel_klass, &klass);
+  Member* member = ((outermost_node != NULL) && outermost_node->IsMember())
+                       ? Member::Cast(outermost_node)
+                       : NULL;
+  ActiveMemberScope active_member(&active_class_, member);
+
+
   LocalScope* enclosing_scope = NULL;
   if (function.IsLocalFunction()) {
     enclosing_scope = LocalScope::RestoreOuterScope(
@@ -271,7 +313,9 @@
 
       intptr_t pos = 0;
       if (function.IsClosureFunction()) {
-        LocalVariable* variable = MakeVariable(Symbols::ClosureParameter());
+        LocalVariable* variable =
+            MakeVariable(Symbols::ClosureParameter(),
+                         AbstractType::dynamic_type());
         variable->set_is_forced_stack();
         scope_->InsertParameterAt(pos++, variable);
       } else if (!function.is_static()) {
@@ -299,7 +343,8 @@
         }
       } else if (function.IsFactory()) {
         LocalVariable* variable = MakeVariable(
-            Symbols::TypeArgumentsParameter(), AbstractType::dynamic_type());
+            Symbols::TypeArgumentsParameter(),
+            AbstractType::dynamic_type());
         scope_->InsertParameterAt(pos++, variable);
         result_->type_arguments_variable = variable;
       }
@@ -332,7 +377,8 @@
         result_->this_variable = variable;
       }
       if (is_setter) {
-        result_->setter_value = MakeVariable(Symbols::Value());
+        result_->setter_value = MakeVariable(
+            Symbols::Value(), AbstractType::dynamic_type());
         scope_->InsertParameterAt(pos++, result_->setter_value);
       }
       break;
@@ -353,7 +399,8 @@
     case RawFunction::kInvokeFieldDispatcher:
       for (intptr_t i = 0; i < function.NumParameters(); ++i) {
         LocalVariable* variable = MakeVariable(
-            dart::String::ZoneHandle(Z, function.ParameterNameAt(i)));
+            dart::String::ZoneHandle(Z, function.ParameterNameAt(i)),
+            AbstractType::dynamic_type());
         scope_->InsertParameterAt(i, variable);
       }
       break;
@@ -528,7 +575,9 @@
 
 void ScopeBuilder::AddSwitchVariable() {
   if ((depth_.function_ == 0) && (result_->switch_variable == NULL)) {
-    LocalVariable* variable = MakeVariable(Symbols::SwitchExpr());
+    LocalVariable* variable = MakeVariable(
+        Symbols::SwitchExpr(),
+        AbstractType::dynamic_type());
     variable->set_is_forced_stack();
     current_function_scope_->AddVariable(variable);
     result_->switch_variable = variable;
@@ -546,7 +595,9 @@
   if ((depth_.function_ == 0) && (depth_.finally_ > 0) &&
       (result_->finally_return_variable == NULL)) {
     const dart::String& name = H.DartSymbol(":try_finally_return_value");
-    LocalVariable* variable = MakeVariable(name);
+    LocalVariable* variable = MakeVariable(
+        name,
+        AbstractType::dynamic_type());
     current_function_scope_->AddVariable(variable);
     result_->finally_return_variable = variable;
   }
@@ -2731,34 +2782,18 @@
   dart::Class& klass =
       dart::Class::Handle(zone_, parsed_function_->function().Owner());
 
-  // Find out if there is an enclosing kernel class (which will be used to
-  // resolve type parameters).
+  Function& outermost_function = Function::Handle(Z);
+  TreeNode* outermost_node = NULL;
   Class* kernel_klass = NULL;
-  dart::Function& topmost = dart::Function::Handle(Z, function.raw());
-  while (topmost.parent_function() != Object::null()) {
-    topmost = topmost.parent_function();
-  }
-  TreeNode* topmost_node = static_cast<TreeNode*>(topmost.kernel_function());
-  if (topmost_node != NULL) {
-    // Going up the closure->parent chain needs to result in a Procedure or
-    // Constructor.
-    TreeNode* parent = NULL;
-    if (topmost_node->IsProcedure()) {
-      parent = Procedure::Cast(topmost_node)->parent();
-    } else if (topmost_node->IsConstructor()) {
-      parent = Constructor::Cast(topmost_node)->parent();
-    } else if (topmost_node->IsField()) {
-      parent = Field::Cast(topmost_node)->parent();
-    }
-    if (parent != NULL && parent->IsClass()) kernel_klass = Class::Cast(parent);
-  }
+  DiscoverEnclosingElements(
+      Z, function, &outermost_function, &outermost_node, &kernel_klass);
 
   // Mark that we are using [klass]/[kernell_klass] as active class.  Resolving
   // of type parameters will get resolved via [kernell_klass] unless we are
   // nested inside a static factory in which case we will use [member].
   ActiveClassScope active_class_scope(&active_class_, kernel_klass, &klass);
-  Member* member = topmost_node != NULL && topmost_node->IsMember()
-                       ? Member::Cast(topmost_node)
+  Member* member = ((outermost_node != NULL) && outermost_node->IsMember())
+                       ? Member::Cast(outermost_node)
                        : NULL;
   ActiveMemberScope active_member(&active_class_, member);
 
@@ -2846,12 +2881,12 @@
       LocalVariable* variable = scope->VariableAt(i);
       if (variable->is_captured()) {
         // There is no LocalVariable describing the on-stack parameter so
-        // create one directly.
+        // create one directly and use the same type.
         LocalVariable* parameter =
             new (Z) LocalVariable(TokenPosition::kNoSource,
                                   TokenPosition::kNoSource,
                                   Symbols::TempParam(),
-                                  Object::dynamic_type());
+                                  variable->type());
         parameter->set_index(parameter_index);
         // Mark the stack variable so it will be ignored by the code for
         // try/catch.
@@ -3804,6 +3839,24 @@
 }
 
 
+const AbstractType& DartTypeTranslator::TranslateVariableType(
+    VariableDeclaration* variable) {
+  AbstractType& abstract_type = TranslateType(variable->type());
+
+  // We return a new `ZoneHandle` here on purpose: The intermediate language
+  // instructions do not make a copy of the handle, so we do it.
+  AbstractType& type = Type::ZoneHandle(Z);
+
+  if (abstract_type.IsMalformed()) {
+    type = AbstractType::dynamic_type().raw();
+  } else {
+    type = result_.raw();
+  }
+
+  return type;
+}
+
+
 void DartTypeTranslator::VisitInvalidType(InvalidType* node) {
   result_ = ClassFinalizer::NewFinalizedMalformedType(
       Error::Handle(Z),  // No previous error.
diff --git a/runtime/vm/kernel_to_il.h b/runtime/vm/kernel_to_il.h
index eb3beca..6a62834 100644
--- a/runtime/vm/kernel_to_il.h
+++ b/runtime/vm/kernel_to_il.h
@@ -296,6 +296,9 @@
   // Can return a malformed type.
   AbstractType& TranslateTypeWithoutFinalization(DartType* node);
 
+  // Is guaranteed to be not malformed.
+  const AbstractType& TranslateVariableType(VariableDeclaration* variable);
+
 
   virtual void VisitDefaultDartType(DartType* node) { UNREACHABLE(); }
 
@@ -494,6 +497,7 @@
         node_(node),
         zone_(Thread::Current()->zone()),
         translation_helper_(Thread::Current(), zone_, Isolate::Current()),
+        type_translator_(&translation_helper_, &active_class_),
         current_function_scope_(NULL),
         scope_(NULL),
         depth_(0),
@@ -534,8 +538,9 @@
   void EnterScope(TreeNode* node);
   void ExitScope();
 
-  LocalVariable* MakeVariable(const dart::String& name);
-  LocalVariable* MakeVariable(const dart::String& name, const Type& type);
+  const Type& TranslateVariableType(VariableDeclaration* variable);
+  LocalVariable* MakeVariable(const dart::String& name,
+                              const AbstractType& type);
 
   void AddParameters(FunctionNode* function, intptr_t pos = 0);
   void AddParameter(VariableDeclaration* declaration, intptr_t pos);
@@ -581,9 +586,11 @@
   ParsedFunction* parsed_function_;
   TreeNode* node_;
 
+  ActiveClass active_class_;
+
   Zone* zone_;
   TranslationHelper translation_helper_;
-
+  DartTypeTranslator type_translator_;
 
   FunctionNode* current_function_node_;
   LocalScope* current_function_scope_;