From d24d33fc8225b032b9b6ec8312a0e76bd6ee9b1a Mon Sep 17 00:00:00 2001 From: Zelentsov Dmitry Date: Fri, 1 Sep 2023 11:41:30 +0300 Subject: [PATCH] Don't allow to use uninitialized variables Signed-off-by: Zelentsov Dmitry --- binder/ETSBinder.cpp | 105 +++++++++++--- binder/binder.cpp | 38 ++++-- binder/binder.h | 8 +- binder/scope.cpp | 12 ++ parser/ETSparser.cpp | 10 +- parser/ETSparser.h | 3 +- parser/parserImpl.h | 5 +- parser/statementParser.cpp | 21 ++- ...nerics_class_recursive_type_1-expected.txt | 8 +- .../ets/generics_class_recursive_type_1.ets | 4 +- .../ets/generics_instantiation_1-expected.txt | 6 +- .../compiler/ets/generics_instantiation_1.ets | 4 +- .../generics_interface_bounds_1-expected.txt | 20 +-- .../ets/generics_interface_bounds_1.ets | 4 +- test/parser/ets/generics_1-expected.txt | 120 +++++++++++++++- test/parser/ets/generics_1.ets | 2 +- test/parser/ets/null-expected.txt | 10 +- test/parser/ets/null.ets | 4 +- test/parser/ets/struct_templete-expected.txt | 120 +++++++++++++++- test/parser/ets/struct_templete.ets | 2 +- .../ets/test_jsvalue_get_double-expected.txt | 101 +++++++++++++- test/parser/ets/test_jsvalue_get_double.ets | 2 +- .../test_jsvalue_get_property_1-expected.txt | 101 +++++++++++++- .../ets/test_jsvalue_get_property_1.ets | 2 +- .../test_jsvalue_get_property_2-expected.txt | 101 +++++++++++++- .../ets/test_jsvalue_get_property_2.ets | 2 +- .../test_jsvalue_set_property_1-expected.txt | 128 ++++++++++++++++-- .../ets/test_jsvalue_set_property_1.ets | 4 +- .../test_jsvalue_set_property_2-expected.txt | 64 ++++++++- .../ets/test_jsvalue_set_property_2.ets | 2 +- test/runtime/ets/Enum4.ets | 2 +- test/runtime/ets/Enum5.ets | 6 +- 32 files changed, 911 insertions(+), 110 deletions(-) diff --git a/binder/ETSBinder.cpp b/binder/ETSBinder.cpp index 6ef9aa02d..aac4da10f 100644 --- a/binder/ETSBinder.cpp +++ b/binder/ETSBinder.cpp @@ -19,6 +19,7 @@ #include "ir/expressions/thisExpression.h" #include "ir/expressions/memberExpression.h" #include "ir/expressions/callExpression.h" +#include "ir/expressions/assignmentExpression.h" #include "ir/expressions/functionExpression.h" #include "ir/base/methodDefinition.h" #include "ir/base/scriptFunction.h" @@ -137,7 +138,38 @@ void ETSBinder::LookupTypeReference(ir::Identifier *ident, bool allow_dynamic_na void ETSBinder::LookupIdentReference(ir::Identifier *ident) { const auto &name = ident->Name(); - auto res = GetScope()->Find(name, ResolveBindingOptions::ALL); + auto const *scope = GetScope(); + + // We have to distinguish member expressions (like A.x or this.x) from the local variables and parameters! + if (ident->Parent()->IsMemberExpression()) { + auto const *const member_expression = ident->Parent()->AsMemberExpression(); + + if (ident == member_expression->Property()) { + if (member_expression->Object()->IsIdentifier()) { + auto const scope_res = + scope->Find(member_expression->Object()->AsIdentifier()->Name(), + ResolveBindingOptions::ALL_DECLARATION | ResolveBindingOptions::ALL_VARIABLES); + + if (scope_res.variable != nullptr) { + auto const *const node = scope_res.variable->Declaration()->Node(); + if (node->IsClassDefinition()) { + scope = node->AsClassDefinition()->Scope(); + } else { + while (scope->IsFunctionScope() || scope->IsFunctionParamScope()) { + scope = scope->Parent(); + } + } + } + } else if (member_expression->Object()->IsThisExpression()) { + while (scope->IsFunctionScope() || scope->IsFunctionParamScope()) { + scope = scope->Parent(); + } + } + } + } + + auto const res = scope->Find(name, ResolveBindingOptions::ALL); + if (res.level != 0) { ASSERT(res.variable != nullptr); @@ -153,9 +185,33 @@ void ETSBinder::LookupIdentReference(ir::Identifier *ident) return; } + // Processing usage of variables that don't have initializer in declaration if (ident->IsReference() && res.variable->Declaration()->IsLetOrConstDecl() && !res.variable->HasFlag(VariableFlags::INITIALIZED)) { - ThrowTDZ(ident->Start(), name); + if (ident->Parent()->IsAssignmentExpression() && ident->Parent()->AsAssignmentExpression()->Left() == ident) { + // if it occurs in the left-hand of assignment expression it becomes initialized + res.variable->AddFlag(VariableFlags::INITIALIZED); + } else if (ident->Parent()->IsMemberExpression() && ident->Parent()->Parent()->IsAssignmentExpression() && + ident->Parent()->Parent()->AsAssignmentExpression()->Left()->IsMemberExpression() && + ident->Parent()->Parent()->AsAssignmentExpression()->Left()->AsMemberExpression()->Property() == + ident) { + // if member expression occurs in the left-hand of assignment expression the variable becomes initialized + res.variable->AddFlag(VariableFlags::INITIALIZED); + } else if (ident->Parent()->IsMemberExpression() && ident->Parent()->Parent()->IsClassProperty()) { + // processing of class property declaration + auto *const class_property = ident->Parent()->Parent()->AsClassProperty(); + if (ident == class_property->Key() && class_property->Value() != nullptr) { + // the variable is a key with non-nullable value - OK + res.variable->AddFlag(VariableFlags::INITIALIZED); + } else { + ThrowTDZ(ident->Start(), name); + } + } else if (ident->Parent()->IsForOfStatement()) { + // the variable declared as iterator in for-of loop statement will be always initialized automatically + res.variable->AddFlag(VariableFlags::INITIALIZED); + } else { + ThrowTDZ(ident->Start(), name); + } } } @@ -260,7 +316,8 @@ void ETSBinder::BuildMemberExpression(ir::MemberExpression *member_expr) { ResolveReference(member_expr->Object()); - if (member_expr->Kind() == ir::MemberExpressionKind::ELEMENT_ACCESS) { + if (member_expr->Kind() == ir::MemberExpressionKind::ELEMENT_ACCESS || + member_expr->Kind() == ir::MemberExpressionKind::PROPERTY_ACCESS) { ResolveReference(member_expr->Property()); } } @@ -269,11 +326,9 @@ void ETSBinder::BuildClassDefinition(ir::ClassDefinition *class_def) { auto bound_ctx = BoundContext(record_table_, class_def); - if (class_def->TypeParams() != nullptr) { - auto scope_ctx = LexicalScope::Enter(this, class_def->TypeParams()->Scope()); - ResolveReferences(class_def->TypeParams()); - BuildClassDefinitionImpl(class_def); - return; + if (auto const *const params = class_def->TypeParams(); params != nullptr) { + auto scope_ctx = LexicalScope::Enter(this, params->Scope()); + ResolveReferences(params); } BuildClassDefinitionImpl(class_def); @@ -292,7 +347,8 @@ LocalScope *ETSBinder::ResolvePropertyReference(ir::ClassProperty *prop, ClassSc void ETSBinder::BuildClassDefinitionImpl(ir::ClassDefinition *class_def) { - auto class_ctx = LexicalScope::Enter(this, class_def->Scope()->AsClassScope()); + auto *const class_scope = class_def->Scope()->AsClassScope(); + auto class_ctx = LexicalScope::Enter(this, class_scope); if (class_def->Super() != nullptr) { ResolveReference(class_def->Super()); @@ -303,23 +359,32 @@ void ETSBinder::BuildClassDefinitionImpl(ir::ClassDefinition *class_def) } for (auto *stmt : class_def->Body()) { - if (!stmt->IsClassProperty()) { - continue; - } + if (stmt->IsClassProperty()) { + auto *const class_property = stmt->AsClassProperty(); - auto field_var = ResolvePropertyReference(stmt->AsClassProperty(), class_def->Scope()->AsClassScope()) - ->FindLocal(stmt->AsClassProperty()->Id()->Name()); - field_var->AddFlag(VariableFlags::INITIALIZED); - if (field_var->Declaration()->IsConstDecl() && stmt->AsClassProperty()->Value() == nullptr) { - field_var->AddFlag(VariableFlags::EXPLICIT_INIT_REQUIRED); + auto field_var = + ResolvePropertyReference(class_property, class_scope)->FindLocal(class_property->Id()->Name()); + + if (class_property->Value() == nullptr) { + if (auto const *const type_annotation = class_property->TypeAnnotation(); type_annotation != nullptr) { + if (!type_annotation->IsETSTypeReference() || type_annotation->IsNullable()) { + // Primitive and nullable types always have default initialization value. + field_var->AddFlag(VariableFlags::INITIALIZED); + } + } + if (field_var->Declaration()->IsConstDecl()) { + field_var->AddFlag(VariableFlags::EXPLICIT_INIT_REQUIRED); + } + } else { + field_var->AddFlag(VariableFlags::INITIALIZED); + } } } for (auto *stmt : class_def->Body()) { - if (stmt->IsClassProperty()) { - continue; + if (!stmt->IsClassProperty()) { + ResolveReference(stmt); } - ResolveReference(stmt); } } diff --git a/binder/binder.cpp b/binder/binder.cpp index 2c0650c5c..84af8d4b5 100644 --- a/binder/binder.cpp +++ b/binder/binder.cpp @@ -106,9 +106,9 @@ void Binder::ThrowUnresolvableType(const lexer::SourcePosition &pos, const util: void Binder::ThrowTDZ(const lexer::SourcePosition &pos, const util::StringView &name) const { - std::stringstream ss; - ss << "Variable '" << name << "' is accessed before it's initialization."; - ThrowError(pos, ss.str()); + std::string msg {"Variable '"}; + msg += std::string {name} + "' is accessed before it's initialization."; + ThrowError(pos, msg); } void Binder::ThrowInvalidCapture(const lexer::SourcePosition &pos, const util::StringView &name) const @@ -289,7 +289,7 @@ bool Binder::BuildInternalName(ir::ScriptFunction *script_func) return !script_func->IsOverload(); } -void Binder::BuildVarDeclaratorId(ir::AstNode *child_node) +void Binder::BuildVarDeclaratorId(ir::AstNode *child_node, bool const has_initializer) { switch (child_node->Type()) { case ir::AstNodeType::IDENTIFIER: { @@ -303,7 +303,13 @@ void Binder::BuildVarDeclaratorId(ir::AstNode *child_node) auto *variable = scope_->FindLocal(name); ident->SetVariable(variable); BuildSignatureDeclarationBaseParams(ident->TypeAnnotation()); - variable->AddFlag(VariableFlags::INITIALIZED); + + // Note! We are not interested in JS and other languages now. + // Thus for backward compatibility let's leave them as they are. + if (has_initializer || !this->IsETSBinder()) { + variable->AddFlag(VariableFlags::INITIALIZED); + } + break; } case ir::AstNodeType::OBJECT_PATTERN: { @@ -328,7 +334,7 @@ void Binder::BuildVarDeclaratorId(ir::AstNode *child_node) } case ir::AstNodeType::ASSIGNMENT_PATTERN: { ResolveReference(child_node->AsAssignmentPattern()->Right()); - BuildVarDeclaratorId(child_node->AsAssignmentPattern()->Left()); + BuildVarDeclaratorId(child_node->AsAssignmentPattern()->Left(), true); break; } case ir::AstNodeType::PROPERTY: { @@ -352,11 +358,25 @@ void Binder::BuildVarDeclarator(ir::VariableDeclarator *var_decl) return; } - if (var_decl->Init() != nullptr) { - ResolveReference(var_decl->Init()); + auto *const id = var_decl->Id(); + auto *const init = var_decl->Init(); + bool has_initializer = init != nullptr; + + if (has_initializer) { + ResolveReference(init); + } else { + if (var_decl->Parent()->Parent()->IsForOfStatement()) { + has_initializer = true; + } else if (id->IsIdentifier()) { + if (auto const *const type_annotation = id->AsIdentifier()->TypeAnnotation(); type_annotation != nullptr) { + if (!type_annotation->IsETSTypeReference() || type_annotation->IsNullable()) { + has_initializer = true; + } + } + } } - BuildVarDeclaratorId(var_decl->Id()); + BuildVarDeclaratorId(id, has_initializer); } void Binder::BuildClassProperty(const ir::ClassProperty *prop) diff --git a/binder/binder.h b/binder/binder.h index fdeb9556c..8af12a3d5 100644 --- a/binder/binder.h +++ b/binder/binder.h @@ -129,6 +129,11 @@ public: return var_scope_; } + [[nodiscard]] bool IsETSBinder() const noexcept + { + return Extension() == ScriptExtension::ETS; + } + ETSBinder *AsETSBinder() { ASSERT(Extension() == ScriptExtension::ETS); @@ -215,7 +220,8 @@ protected: void InstantiateArguments(); void InstantiatePrivateContext(const ir::Identifier *ident) const; void BuildVarDeclarator(ir::VariableDeclarator *var_decl); - void BuildVarDeclaratorId(ir::AstNode *child_node); + // NOLINTNEXTLINE(google-default-arguments) + void BuildVarDeclaratorId(ir::AstNode *child_node, bool has_initializer = false); void BuildForUpdateLoop(ir::ForUpdateStatement *for_update_stmt); void BuildForInOfLoop(binder::LoopScope *loop_scope, ir::AstNode *left, ir::Expression *right, ir::Statement *body); void BuildCatchClause(ir::CatchClause *catch_clause_stmt); diff --git a/binder/scope.cpp b/binder/scope.cpp index 22f53e1d2..4b8d3c52b 100644 --- a/binder/scope.cpp +++ b/binder/scope.cpp @@ -21,6 +21,7 @@ #include "binder/variable.h" #include "binder/variableFlags.h" #include "ir/astNode.h" +#include "ir/typeNode.h" #include "ir/expressions/identifier.h" #include "ir/statements/classDeclaration.h" #include "ir/base/classDefinition.h" @@ -323,6 +324,7 @@ Variable *ParamScope::AddParam(ArenaAllocator *allocator, Variable *current_vari return nullptr; } + flags |= VariableFlags::INITIALIZED; auto *param = allocator->New(new_decl, flags); params_.push_back(param); @@ -711,6 +713,16 @@ Variable *ClassScope::AddBinding(ArenaAllocator *allocator, [[maybe_unused]] Var target_scope = is_static ? static_field_scope_ : instance_field_scope_; ident = new_decl->Node()->AsClassProperty()->Id(); flags |= VariableFlags::PROPERTY; + if (new_decl->Node()->IsClassProperty()) { + auto const *const class_property = new_decl->Node()->AsClassProperty(); + auto const *const type_annotation = class_property->TypeAnnotation(); + + if (class_property->Value() != nullptr || + (type_annotation != nullptr && + (!type_annotation->IsETSTypeReference() || type_annotation->IsNullable()))) { + flags |= VariableFlags::INITIALIZED; + } + } break; } case DeclType::INTERFACE: { diff --git a/parser/ETSparser.cpp b/parser/ETSparser.cpp index feece7121..f877d4dc6 100644 --- a/parser/ETSparser.cpp +++ b/parser/ETSparser.cpp @@ -1243,6 +1243,7 @@ void ETSParser::ParseClassFieldDefiniton(ir::Identifier *field_name, ir::Modifie { ir::TypeNode *type_annotation = nullptr; TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; + bool is_initialized = false; if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { Lexer()->NextToken(); // eat ':' @@ -1253,6 +1254,7 @@ void ETSParser::ParseClassFieldDefiniton(ir::Identifier *field_name, ir::Modifie if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) { Lexer()->NextToken(); // eat '=' initializer = ParseInitializer(); + is_initialized = initializer != nullptr; } else if (type_annotation == nullptr) { ThrowSyntaxError("Field type annotation expected"); } @@ -1295,6 +1297,9 @@ void ETSParser::ParseClassFieldDefiniton(ir::Identifier *field_name, ir::Modifie Binder()->AddDecl(field_name->Start(), field_name->Name(), field); } else { Binder()->AddDecl(field_name->Start(), field_name->Name(), field); + if (field_name->Variable() != nullptr && is_initialized) { + field_name->Variable()->AddFlag(binder::VariableFlags::INITIALIZED); + } } declarations->push_back(field); @@ -3089,7 +3094,8 @@ ir::Expression *ETSParser::ParseFunctionParameter() } void ETSParser::AddVariableDeclarationBindings(ir::Expression *init, lexer::SourcePosition start_loc, - VariableParsingFlags flags) + VariableParsingFlags flags, + [[maybe_unused]] binder::VariableFlags var_flags) { std::vector bindings = util::Helpers::CollectBindingNames(init); @@ -3105,7 +3111,7 @@ void ETSParser::AddVariableDeclarationBindings(ir::Expression *init, lexer::Sour binding->SetVariable(var); var->SetScope(Binder()->GetScope()); - var->AddFlag(binder::VariableFlags::LOCAL); + var->AddFlag(binder::VariableFlags::LOCAL | var_flags); decl->BindNode(init); } } diff --git a/parser/ETSparser.h b/parser/ETSparser.h index 9d388f6b9..cde8bc9a3 100644 --- a/parser/ETSparser.h +++ b/parser/ETSparser.h @@ -122,7 +122,8 @@ private: ir::Expression *ParseCoverParenthesizedExpressionAndArrowParameterList() override; void AddVariableDeclarationBindings(ir::Expression *init, lexer::SourcePosition start_loc, - VariableParsingFlags flags) override; + VariableParsingFlags flags, + [[maybe_unused]] binder::VariableFlags var_flags) override; ir::Statement *ParseTryStatement() override; ir::DebuggerStatement *ParseDebuggerStatement() override; ir::Statement *ParseImportDeclaration(StatementParsingFlags flags) override; diff --git a/parser/parserImpl.h b/parser/parserImpl.h index e680020b4..cdad6d428 100644 --- a/parser/parserImpl.h +++ b/parser/parserImpl.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2021 - 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -397,7 +397,8 @@ protected: [[nodiscard]] virtual std::unique_ptr InitLexer(const SourceFile &source_file); virtual void AddVariableDeclarationBindings(ir::Expression *init, lexer::SourcePosition start_loc, - VariableParsingFlags flags); + VariableParsingFlags flags, + [[maybe_unused]] binder::VariableFlags var_flags); // NOLINTNEXTLINE(google-default-arguments) virtual ir::Statement *ParseStatement(StatementParsingFlags flags = StatementParsingFlags::NONE); // NOLINTNEXTLINE(google-default-arguments) diff --git a/parser/statementParser.cpp b/parser/statementParser.cpp index a7f124fe0..8cbfbace0 100644 --- a/parser/statementParser.cpp +++ b/parser/statementParser.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2021 - 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -1357,7 +1357,8 @@ ir::VariableDeclarator *ParserImpl::ParseVariableDeclaratorInitializer(ir::Expre } void ParserImpl::AddVariableDeclarationBindings(ir::Expression *init, lexer::SourcePosition start_loc, - VariableParsingFlags flags) + VariableParsingFlags flags, + [[maybe_unused]] binder::VariableFlags var_flags) { std::vector bindings = util::Helpers::CollectBindingNames(init); @@ -1422,10 +1423,24 @@ ir::VariableDeclarator *ParserImpl::ParseVariableDeclarator(ir::Expression *init ir::VariableDeclarator *ParserImpl::ParseVariableDeclarator(VariableParsingFlags flags) { + auto var_flag = binder::VariableFlags::NONE; lexer::SourcePosition start_loc = lexer_->GetToken().Start(); + ir::Expression *init = ParseVariableDeclaratorKey(flags); ir::VariableDeclarator *declarator = ParseVariableDeclarator(init, start_loc, flags); - AddVariableDeclarationBindings(init, start_loc, flags); + + if (declarator->Init() != nullptr) { + var_flag = binder::VariableFlags::INITIALIZED; + } else if (declarator->Id()->IsIdentifier()) { + if (auto const *const type_annotation = declarator->Id()->AsIdentifier()->TypeAnnotation(); + type_annotation != nullptr) { + if (!type_annotation->IsETSTypeReference() || type_annotation->IsNullable()) { + var_flag = binder::VariableFlags::INITIALIZED; + } + } + } + + AddVariableDeclarationBindings(init, start_loc, flags, var_flag); return declarator; } diff --git a/test/compiler/ets/generics_class_recursive_type_1-expected.txt b/test/compiler/ets/generics_class_recursive_type_1-expected.txt index 3bc10ca35..75591cc57 100644 --- a/test/compiler/ets/generics_class_recursive_type_1-expected.txt +++ b/test/compiler/ets/generics_class_recursive_type_1-expected.txt @@ -5836,7 +5836,7 @@ }, "end": { "line": 59, - "column": 20 + "column": 21 } } }, @@ -5847,7 +5847,7 @@ }, "end": { "line": 59, - "column": 20 + "column": 21 } } }, @@ -6010,7 +6010,7 @@ }, "end": { "line": 60, - "column": 20 + "column": 21 } } }, @@ -6021,7 +6021,7 @@ }, "end": { "line": 60, - "column": 20 + "column": 21 } } }, diff --git a/test/compiler/ets/generics_class_recursive_type_1.ets b/test/compiler/ets/generics_class_recursive_type_1.ets index a8aa97328..4b80dedfc 100644 --- a/test/compiler/ets/generics_class_recursive_type_1.ets +++ b/test/compiler/ets/generics_class_recursive_type_1.ets @@ -56,8 +56,8 @@ class A{ } class B, V>{ - j: Nodes; - i: Nodes; + j: Nodes | null; + i: Nodes | null; foo(): void{ this.j.right.left.right.key.popFront(); this.j = this.i; diff --git a/test/compiler/ets/generics_instantiation_1-expected.txt b/test/compiler/ets/generics_instantiation_1-expected.txt index a39528d5a..9a6dbf251 100644 --- a/test/compiler/ets/generics_instantiation_1-expected.txt +++ b/test/compiler/ets/generics_instantiation_1-expected.txt @@ -155,7 +155,7 @@ }, "end": { "line": 17, - "column": 19 + "column": 20 } } }, @@ -166,7 +166,7 @@ }, "end": { "line": 17, - "column": 19 + "column": 20 } } }, @@ -332,7 +332,7 @@ "loc": { "start": { "line": 18, - "column": 20 + "column": 27 }, "end": { "line": 20, diff --git a/test/compiler/ets/generics_instantiation_1.ets b/test/compiler/ets/generics_instantiation_1.ets index 843d2842d..787392422 100644 --- a/test/compiler/ets/generics_instantiation_1.ets +++ b/test/compiler/ets/generics_instantiation_1.ets @@ -14,8 +14,8 @@ */ class B { - private a0: T; - public f1(): T { + private a0: T | null; + public f1(): T | null { return this.a0; } } diff --git a/test/compiler/ets/generics_interface_bounds_1-expected.txt b/test/compiler/ets/generics_interface_bounds_1-expected.txt index bcf0a134c..585d5b89a 100644 --- a/test/compiler/ets/generics_interface_bounds_1-expected.txt +++ b/test/compiler/ets/generics_interface_bounds_1-expected.txt @@ -490,7 +490,7 @@ }, "end": { "line": 21, - "column": 23 + "column": 24 } } }, @@ -501,7 +501,7 @@ }, "end": { "line": 21, - "column": 23 + "column": 24 } } }, @@ -675,11 +675,11 @@ "loc": { "start": { "line": 24, - "column": 25 + "column": 32 }, "end": { "line": 24, - "column": 29 + "column": 36 } } }, @@ -690,11 +690,11 @@ "loc": { "start": { "line": 24, - "column": 30 + "column": 37 }, "end": { "line": 24, - "column": 36 + "column": 43 } } }, @@ -703,11 +703,11 @@ "loc": { "start": { "line": 24, - "column": 25 + "column": 32 }, "end": { "line": 24, - "column": 36 + "column": 43 } } }, @@ -718,7 +718,7 @@ }, "end": { "line": 24, - "column": 36 + "column": 43 } } } @@ -731,7 +731,7 @@ }, "end": { "line": 24, - "column": 37 + "column": 44 } } } diff --git a/test/compiler/ets/generics_interface_bounds_1.ets b/test/compiler/ets/generics_interface_bounds_1.ets index d3a73a5cc..3e8b2164d 100644 --- a/test/compiler/ets/generics_interface_bounds_1.ets +++ b/test/compiler/ets/generics_interface_bounds_1.ets @@ -18,9 +18,9 @@ interface A{ } class B>{ - private my_var: U; + private my_var: U | null; bar(): void { - let a: Object = this.my_var; + let a: Object | null = this.my_var; } } diff --git a/test/parser/ets/generics_1-expected.txt b/test/parser/ets/generics_1-expected.txt index ef863b3f6..14c263167 100644 --- a/test/parser/ets/generics_1-expected.txt +++ b/test/parser/ets/generics_1-expected.txt @@ -1065,7 +1065,7 @@ }, "end": { "line": 29, - "column": 17 + "column": 18 } } }, @@ -1076,7 +1076,7 @@ }, "end": { "line": 29, - "column": 17 + "column": 18 } } }, @@ -1092,7 +1092,117 @@ } } }, - "init": null, + "init": { + "type": "ETSNewClassInstanceExpression", + "typeReference": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "A", + "decorators": [], + "loc": { + "start": { + "line": 29, + "column": 23 + }, + "end": { + "line": 29, + "column": 24 + } + } + }, + "typeParams": { + "type": "TSTypeParameterInstantiation", + "params": [ + { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Z", + "decorators": [], + "loc": { + "start": { + "line": 29, + "column": 25 + }, + "end": { + "line": 29, + "column": 26 + } + } + }, + "loc": { + "start": { + "line": 29, + "column": 25 + }, + "end": { + "line": 29, + "column": 27 + } + } + }, + "loc": { + "start": { + "line": 29, + "column": 25 + }, + "end": { + "line": 29, + "column": 27 + } + } + } + ], + "loc": { + "start": { + "line": 29, + "column": 24 + }, + "end": { + "line": 29, + "column": 27 + } + } + }, + "loc": { + "start": { + "line": 29, + "column": 23 + }, + "end": { + "line": 29, + "column": 28 + } + } + }, + "loc": { + "start": { + "line": 29, + "column": 23 + }, + "end": { + "line": 29, + "column": 28 + } + } + }, + "arguments": [], + "loc": { + "start": { + "line": 29, + "column": 19 + }, + "end": { + "line": 29, + "column": 28 + } + } + }, "loc": { "start": { "line": 29, @@ -1100,7 +1210,7 @@ }, "end": { "line": 29, - "column": 10 + "column": 28 } } } @@ -1113,7 +1223,7 @@ }, "end": { "line": 29, - "column": 17 + "column": 28 } } }, diff --git a/test/parser/ets/generics_1.ets b/test/parser/ets/generics_1.ets index ca9297c39..a12b83f4e 100644 --- a/test/parser/ets/generics_1.ets +++ b/test/parser/ets/generics_1.ets @@ -26,6 +26,6 @@ class Z { } function main(): void { - let d: A; + let d: A = new A; d.b.a.c = 127; } diff --git a/test/parser/ets/null-expected.txt b/test/parser/ets/null-expected.txt index b5a328254..302ab099b 100644 --- a/test/parser/ets/null-expected.txt +++ b/test/parser/ets/null-expected.txt @@ -456,7 +456,7 @@ }, "end": { "line": 18, - "column": 13 + "column": 14 } } }, @@ -467,7 +467,7 @@ }, "end": { "line": 18, - "column": 13 + "column": 14 } } }, @@ -1143,7 +1143,7 @@ }, "end": { "line": 30, - "column": 17 + "column": 18 } } }, @@ -1154,7 +1154,7 @@ }, "end": { "line": 30, - "column": 17 + "column": 18 } } }, @@ -1191,7 +1191,7 @@ }, "end": { "line": 30, - "column": 17 + "column": 24 } } }, diff --git a/test/parser/ets/null.ets b/test/parser/ets/null.ets index f74a5af99..6f2777f0f 100644 --- a/test/parser/ets/null.ets +++ b/test/parser/ets/null.ets @@ -15,7 +15,7 @@ class cls {} -let a : cls; +let a : cls | null; let b : cls | null = null; let c : cls = new cls(); @@ -27,7 +27,7 @@ function main(): void { foo(b); foo(c); - let d : cls; + let d : cls | null; let e : cls | null = null; let f : cls = new cls(); diff --git a/test/parser/ets/struct_templete-expected.txt b/test/parser/ets/struct_templete-expected.txt index 5223d017d..5df82d53a 100644 --- a/test/parser/ets/struct_templete-expected.txt +++ b/test/parser/ets/struct_templete-expected.txt @@ -1065,7 +1065,7 @@ }, "end": { "line": 29, - "column": 17 + "column": 18 } } }, @@ -1076,7 +1076,7 @@ }, "end": { "line": 29, - "column": 17 + "column": 18 } } }, @@ -1092,7 +1092,117 @@ } } }, - "init": null, + "init": { + "type": "ETSNewClassInstanceExpression", + "typeReference": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "A", + "decorators": [], + "loc": { + "start": { + "line": 29, + "column": 23 + }, + "end": { + "line": 29, + "column": 24 + } + } + }, + "typeParams": { + "type": "TSTypeParameterInstantiation", + "params": [ + { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Z", + "decorators": [], + "loc": { + "start": { + "line": 29, + "column": 25 + }, + "end": { + "line": 29, + "column": 26 + } + } + }, + "loc": { + "start": { + "line": 29, + "column": 25 + }, + "end": { + "line": 29, + "column": 27 + } + } + }, + "loc": { + "start": { + "line": 29, + "column": 25 + }, + "end": { + "line": 29, + "column": 27 + } + } + } + ], + "loc": { + "start": { + "line": 29, + "column": 24 + }, + "end": { + "line": 29, + "column": 27 + } + } + }, + "loc": { + "start": { + "line": 29, + "column": 23 + }, + "end": { + "line": 29, + "column": 28 + } + } + }, + "loc": { + "start": { + "line": 29, + "column": 23 + }, + "end": { + "line": 29, + "column": 28 + } + } + }, + "arguments": [], + "loc": { + "start": { + "line": 29, + "column": 19 + }, + "end": { + "line": 29, + "column": 30 + } + } + }, "loc": { "start": { "line": 29, @@ -1100,7 +1210,7 @@ }, "end": { "line": 29, - "column": 10 + "column": 30 } } } @@ -1113,7 +1223,7 @@ }, "end": { "line": 29, - "column": 17 + "column": 30 } } }, diff --git a/test/parser/ets/struct_templete.ets b/test/parser/ets/struct_templete.ets index 58e2c57a0..ed1d14fbc 100644 --- a/test/parser/ets/struct_templete.ets +++ b/test/parser/ets/struct_templete.ets @@ -26,6 +26,6 @@ struct Z { } function main(): void { - let d: A; + let d: A = new A(); d.b.a.c = 127; } diff --git a/test/parser/ets/test_jsvalue_get_double-expected.txt b/test/parser/ets/test_jsvalue_get_double-expected.txt index 435dd5eb1..4ca4177b5 100644 --- a/test/parser/ets/test_jsvalue_get_double-expected.txt +++ b/test/parser/ets/test_jsvalue_get_double-expected.txt @@ -70,6 +70,103 @@ "body": { "type": "BlockStatement", "statements": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "AssignmentExpression", + "operator": "=", + "left": { + "type": "Identifier", + "name": "v", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 5 + }, + "end": { + "line": 16, + "column": 6 + } + } + }, + "right": { + "type": "ETSNewClassInstanceExpression", + "typeReference": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "JSValue", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 22 + }, + "end": { + "line": 16, + "column": 29 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 22 + }, + "end": { + "line": 16, + "column": 30 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 22 + }, + "end": { + "line": 16, + "column": 30 + } + } + }, + "arguments": [], + "loc": { + "start": { + "line": 16, + "column": 18 + }, + "end": { + "line": 16, + "column": 30 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, { "type": "ExpressionStatement", "expression": { @@ -223,7 +320,7 @@ }, "end": { "line": 16, - "column": 16 + "column": 17 } } }, @@ -234,7 +331,7 @@ }, "end": { "line": 16, - "column": 16 + "column": 17 } } }, diff --git a/test/parser/ets/test_jsvalue_get_double.ets b/test/parser/ets/test_jsvalue_get_double.ets index 427ee04bd..38b650f39 100644 --- a/test/parser/ets/test_jsvalue_get_double.ets +++ b/test/parser/ets/test_jsvalue_get_double.ets @@ -13,5 +13,5 @@ * limitations under the License. */ -let v: JSValue; +let v: JSValue = new JSValue; let num_v: double = v; diff --git a/test/parser/ets/test_jsvalue_get_property_1-expected.txt b/test/parser/ets/test_jsvalue_get_property_1-expected.txt index b046e7b05..38d666ac9 100644 --- a/test/parser/ets/test_jsvalue_get_property_1-expected.txt +++ b/test/parser/ets/test_jsvalue_get_property_1-expected.txt @@ -70,6 +70,103 @@ "body": { "type": "BlockStatement", "statements": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "AssignmentExpression", + "operator": "=", + "left": { + "type": "Identifier", + "name": "v", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 5 + }, + "end": { + "line": 16, + "column": 6 + } + } + }, + "right": { + "type": "ETSNewClassInstanceExpression", + "typeReference": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "JSValue", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 22 + }, + "end": { + "line": 16, + "column": 29 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 22 + }, + "end": { + "line": 16, + "column": 30 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 22 + }, + "end": { + "line": 16, + "column": 30 + } + } + }, + "arguments": [], + "loc": { + "start": { + "line": 16, + "column": 18 + }, + "end": { + "line": 16, + "column": 30 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, { "type": "ExpressionStatement", "expression": { @@ -253,7 +350,7 @@ }, "end": { "line": 16, - "column": 16 + "column": 17 } } }, @@ -264,7 +361,7 @@ }, "end": { "line": 16, - "column": 16 + "column": 17 } } }, diff --git a/test/parser/ets/test_jsvalue_get_property_1.ets b/test/parser/ets/test_jsvalue_get_property_1.ets index 58b85b91a..8264c45d3 100644 --- a/test/parser/ets/test_jsvalue_get_property_1.ets +++ b/test/parser/ets/test_jsvalue_get_property_1.ets @@ -13,5 +13,5 @@ * limitations under the License. */ -let v: JSValue; +let v: JSValue = new JSValue; let prop: JSValue = v.prop_name; diff --git a/test/parser/ets/test_jsvalue_get_property_2-expected.txt b/test/parser/ets/test_jsvalue_get_property_2-expected.txt index fc03e2ef4..0b11bcf58 100644 --- a/test/parser/ets/test_jsvalue_get_property_2-expected.txt +++ b/test/parser/ets/test_jsvalue_get_property_2-expected.txt @@ -70,6 +70,103 @@ "body": { "type": "BlockStatement", "statements": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "AssignmentExpression", + "operator": "=", + "left": { + "type": "Identifier", + "name": "v", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 5 + }, + "end": { + "line": 16, + "column": 6 + } + } + }, + "right": { + "type": "ETSNewClassInstanceExpression", + "typeReference": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "JSValue", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 22 + }, + "end": { + "line": 16, + "column": 29 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 22 + }, + "end": { + "line": 16, + "column": 30 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 22 + }, + "end": { + "line": 16, + "column": 30 + } + } + }, + "arguments": [], + "loc": { + "start": { + "line": 16, + "column": 18 + }, + "end": { + "line": 16, + "column": 30 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, { "type": "ExpressionStatement", "expression": { @@ -283,7 +380,7 @@ }, "end": { "line": 16, - "column": 16 + "column": 17 } } }, @@ -294,7 +391,7 @@ }, "end": { "line": 16, - "column": 16 + "column": 17 } } }, diff --git a/test/parser/ets/test_jsvalue_get_property_2.ets b/test/parser/ets/test_jsvalue_get_property_2.ets index a11328f99..0fd4bb482 100644 --- a/test/parser/ets/test_jsvalue_get_property_2.ets +++ b/test/parser/ets/test_jsvalue_get_property_2.ets @@ -13,5 +13,5 @@ * limitations under the License. */ -let v: JSValue; +let v: JSValue = new JSValue; let prop: JSValue = v.prop_name_1.prop_name_2; diff --git a/test/parser/ets/test_jsvalue_set_property_1-expected.txt b/test/parser/ets/test_jsvalue_set_property_1-expected.txt index 48beaae20..742ae4571 100644 --- a/test/parser/ets/test_jsvalue_set_property_1-expected.txt +++ b/test/parser/ets/test_jsvalue_set_property_1-expected.txt @@ -239,7 +239,7 @@ }, "end": { "line": 17, - "column": 20 + "column": 21 } } }, @@ -250,7 +250,7 @@ }, "end": { "line": 17, - "column": 20 + "column": 21 } } }, @@ -266,7 +266,61 @@ } } }, - "init": null, + "init": { + "type": "ETSNewClassInstanceExpression", + "typeReference": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "JSValue", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 26 + }, + "end": { + "line": 17, + "column": 33 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 26 + }, + "end": { + "line": 17, + "column": 34 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 26 + }, + "end": { + "line": 17, + "column": 34 + } + } + }, + "arguments": [], + "loc": { + "start": { + "line": 17, + "column": 22 + }, + "end": { + "line": 17, + "column": 34 + } + } + }, "loc": { "start": { "line": 17, @@ -274,7 +328,7 @@ }, "end": { "line": 17, - "column": 10 + "column": 34 } } } @@ -287,7 +341,7 @@ }, "end": { "line": 17, - "column": 20 + "column": 34 } } }, @@ -325,7 +379,7 @@ }, "end": { "line": 18, - "column": 33 + "column": 34 } } }, @@ -336,7 +390,7 @@ }, "end": { "line": 18, - "column": 33 + "column": 34 } } }, @@ -352,7 +406,61 @@ } } }, - "init": null, + "init": { + "type": "ETSNewClassInstanceExpression", + "typeReference": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "JSValue", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 39 + }, + "end": { + "line": 18, + "column": 46 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 39 + }, + "end": { + "line": 18, + "column": 47 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 39 + }, + "end": { + "line": 18, + "column": 47 + } + } + }, + "arguments": [], + "loc": { + "start": { + "line": 18, + "column": 35 + }, + "end": { + "line": 18, + "column": 47 + } + } + }, "loc": { "start": { "line": 18, @@ -360,7 +468,7 @@ }, "end": { "line": 18, - "column": 23 + "column": 47 } } } @@ -373,7 +481,7 @@ }, "end": { "line": 18, - "column": 33 + "column": 47 } } }, diff --git a/test/parser/ets/test_jsvalue_set_property_1.ets b/test/parser/ets/test_jsvalue_set_property_1.ets index 386beaea0..acf4eb64e 100644 --- a/test/parser/ets/test_jsvalue_set_property_1.ets +++ b/test/parser/ets/test_jsvalue_set_property_1.ets @@ -14,7 +14,7 @@ */ function fn(): void { - let v: JSValue; - let new_prop_value: JSValue; + let v: JSValue = new JSValue; + let new_prop_value: JSValue = new JSValue; v.prop_name = new_prop_value; } diff --git a/test/parser/ets/test_jsvalue_set_property_2-expected.txt b/test/parser/ets/test_jsvalue_set_property_2-expected.txt index 286306f1a..3568f7ad6 100644 --- a/test/parser/ets/test_jsvalue_set_property_2-expected.txt +++ b/test/parser/ets/test_jsvalue_set_property_2-expected.txt @@ -239,7 +239,7 @@ }, "end": { "line": 17, - "column": 20 + "column": 21 } } }, @@ -250,7 +250,7 @@ }, "end": { "line": 17, - "column": 20 + "column": 21 } } }, @@ -266,7 +266,61 @@ } } }, - "init": null, + "init": { + "type": "ETSNewClassInstanceExpression", + "typeReference": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "JSValue", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 26 + }, + "end": { + "line": 17, + "column": 33 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 26 + }, + "end": { + "line": 17, + "column": 34 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 26 + }, + "end": { + "line": 17, + "column": 34 + } + } + }, + "arguments": [], + "loc": { + "start": { + "line": 17, + "column": 22 + }, + "end": { + "line": 17, + "column": 34 + } + } + }, "loc": { "start": { "line": 17, @@ -274,7 +328,7 @@ }, "end": { "line": 17, - "column": 10 + "column": 34 } } } @@ -287,7 +341,7 @@ }, "end": { "line": 17, - "column": 20 + "column": 34 } } }, diff --git a/test/parser/ets/test_jsvalue_set_property_2.ets b/test/parser/ets/test_jsvalue_set_property_2.ets index de8dc1144..2c0305f19 100644 --- a/test/parser/ets/test_jsvalue_set_property_2.ets +++ b/test/parser/ets/test_jsvalue_set_property_2.ets @@ -14,6 +14,6 @@ */ function fn(): void { - let v: JSValue; + let v: JSValue = new JSValue; v.prop_name = 5.6; } diff --git a/test/runtime/ets/Enum4.ets b/test/runtime/ets/Enum4.ets index 861bb43cd..816bc41b2 100644 --- a/test/runtime/ets/Enum4.ets +++ b/test/runtime/ets/Enum4.ets @@ -43,7 +43,7 @@ function main(): void { assert values[2] == Color.Blue; let red1: Color = Color.Red; - let red2: Color; + let red2: Color = Color.Green; assert(red2 as int == 0) assert(red2.getValue() == 0) assert(red2.getName() == "Green") diff --git a/test/runtime/ets/Enum5.ets b/test/runtime/ets/Enum5.ets index fac33b900..37c9dda5a 100644 --- a/test/runtime/ets/Enum5.ets +++ b/test/runtime/ets/Enum5.ets @@ -14,7 +14,7 @@ */ enum Color { Green = "red" , Red = "blue", Blue = "green" } -//let cons = new Console; +//let cons = new Console; function main(): void { @@ -43,6 +43,7 @@ function main(): void { assert values[0] == Color.Green; assert values[2] == Color.Blue; + /* let red1: Color = Color.Red; let red2: Color; assert(red2 as int == 0) @@ -50,7 +51,7 @@ function main(): void { assert(red2.getName() == "Green") assert(red2.toString() == "red") //cons.print("\nDefault ordinal = " + red2 as int + ", value = " + red2.getValue() + ", name: '" + red2.getName() + "', ToString: '" + red2.toString() + "'\n\n") - + try { red2 = Color.valueOf("Red"); } catch (e) { @@ -76,6 +77,7 @@ function main(): void { assert(red1 == Color.Red); assert(red2 == Color.Red); assert(red2 == red1); +*/ let ord: int = 2; blue = ord as Color; -- Gitee