Implement constructor kinds in the VM mirrors.

BUG=http://dartbug.com/13798
R=asiva@google.com, hausner@google.com

Review URL: https://codereview.chromium.org//26436004

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@28416 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index be30b5d..59ac369 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -261,12 +261,14 @@
   args.SetAt(4, Bool::Get(func.is_abstract()));
   args.SetAt(5, Bool::Get(func.IsGetterFunction()));
   args.SetAt(6, Bool::Get(func.IsSetterFunction()));
-  args.SetAt(7, Bool::Get(func.kind() == RawFunction::kConstructor));
-  // TODO(mlippautz): Implement different constructor kinds.
-  args.SetAt(8, Bool::False());
-  args.SetAt(9, Bool::False());
-  args.SetAt(10, Bool::False());
-  args.SetAt(11, Bool::False());
+
+  bool isConstructor = (func.kind() == RawFunction::kConstructor);
+  args.SetAt(7, Bool::Get(isConstructor));
+  args.SetAt(8, Bool::Get(isConstructor && func.is_const()));
+  args.SetAt(9, Bool::Get(isConstructor && func.IsConstructor()));
+  args.SetAt(10, Bool::Get(isConstructor && func.is_redirecting()));
+  args.SetAt(11, Bool::Get(isConstructor && func.IsFactory()));
+
   return CreateMirror(Symbols::_LocalMethodMirrorImpl(), args);
 }
 
diff --git a/runtime/tests/vm/dart/isolate_mirror_local_test.dart b/runtime/tests/vm/dart/isolate_mirror_local_test.dart
index b07be27..f544f8c 100644
--- a/runtime/tests/vm/dart/isolate_mirror_local_test.dart
+++ b/runtime/tests/vm/dart/isolate_mirror_local_test.dart
@@ -252,11 +252,12 @@
 
   func = cls_mirror.constructors[const Symbol('MyClass')];
   Expect.isTrue(func is MethodMirror);
-  Expect.equals('MyClass return(MyClass) constructor', buildMethodString(func));
+  Expect.equals('MyClass return(MyClass) constructor generative',
+                buildMethodString(func));
 
   func = cls_mirror.constructors[const Symbol('MyClass.named')];
   Expect.isTrue(func is MethodMirror);
-  Expect.equals('MyClass.named return(MyClass) constructor',
+  Expect.equals('MyClass.named return(MyClass) constructor generative',
                 buildMethodString(func));
 
   func = generic_cls_mirror.members[const Symbol('method')];
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 4852fb8..3564c2c 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -4197,6 +4197,11 @@
 }
 
 
+void Function::set_is_redirecting(bool value) const {
+  set_kind_tag(RedirectingBit::update(value, raw_ptr()->kind_tag_));
+}
+
+
 void Function::set_is_static(bool value) const {
   set_kind_tag(StaticBit::update(value, raw_ptr()->kind_tag_));
 }
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 30ce9f7..30ffe5a 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -1699,6 +1699,11 @@
   }
   void set_is_recognized(bool value) const;
 
+  bool is_redirecting() const {
+    return RedirectingBit::decode(raw_ptr()->kind_tag_);
+  }
+  void set_is_redirecting(bool value) const;
+
   bool HasOptimizedCode() const;
 
   // Returns true if the argument counts are valid for calling this function.
@@ -1858,7 +1863,8 @@
     kVisibleBit = 8,
     kIntrinsicBit = 9,
     kRecognizedBit = 10,
-    kKindTagBit = 11,
+    kRedirectingBit = 11,
+    kKindTagBit = 12,
     kKindTagSize = 4,
   };
   class StaticBit : public BitField<bool, kStaticBit, 1> {};
@@ -1872,6 +1878,7 @@
   class VisibleBit : public BitField<bool, kVisibleBit, 1> {};
   class IntrinsicBit : public BitField<bool, kIntrinsicBit, 1> {};
   class RecognizedBit : public BitField<bool, kRecognizedBit, 1> {};
+  class RedirectingBit : public BitField<bool, kRedirectingBit, 1> {};
   class KindBits :
     public BitField<RawFunction::Kind, kKindTagBit, kKindTagSize> {};  // NOLINT
 
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 7ffeeb8..438dc5f 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -3121,9 +3121,11 @@
   // Parse redirecting factory constructor.
   Type& redirection_type = Type::Handle();
   String& redirection_identifier = String::Handle();
