| Index: runtime/vm/parser.cc
|
| diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
|
| index a966b40a639cb4b29aff9cba5fcb7ee7b033ca80..725496d7658074d56a4b6f07e0f6116f62759662 100644
|
| --- a/runtime/vm/parser.cc
|
| +++ b/runtime/vm/parser.cc
|
| @@ -38,15 +38,17 @@
|
| namespace dart {
|
|
|
| DEFINE_FLAG(bool, enable_debug_break, false, "Allow use of break \"message\".");
|
| +DEFINE_FLAG(bool, enable_mirrors, true,
|
| + "Disable to make importing dart:mirrors an error.");
|
| DEFINE_FLAG(bool, load_deferred_eagerly, false,
|
| "Load deferred libraries eagerly.");
|
| DEFINE_FLAG(bool, trace_parser, false, "Trace parser operations.");
|
| DEFINE_FLAG(bool, warn_mixin_typedef, true, "Warning on legacy mixin typedef.");
|
| +
|
| +DECLARE_FLAG(bool, lazy_dispatchers);
|
| +DECLARE_FLAG(bool, load_deferred_eagerly);
|
| DECLARE_FLAG(bool, throw_on_javascript_int_overflow);
|
| DECLARE_FLAG(bool, warn_on_javascript_compatibility);
|
| -DEFINE_FLAG(bool, enable_mirrors, true,
|
| - "Disable to make importing dart:mirrors an error.");
|
| -DECLARE_FLAG(bool, lazy_dispatchers);
|
|
|
| // Quick access to the current isolate and zone.
|
| #define I (isolate())
|
| @@ -172,6 +174,9 @@ void ParsedFunction::SetRegExpCompileData(
|
|
|
|
|
| void ParsedFunction::AddDeferredPrefix(const LibraryPrefix& prefix) {
|
| + // 'deferred_prefixes_' are used to invalidate code, but no invalidation is
|
| + // needed if --load_deferred_eagerly.
|
| + ASSERT(!FLAG_load_deferred_eagerly);
|
| ASSERT(prefix.is_deferred_load());
|
| ASSERT(!prefix.is_loaded());
|
| for (intptr_t i = 0; i < deferred_prefixes_->length(); i++) {
|
| @@ -10038,8 +10043,19 @@ SequenceNode* Parser::NodeAsSequenceNode(intptr_t sequence_pos,
|
| }
|
|
|
|
|
| -AstNode* Parser::ThrowTypeError(intptr_t type_pos, const AbstractType& type) {
|
| +// Call _throwNewIfNotLoaded if prefix is not NULL, otherwise call _throwNew.
|
| +AstNode* Parser::ThrowTypeError(intptr_t type_pos, const AbstractType& type,
|
| + LibraryPrefix* prefix) {
|
| ArgumentListNode* arguments = new(Z) ArgumentListNode(type_pos);
|
| +
|
| + String& method_name = String::Handle(Z);
|
| + if (prefix == NULL) {
|
| + method_name = Library::PrivateCoreLibName(Symbols::ThrowNew()).raw();
|
| + } else {
|
| + arguments->Add(new(Z) LiteralNode(type_pos, *prefix));
|
| + method_name = Library::PrivateCoreLibName(
|
| + Symbols::ThrowNewIfNotLoaded()).raw();
|
| + }
|
| // Location argument.
|
| arguments->Add(new(Z) LiteralNode(
|
| type_pos, Integer::ZoneHandle(Z, Integer::New(type_pos))));
|
| @@ -10054,20 +10070,29 @@ AstNode* Parser::ThrowTypeError(intptr_t type_pos, const AbstractType& type) {
|
| ASSERT(!error.IsNull());
|
| arguments->Add(new(Z) LiteralNode(type_pos, String::ZoneHandle(Z,
|
| Symbols::New(error.ToErrorCString()))));
|
| - return MakeStaticCall(Symbols::TypeError(),
|
| - Library::PrivateCoreLibName(Symbols::ThrowNew()),
|
| - arguments);
|
| + return MakeStaticCall(Symbols::TypeError(), method_name, arguments);
|
| }
|
|
|
|
|
| +// Call _throwNewIfNotLoaded if prefix is not NULL, otherwise call _throwNew.
|
| AstNode* Parser::ThrowNoSuchMethodError(intptr_t call_pos,
|
| const Class& cls,
|
| const String& function_name,
|
| ArgumentListNode* function_arguments,
|
| InvocationMirror::Call im_call,
|
| InvocationMirror::Type im_type,
|
| - const Function* func) {
|
| + const Function* func,
|
| + const LibraryPrefix* prefix) {
|
| ArgumentListNode* arguments = new(Z) ArgumentListNode(call_pos);
|
| +
|
| + String& method_name = String::Handle(Z);
|
| + if (prefix == NULL) {
|
| + method_name = Library::PrivateCoreLibName(Symbols::ThrowNew()).raw();
|
| + } else {
|
| + arguments->Add(new(Z) LiteralNode(call_pos, *prefix));
|
| + method_name = Library::PrivateCoreLibName(
|
| + Symbols::ThrowNewIfNotLoaded()).raw();
|
| + }
|
| // Object receiver.
|
| // If the function is external and dynamic, pass the actual receiver,
|
| // otherwise, pass a class literal of the unresolved method's owner.
|
| @@ -10140,9 +10165,7 @@ AstNode* Parser::ThrowNoSuchMethodError(intptr_t call_pos,
|
| }
|
| arguments->Add(new(Z) LiteralNode(call_pos, array));
|
|
|
| - return MakeStaticCall(Symbols::NoSuchMethodError(),
|
| - Library::PrivateCoreLibName(Symbols::ThrowNew()),
|
| - arguments);
|
| + return MakeStaticCall(Symbols::NoSuchMethodError(), method_name, arguments);
|
| }
|
|
|
|
|
| @@ -11816,7 +11839,7 @@ AstNode* Parser::ResolveIdentInPrefixScope(intptr_t ident_pos,
|
| return NULL;
|
| }
|
| Object& obj = Object::Handle(Z);
|
| - if (prefix.is_loaded()) {
|
| + if (prefix.is_loaded() || FLAG_load_deferred_eagerly) {
|
| obj = prefix.LookupObject(ident);
|
| } else {
|
| // Remember that this function depends on an import prefix of an
|
| @@ -11952,16 +11975,25 @@ AstNode* Parser::ResolveIdent(intptr_t ident_pos,
|
| }
|
|
|
|
|
| -// Parses type = [ident "."] ident ["<" type { "," type } ">"], then resolve and
|
| -// finalize it according to the given type finalization mode.
|
| RawAbstractType* Parser::ParseType(
|
| ClassFinalizer::FinalizationKind finalization,
|
| bool allow_deferred_type,
|
| bool consume_unresolved_prefix) {
|
| + LibraryPrefix& prefix = LibraryPrefix::Handle(Z);
|
| + return ParseType(finalization, allow_deferred_type,
|
| + consume_unresolved_prefix, &prefix);
|
| +}
|
| +
|
| +// Parses type = [ident "."] ident ["<" type { "," type } ">"], then resolve and
|
| +// finalize it according to the given type finalization mode. Returns prefix.
|
| +RawAbstractType* Parser::ParseType(
|
| + ClassFinalizer::FinalizationKind finalization,
|
| + bool allow_deferred_type,
|
| + bool consume_unresolved_prefix,
|
| + LibraryPrefix* prefix) {
|
| TRACE_PARSER("ParseType");
|
| CheckToken(Token::kIDENT, "type name expected");
|
| intptr_t ident_pos = TokenPos();
|
| - LibraryPrefix& prefix = LibraryPrefix::Handle(Z);
|
| String& type_name = String::Handle(Z);
|
|
|
| if (finalization == ClassFinalizer::kIgnore) {
|
| @@ -11972,7 +12004,7 @@ RawAbstractType* Parser::ParseType(
|
| }
|
| SkipQualIdent();
|
| } else {
|
| - prefix = ParsePrefix();
|
| + *prefix = ParsePrefix();
|
| type_name = CurrentLiteral()->raw();
|
| ConsumeToken();
|
|
|
| @@ -11982,7 +12014,7 @@ RawAbstractType* Parser::ParseType(
|
| // a period and another identifier, consume the qualified identifier
|
| // and create a malformed type.
|
| if (consume_unresolved_prefix &&
|
| - prefix.IsNull() &&
|
| + prefix->IsNull() &&
|
| (CurrentToken() == Token::kPERIOD) &&
|
| (Token::IsIdentifier(LookaheadToken(1)))) {
|
| if (!is_top_level_ && (current_block_ != NULL)) {
|
| @@ -12009,7 +12041,7 @@ RawAbstractType* Parser::ParseType(
|
| // If parsing inside a local scope, check whether the type name
|
| // is shadowed by a local declaration.
|
| if (!is_top_level_ &&
|
| - (prefix.IsNull()) &&
|
| + (prefix->IsNull()) &&
|
| ResolveIdentInLocalScope(ident_pos, type_name, NULL)) {
|
| // The type is malformed. Skip over its type arguments.
|
| ParseTypeArguments(ClassFinalizer::kIgnore);
|
| @@ -12020,29 +12052,30 @@ RawAbstractType* Parser::ParseType(
|
| "using '%s' in this context is invalid",
|
| type_name.ToCString());
|
| }
|
| - if (!prefix.IsNull() && prefix.is_deferred_load()) {
|
| + if (!FLAG_load_deferred_eagerly &&
|
| + !prefix->IsNull() && prefix->is_deferred_load()) {
|
| // If deferred prefixes are allowed but it is not yet loaded,
|
| // remember that this function depends on the prefix.
|
| - if (allow_deferred_type && !prefix.is_loaded()) {
|
| + if (allow_deferred_type && !prefix->is_loaded()) {
|
| if (parsed_function() != NULL) {
|
| - parsed_function()->AddDeferredPrefix(prefix);
|
| + parsed_function()->AddDeferredPrefix(*prefix);
|
| }
|
| }
|
| // If the deferred prefixes are not allowed, or if the prefix is not yet
|
| // loaded when finalization is requested, return a malformed type.
|
| // Otherwise, handle resolution below, as needed.
|
| if (!allow_deferred_type ||
|
| - (!prefix.is_loaded()
|
| + (!prefix->is_loaded()
|
| && (finalization > ClassFinalizer::kResolveTypeParameters))) {
|
| ParseTypeArguments(ClassFinalizer::kIgnore);
|
| return ClassFinalizer::NewFinalizedMalformedType(
|
| Error::Handle(Z), // No previous error.
|
| script_,
|
| ident_pos,
|
| - !prefix.is_loaded()
|
| + !prefix->is_loaded()
|
| ? "deferred type '%s.%s' is not yet loaded"
|
| : "using deferred type '%s.%s' is invalid",
|
| - String::Handle(Z, prefix.name()).ToCString(),
|
| + String::Handle(Z, prefix->name()).ToCString(),
|
| type_name.ToCString());
|
| }
|
| }
|
| @@ -12050,7 +12083,7 @@ RawAbstractType* Parser::ParseType(
|
| Object& type_class = Object::Handle(Z);
|
| // Leave type_class as null if type finalization mode is kIgnore.
|
| if (finalization != ClassFinalizer::kIgnore) {
|
| - type_class = UnresolvedClass::New(prefix, type_name, ident_pos);
|
| + type_class = UnresolvedClass::New(*prefix, type_name, ident_pos);
|
| }
|
| TypeArguments& type_arguments = TypeArguments::Handle(
|
| Z, ParseTypeArguments(finalization));
|
| @@ -12599,10 +12632,28 @@ AstNode* Parser::ParseNewOperator(Token::Kind op_kind) {
|
| const bool allow_deferred_type = !is_const;
|
| const bool consume_unresolved_prefix = (LookaheadToken(3) == Token::kLT) ||
|
| (LookaheadToken(3) == Token::kPERIOD);
|
| + LibraryPrefix& prefix = LibraryPrefix::ZoneHandle(Z);
|
| AbstractType& type = AbstractType::Handle(Z,
|
| ParseType(ClassFinalizer::kCanonicalizeWellFormed,
|
| allow_deferred_type,
|
| - consume_unresolved_prefix));
|
| + consume_unresolved_prefix,
|
| + &prefix));
|
| + if (FLAG_load_deferred_eagerly &&
|
| + !prefix.IsNull() && prefix.is_deferred_load() && !prefix.is_loaded()) {
|
| + // Add runtime check.
|
| + Type& malformed_type = Type::Handle(Z);
|
| + malformed_type = ClassFinalizer::NewFinalizedMalformedType(
|
| + Error::Handle(Z), // No previous error.
|
| + script_,
|
| + type_pos,
|
| + "deferred type '%s.%s' is not yet loaded",
|
| + String::Handle(Z, prefix.name()).ToCString(),
|
| + String::Handle(type.Name()).ToCString());
|
| + // Note: Adding a statement to current block is a hack, parsing an
|
| + // expression should have no side-effect.
|
| + current_block_->statements->Add(
|
| + ThrowTypeError(type_pos, malformed_type, &prefix));
|
| + }
|
| // In case the type is malformed, throw a dynamic type error after finishing
|
| // parsing the instance creation expression.
|
| if (!type.IsMalformed() && (type.IsTypeParameter() || type.IsDynamicType())) {
|
| @@ -13083,6 +13134,26 @@ AstNode* Parser::ParsePrimary() {
|
| call_type,
|
| NULL); // No existing function.
|
| }
|
| + } else if (FLAG_load_deferred_eagerly && prefix.is_deferred_load()) {
|
| + // primary != NULL.
|
| + String& qualified_name = String::ZoneHandle(Z, prefix.name());
|
| + qualified_name = String::Concat(qualified_name, Symbols::Dot());
|
| + qualified_name = String::Concat(qualified_name, ident);
|
| + qualified_name = Symbols::New(qualified_name);
|
| + InvocationMirror::Type call_type =
|
| + CurrentToken() == Token::kLPAREN ?
|
| + InvocationMirror::kMethod : InvocationMirror::kGetter;
|
| + // Note: Adding a statement to current block is a hack, parsing an
|
| + // espression should have no side-effect.
|
| + current_block_->statements->Add(ThrowNoSuchMethodError(
|
| + qual_ident_pos,
|
| + current_class(),
|
| + qualified_name,
|
| + NULL, // No arguments.
|
| + InvocationMirror::kTopLevel,
|
| + call_type,
|
| + NULL, // No existing function.
|
| + &prefix));
|
| }
|
| }
|
| ASSERT(primary != NULL);
|
|
|