diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc index be30b5deb8d..59ac369d92b 100644 --- a/runtime/lib/mirrors.cc +++ b/runtime/lib/mirrors.cc @@ -261,12 +261,14 @@ static RawInstance* CreateMethodMirror(const Function& func, 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 b07be27c281..f544f8c2155 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 @@ void testRootLibraryMirror(LibraryMirror lib_mirror) { 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 4852fb8f201..3564c2c3c91 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -4197,6 +4197,11 @@ void Function::set_is_recognized(bool value) const { } +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 30ce9f77c20..30ffe5a75c8 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -1699,6 +1699,11 @@ class Function : public Object { } 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 @@ class Function : public Object { kVisibleBit = 8, kIntrinsicBit = 9, kRecognizedBit = 10, - kKindTagBit = 11, + kRedirectingBit = 11, + kKindTagBit = 12, kKindTagSize = 4, }; class StaticBit : public BitField {}; @@ -1872,6 +1878,7 @@ class Function : public Object { class VisibleBit : public BitField {}; class IntrinsicBit : public BitField {}; class RecognizedBit : public BitField {}; + class RedirectingBit : public BitField {}; class KindBits : public BitField {}; // NOLINT diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc index 7ffeeb86d1d..438dc5f3453 100644 --- a/runtime/vm/parser.cc +++ b/runtime/vm/parser.cc @@ -3121,9 +3121,11 @@ void Parser::ParseMethodOrConstructor(ClassDesc* members, MemberDesc* method) { // 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 @@ void Parser::ParseMethodOrConstructor(ClassDesc* members, MemberDesc* method) { ((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 @@ void Parser::ParseMethodOrConstructor(ClassDesc* members, MemberDesc* method) { 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 9b62a138955..daf4ba1dfa1 100644 --- a/tests/lib/lib.status +++ b/tests/lib/lib.status @@ -155,7 +155,6 @@ mirrors/mixin_test/01: Fail, OK # TODO(ahe): Slight broken test to ensure test c 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/local_isolate_test: Fail # Issue 13719: Please triage this failure. 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 f3339ca844e..febac1f6f79 100644 --- a/tests/lib/mirrors/constructor_kinds_test.dart +++ b/tests/lib/mirrors/constructor_kinds_test.dart @@ -10,29 +10,36 @@ import 'package:expect/expect.dart'; 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 @@ main() { 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 @@ main() { 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);