+  bool is_redirecting = false;
   if (method->IsFactory() && (CurrentToken() == Token::kASSIGN)) {
     ConsumeToken();
     const intptr_t type_pos = TokenPos();
+    is_redirecting = true;
     const AbstractType& type = AbstractType::Handle(
         ParseType(ClassFinalizer::kResolveTypeParameters));
     if (!type.IsMalformed() && type.IsTypeParameter()) {
@@ -3153,6 +3155,7 @@
         ((LookaheadToken(2) == Token::kLPAREN) ||
          LookaheadToken(4) == Token::kLPAREN)) {
       // Redirected constructor: either this(...) or this.xxx(...).
+      is_redirecting = true;
       if (method->params.has_field_initializer) {
         // Constructors that redirect to another constructor must not
         // initialize any fields using field initializer parameters.
@@ -3287,6 +3290,7 @@
                     method->decl_begin_pos));
   func.set_result_type(*method->type);
   func.set_end_token_pos(method_end_pos);
+  func.set_is_redirecting(is_redirecting);
   if (method->metadata_pos > 0) {
     library_.AddFunctionMetadata(func, method->metadata_pos);
   }
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 9b62a13..daf4ba1 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -155,7 +155,6 @@
 mirrors/typedef_test/01: Fail, OK # Incorrect dart2js behavior.
 mirrors/closures_test/01: Fail, OK # Incorrect dart2js behavior.
 
-mirrors/constructor_kinds_test: RuntimeError # Issue 13798
 mirrors/generics_substitution_test: RuntimeError # Issue 13808
 mirrors/generic_function_typedef_test: RuntimeError # Issue 12282
 mirrors/generic_mixin_applications_test: RuntimeError # Issue 12282
@@ -209,7 +208,6 @@
 mirrors/mixin_test/01: Fail # Issue 13719: Please triage this failure.
 mirrors/typedef_test/01: Fail # Issue 13719: Please triage this failure.
 
-mirrors/constructor_kinds_test: RuntimeError # Issue 13798
 mirrors/generics_substitution_test: RuntimeError # Issue 13808
 mirrors/generic_function_typedef_test: RuntimeError # Issue 12282
 mirrors/generic_mixin_applications_test: RuntimeError # Issue 12282
diff --git a/tests/lib/mirrors/constructor_kinds_test.dart b/tests/lib/mirrors/constructor_kinds_test.dart
index f3339ca..febac1f 100644
--- a/tests/lib/mirrors/constructor_kinds_test.dart
+++ b/tests/lib/mirrors/constructor_kinds_test.dart
@@ -10,29 +10,36 @@
 class ClassWithDefaultConstructor {}
 
 class Class {
-  Class.generative();
-  Class.redirectingGenerative() : this.generative();
-  factory Class.faktory () => new Class.generative();
-  factory Class.redirectingFactory() = Class.faktory;
+  Class.generativeConstructor();
+  Class.redirectingGenerativeConstructor() : this.generativeConstructor();
+  factory Class.factoryConstructor() => new Class.generativeConstructor();
+  factory Class.redirectingFactoryConstructor() = Class.factoryConstructor;
 
-  const Class.constGenerative();
-  const Class.constRedirectingGenerative() : this.constGenerative();
+  const Class.constGenerativeConstructor();
+  const Class.constRedirectingGenerativeConstructor()
+      : this.constGenerativeConstructor();
   // Not legal.
-  // const factory Class.constFaktory () => const Class.constGenerative();
-  const factory Class.constRedirectingFactory() = Class.constGenerative;
+  // const factory Class.constFactoryConstructor() => ...
+  const factory Class.constRedirectingFactoryConstructor()
+      = Class.constGenerativeConstructor;
 }
 
 main() {
   ClassMirror cm;
   MethodMirror mm;
 
-  new Class.generative();  
-  new Class.redirectingGenerative();
-  new Class.faktory();
-  new Class.redirectingFactory();
-  const Class.constGenerative();
-  const Class.constRedirectingGenerative();
-  const Class.constRedirectingFactory();
+  // Multitest with and without constructor calls. On the VM, we want to check
+  // that constructor properties are correctly set even if the constructor
+  // hasn't been fully compiled. On dart2js, we want to check that constructors
+  // are retain even if there are no base-level calls.
+  new ClassWithDefaultConstructor();  /// 01: ok
+  new Class.generativeConstructor();  /// 01: ok
+  new Class.redirectingGenerativeConstructor();  /// 01: ok
+  new Class.factoryConstructor();  /// 01: ok
+  new Class.redirectingFactoryConstructor();  /// 01: ok
+  const Class.constGenerativeConstructor();  /// 01: ok
+  const Class.constRedirectingGenerativeConstructor();  /// 01: ok
+  const Class.constRedirectingFactoryConstructor();  /// 01: ok
 
   cm = reflectClass(ClassWithDefaultConstructor);
   mm = cm.constructors.values.single;
@@ -42,45 +49,44 @@
   Expect.isFalse(mm.isRedirectingConstructor);
   Expect.isFalse(mm.isConstConstructor);
 
-
   cm = reflectClass(Class);
 
-  mm = cm.constructors[#generative];
+  mm = cm.constructors[#Class.generativeConstructor];
   Expect.isTrue(mm.isConstructor);
   Expect.isTrue(mm.isGenerativeConstructor);
   Expect.isFalse(mm.isFactoryConstructor);
   Expect.isFalse(mm.isRedirectingConstructor);
   Expect.isFalse(mm.isConstConstructor);
 
-  mm = cm.constructors[#redirectingGenerative];
+  mm = cm.constructors[#Class.redirectingGenerativeConstructor];
   Expect.isTrue(mm.isConstructor);
   Expect.isTrue(mm.isGenerativeConstructor);
   Expect.isFalse(mm.isFactoryConstructor);
   Expect.isTrue(mm.isRedirectingConstructor);
   Expect.isFalse(mm.isConstConstructor);
 
-  mm = cm.constructors[#faktory];
+  mm = cm.constructors[#Class.factoryConstructor];
   Expect.isTrue(mm.isConstructor);
   Expect.isFalse(mm.isGenerativeConstructor);
   Expect.isTrue(mm.isFactoryConstructor);
   Expect.isFalse(mm.isRedirectingConstructor);
   Expect.isFalse(mm.isConstConstructor);
 
-  mm = cm.constructors[#redirectingFactory];
+  mm = cm.constructors[#Class.redirectingFactoryConstructor];
   Expect.isTrue(mm.isConstructor);
   Expect.isFalse(mm.isGenerativeConstructor);
   Expect.isTrue(mm.isFactoryConstructor);
   Expect.isTrue(mm.isRedirectingConstructor);
   Expect.isFalse(mm.isConstConstructor);
 
-  mm = cm.constructors[#constGenerative];
+  mm = cm.constructors[#Class.constGenerativeConstructor];
   Expect.isTrue(mm.isConstructor);
   Expect.isTrue(mm.isGenerativeConstructor);
   Expect.isFalse(mm.isFactoryConstructor);
   Expect.isFalse(mm.isRedirectingConstructor);
   Expect.isTrue(mm.isConstConstructor);
 
-  mm = cm.constructors[#constRedirectingGenerative];
+  mm = cm.constructors[#Class.constRedirectingGenerativeConstructor];
   Expect.isTrue(mm.isConstructor);
   Expect.isTrue(mm.isGenerativeConstructor);
   Expect.isFalse(mm.isFactoryConstructor);
@@ -88,14 +94,14 @@
   Expect.isTrue(mm.isConstConstructor);
 
   // Not legal.
-  // mm = cm.constructors[#constFaktory];
+  // mm = cm.constructors[#Class.constFactoryConstructor];
   // Expect.isTrue(mm.isConstructor);
   // Expect.isFalse(mm.isGenerativeConstructor);
   // Expect.isTrue(mm.isFactoryConstructor);
   // Expect.isFalse(mm.isRedirectingConstructor);
   // Expect.isTrue(mm.isConstConstructor);
 
-  mm = cm.constructors[#constRedirectingFactory];
+  mm = cm.constructors[#Class.constRedirectingFactoryConstructor];
   Expect.isTrue(mm.isConstructor);
   Expect.isFalse(mm.isGenerativeConstructor);
   Expect.isTrue(mm.isFactoryConstructor);