diff --git a/binder/ETSBinder.cpp b/binder/ETSBinder.cpp index e4ba26aae5e0a344cc9455ee933457ce7b9d3674..6ef9aa02d6e5660e74076ac4fe5ce28c258ead53 100644 --- a/binder/ETSBinder.cpp +++ b/binder/ETSBinder.cpp @@ -656,12 +656,15 @@ void ETSBinder::BuildFunctionName(const ir::ScriptFunction *func) const if (func->IsStaticBlock()) { ss << compiler::Signatures::CCTOR; + } else if (func->IsConstructor()) { + ss << compiler::Signatures::CTOR; } else { - if (func->IsConstructor()) { - ss << compiler::Signatures::CTOR; - } else { - ss << util::Helpers::FunctionName(Allocator(), func); + if (func->IsGetter()) { + ss << compiler::Signatures::GETTER_BEGIN; + } else if (func->IsSetter()) { + ss << compiler::Signatures::SETTER_BEGIN; } + ss << util::Helpers::FunctionName(Allocator(), func); } signature->ToAssemblerType(GetCompilerContext(), ss); diff --git a/checker/ETSchecker.h b/checker/ETSchecker.h index 998d03fbf22c7cab30f66d23fcb68aa3d25965af..96724d34a9909ec5aa9b27aaf3041264e518ceba 100644 --- a/checker/ETSchecker.h +++ b/checker/ETSchecker.h @@ -183,7 +183,7 @@ public: binder::LocalVariable *ResolveMemberReference(const ir::MemberExpression *member_expr, const ETSObjectType *target); void CheckImplicitSuper(ETSObjectType *class_type, Signature *ctor_sig); void CheckValidInheritance(ETSObjectType *class_type, ir::ClassDefinition *class_def); - void CheckGetterSetterModifiers(const ir::ClassDefinition *class_def); + void CheckGetterSetterProperties(ETSObjectType *class_type); void AddElementsToModuleObject(ETSObjectType *module_obj, const util::StringView &str); Type *FindLeastUpperBound(Type *source, Type *target); Type *GetCommonClass(Type *source, Type *target); @@ -418,7 +418,8 @@ public: util::StringView name, const ETSObjectType *class_type); binder::Variable *FindVariableInGlobal(const ir::Identifier *identifier); void ValidateResolvedIdentifier(const ir::Identifier *ident, binder::Variable *resolved); - bool IsVariableStatic(const binder::Variable *var); + bool IsVariableStatic(const binder::Variable *var) const; + bool IsVariableGetterSetter(const binder::Variable *var) const; bool IsSameDeclarationType(binder::LocalVariable *target, binder::LocalVariable *compare); void SaveCapturedVariable(binder::Variable *var, const lexer::SourcePosition &pos); void AddBoxingFlagToPrimitiveType(TypeRelation *relation, Type *target); diff --git a/checker/ets/dynamic.cpp b/checker/ets/dynamic.cpp index 7dfc0a25b61ae0bd56d9d7a478590c3253084ceb..02aac052b538e6e6cc31bbe276fc5c2e0336959e 100644 --- a/checker/ets/dynamic.cpp +++ b/checker/ets/dynamic.cpp @@ -609,6 +609,7 @@ void ETSChecker::BuildDynamicImportClass() auto *var = scope->AddDecl(Allocator(), decl, Binder()->Extension()); var->AddFlag(binder::VariableFlags::PROPERTY); field_ident->SetVariable(var); + var->SetTsType(GlobalBuiltinDynamicType(import->Language())); class_type->AddProperty(var->AsLocalVariable()); diff --git a/checker/ets/helpers.cpp b/checker/ets/helpers.cpp index 5302988b7e1041105d710f43b2707035f14d6614..b8ef228820c382a2ac90e5a003f790ab86a55dea 100644 --- a/checker/ets/helpers.cpp +++ b/checker/ets/helpers.cpp @@ -132,6 +132,14 @@ Type *ETSChecker::GetNonConstantTypeFromPrimitiveType(Type *type) Type *ETSChecker::GetTypeOfVariable(binder::Variable *const var) { + if (IsVariableGetterSetter(var)) { + auto *prop_type = var->TsType()->AsETSFunctionType(); + if (prop_type->HasTypeFlag(checker::TypeFlag::GETTER)) { + return prop_type->FindGetter()->ReturnType(); + } + return prop_type->FindSetter()->Params()[0]->TsType(); + } + if (var->TsType() != nullptr) { return var->TsType(); } @@ -269,7 +277,7 @@ binder::Variable *ETSChecker::FindVariableInGlobal(const ir::Identifier *const i return Scope()->FindInGlobal(identifier->Name(), binder::ResolveBindingOptions::ALL).variable; } -bool ETSChecker::IsVariableStatic(const binder::Variable *var) +bool ETSChecker::IsVariableStatic(const binder::Variable *var) const { if (var->HasFlag(binder::VariableFlags::METHOD)) { return var->TsType()->AsETSFunctionType()->CallSignatures()[0]->HasSignatureFlag(SignatureFlags::STATIC); @@ -277,6 +285,11 @@ bool ETSChecker::IsVariableStatic(const binder::Variable *var) return var->HasFlag(binder::VariableFlags::STATIC); } +bool ETSChecker::IsVariableGetterSetter(const binder::Variable *var) const +{ + return var->TsType() != nullptr && var->TsType()->HasTypeFlag(TypeFlag::GETTER_SETTER); +} + void ETSChecker::ValidateResolvedIdentifier(const ir::Identifier *const ident, binder::Variable *const resolved) { const auto throw_error = [this, ident]() { @@ -498,6 +511,10 @@ Type *ETSChecker::ResolveIdentifier(ir::Identifier *const ident) void ETSChecker::ValidateUnaryOperatorOperand(binder::Variable *variable) { + if (IsVariableGetterSetter(variable)) { + return; + } + if (variable->Declaration()->IsConstDecl()) { if (HasStatus(CheckerStatus::IN_CONSTRUCTOR | CheckerStatus::IN_STATIC_BLOCK) && !variable->HasFlag(binder::VariableFlags::EXPLICIT_INIT_REQUIRED)) { diff --git a/checker/ets/object.cpp b/checker/ets/object.cpp index 442a556b769edd520eb2b89722252b1409de4cfd..81f80b0d6ea66f11122a122df2c080198c15a7f9 100644 --- a/checker/ets/object.cpp +++ b/checker/ets/object.cpp @@ -707,7 +707,7 @@ void ETSChecker::CheckClassDefinition(ir::ClassDefinition *class_def) ValidateOverriding(class_type, class_def->Start()); CheckValidInheritance(class_type, class_def); CheckConstFields(class_type); - CheckGetterSetterModifiers(class_def); + CheckGetterSetterProperties(class_type); } static bool IsAsyncMethod(ir::AstNode *node) @@ -1045,140 +1045,61 @@ binder::LocalVariable *ETSChecker::ResolveMemberReference(const ir::MemberExpres return prop_var; } - auto search_flag = [member_expr]() { - const auto base_flags = PropertySearchFlags::SEARCH_IN_BASE | PropertySearchFlags::SEARCH_IN_INTERFACES; + auto search_flag = [member_expr]() -> PropertySearchFlags { + constexpr auto FUNCTIONAL_FLAGS = PropertySearchFlags::SEARCH_METHOD | PropertySearchFlags::IS_FUNCTIONAL; + constexpr auto GETTER_FLAGS = PropertySearchFlags::SEARCH_METHOD | PropertySearchFlags::IS_GETTER; + constexpr auto SETTER_FLAGS = PropertySearchFlags::SEARCH_METHOD | PropertySearchFlags::IS_SETTER; switch (member_expr->Parent()->Type()) { case ir::AstNodeType::CALL_EXPRESSION: { if (member_expr->Parent()->AsCallExpression()->Callee() == member_expr) { - return PropertySearchFlags::SEARCH_METHOD | base_flags; - } - - if (member_expr->HasMemberKind(ir::MemberExpressionKind::GETTER)) { - return PropertySearchFlags::SEARCH_METHOD | PropertySearchFlags::SEARCH_INSTANCE_METHOD | - PropertySearchFlags::IS_GETTER; + return FUNCTIONAL_FLAGS; } break; } case ir::AstNodeType::ETS_NEW_CLASS_INSTANCE_EXPRESSION: { if (member_expr->Parent()->AsETSNewClassInstanceExpression()->GetTypeRef() == member_expr) { - return PropertySearchFlags::SEARCH_DECL | base_flags; + return PropertySearchFlags::SEARCH_DECL; } break; } case ir::AstNodeType::MEMBER_EXPRESSION: { - return PropertySearchFlags::SEARCH_FIELD | PropertySearchFlags::SEARCH_DECL | base_flags; - } - case ir::AstNodeType::VARIABLE_DECLARATOR: { - const auto *var_init = member_expr->Parent()->AsVariableDeclarator()->Init(); - if (var_init->IsMemberExpression() && - var_init->AsMemberExpression()->HasMemberKind(ir::MemberExpressionKind::GETTER)) { - return PropertySearchFlags::SEARCH_METHOD | PropertySearchFlags::SEARCH_INSTANCE_METHOD | - PropertySearchFlags::IS_GETTER; - } - - break; + return PropertySearchFlags::SEARCH_FIELD | PropertySearchFlags::SEARCH_DECL | GETTER_FLAGS; } case ir::AstNodeType::UPDATE_EXPRESSION: case ir::AstNodeType::UNARY_EXPRESSION: case ir::AstNodeType::BINARY_EXPRESSION: { - auto prop_search_flags = PropertySearchFlags::SEARCH_FIELD; - if (member_expr->Parent()->IsBinaryExpression()) { - const auto *binary = member_expr->Parent()->AsBinaryExpression(); - auto properflags = [](const ir::MemberExpression *expr) { - if (expr->HasMemberKind(ir::MemberExpressionKind::GETTER)) { - return PropertySearchFlags::SEARCH_METHOD | PropertySearchFlags::SEARCH_INSTANCE_METHOD | - PropertySearchFlags::IS_GETTER; - } - - return PropertySearchFlags::NO_OPTS; - }; - - if (binary->Left()->IsMemberExpression()) { - prop_search_flags |= properflags(binary->Left()->AsMemberExpression()); - } - - if (binary->Right()->IsMemberExpression()) { - prop_search_flags |= properflags(binary->Right()->AsMemberExpression()); - } - } - - return prop_search_flags | base_flags; + return PropertySearchFlags::SEARCH_FIELD | GETTER_FLAGS; } case ir::AstNodeType::ASSIGNMENT_EXPRESSION: { const auto *const assignment_expr = member_expr->Parent()->AsAssignmentExpression(); - if (assignment_expr->Left()->IsMemberExpression() && - assignment_expr->Left()->AsMemberExpression()->HasMemberKind(ir::MemberExpressionKind::SETTER)) { - if (assignment_expr->Right()->IsMemberExpression() && - assignment_expr->Right()->AsMemberExpression()->HasMemberKind( - ir::MemberExpressionKind::GETTER)) { - return PropertySearchFlags::SEARCH_METHOD | PropertySearchFlags::SEARCH_INSTANCE_METHOD | - PropertySearchFlags::IS_GETTER; - } - - if (assignment_expr->Right()->IsBinaryExpression()) { - const auto *binary_expr = assignment_expr->Right()->AsBinaryExpression(); - if ((binary_expr->Left()->IsMemberExpression() && - binary_expr->Left()->AsMemberExpression()->HasMemberKind( - ir::MemberExpressionKind::GETTER)) || - (binary_expr->Right()->IsMemberExpression() && - binary_expr->Right()->AsMemberExpression()->HasMemberKind( - ir::MemberExpressionKind::GETTER))) { - return PropertySearchFlags::SEARCH_METHOD | PropertySearchFlags::SEARCH_INSTANCE_METHOD | - PropertySearchFlags::IS_GETTER; - } - } - - return PropertySearchFlags::SEARCH_METHOD | PropertySearchFlags::SEARCH_INSTANCE_METHOD | - PropertySearchFlags::IS_SETTER; - } - if (assignment_expr->Left() == member_expr) { - return PropertySearchFlags::SEARCH_FIELD | base_flags; - } - - if (assignment_expr->Right() == member_expr) { - auto *target_type = assignment_expr->Left()->TsType(); - ASSERT(target_type != nullptr); - - if (target_type->IsETSObjectType() && - target_type->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) { - return PropertySearchFlags::SEARCH_METHOD | base_flags; - } - - ASSERT(assignment_expr->Right()->IsMemberExpression()); - if (assignment_expr->Right()->AsMemberExpression()->HasMemberKind( - ir::MemberExpressionKind::GETTER)) { - return PropertySearchFlags::SEARCH_METHOD | PropertySearchFlags::SEARCH_INSTANCE_METHOD | - PropertySearchFlags::IS_GETTER; + if (assignment_expr->OperatorType() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) { + return PropertySearchFlags::SEARCH_FIELD | SETTER_FLAGS; } - - return PropertySearchFlags::SEARCH_FIELD | base_flags; + return PropertySearchFlags::SEARCH_FIELD | GETTER_FLAGS | SETTER_FLAGS; } - break; - } - case ir::AstNodeType::RETURN_STATEMENT: { - const auto *return_statement = member_expr->Parent()->AsReturnStatement(); - if (return_statement->Argument()->IsMemberExpression() && - return_statement->Argument()->AsMemberExpression()->HasMemberKind( - ir::MemberExpressionKind::GETTER)) { - return PropertySearchFlags::SEARCH_METHOD | PropertySearchFlags::SEARCH_INSTANCE_METHOD | - PropertySearchFlags::IS_GETTER; + auto const *target_type = assignment_expr->Left()->TsType(); + + if (target_type->IsETSObjectType() && + target_type->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) { + return FUNCTIONAL_FLAGS; } - break; + return PropertySearchFlags::SEARCH_FIELD | GETTER_FLAGS; } default: { break; } } - return PropertySearchFlags::SEARCH_FIELD | PropertySearchFlags::SEARCH_METHOD | base_flags; + return PropertySearchFlags::SEARCH_FIELD | FUNCTIONAL_FLAGS | GETTER_FLAGS; }(); + search_flag |= PropertySearchFlags::SEARCH_IN_BASE | PropertySearchFlags::SEARCH_IN_INTERFACES; const auto *const target_ref = [member_expr]() -> const binder::Variable * { if (member_expr->Object()->IsIdentifier()) { @@ -1205,45 +1126,30 @@ binder::LocalVariable *ETSChecker::ResolveMemberReference(const ir::MemberExpres auto *const prop = target->GetProperty(member_expr->Property()->AsIdentifier()->Name(), search_flag); ValidateResolvedProperty(prop, target, member_expr->Property()->AsIdentifier(), search_flag); - if (prop->TsType() != nullptr) { - if ((search_flag & PropertySearchFlags::IS_GETTER) != 0) { - const auto get_return_type = [](ir::MethodDefinition *method) { - if (method->Kind() == ir::MethodDefinitionKind::GET) { - return method->Function()->Signature()->ReturnType(); - } + if (prop->HasFlag(binder::VariableFlags::METHOD) && !IsVariableGetterSetter(prop) && + (search_flag & PropertySearchFlags::IS_FUNCTIONAL) == 0) { + ThrowTypeError("Method used in wrong context", member_expr->Property()->Start()); + } - return method->Overloads()[0]->Function()->Signature()->ReturnType(); - }; + if (IsVariableGetterSetter(prop)) { + auto *prop_type = prop->TsType()->AsETSFunctionType(); + ASSERT((prop_type->FindGetter() != nullptr) == prop_type->HasTypeFlag(TypeFlag::GETTER)); + ASSERT((prop_type->FindSetter() != nullptr) == prop_type->HasTypeFlag(TypeFlag::SETTER)); - const auto &methods = member_expr->AsMemberExpression()->ObjType()->InstanceMethods(); - const auto res = methods.find(member_expr->Property()->AsIdentifier()->Name()); - if (res != methods.end()) { - prop->SetTsType(get_return_type(res->second->Declaration()->Node()->AsMethodDefinition())); - } else { - const auto &static_methods = member_expr->AsMemberExpression()->ObjType()->StaticMethods(); - const auto static_res = static_methods.find(member_expr->Property()->AsIdentifier()->Name()); - if (static_res != static_methods.end()) { - prop->SetTsType(get_return_type(static_res->second->Declaration()->Node()->AsMethodDefinition())); - } - } + auto const &source_pos = member_expr->Property()->Start(); - return prop; + if ((search_flag & PropertySearchFlags::IS_GETTER) != 0) { + if (!prop_type->HasTypeFlag(TypeFlag::GETTER)) { + ThrowTypeError("Cannot read from this property because it is writeonly.", source_pos); + } + ValidateSignatureAccessibility(member_expr->ObjType(), prop_type->FindGetter(), source_pos); } if ((search_flag & PropertySearchFlags::IS_SETTER) != 0) { - const auto &func_type = prop->TsType()->AsETSFunctionType(); - for (const auto *sig : func_type->CallSignatures()) { - if (sig->Function()->IsSetter()) { - if (sig->Function()->ReturnTypeAnnotation() != nullptr && - sig->Function()->ReturnTypeAnnotation()->TsType() != GlobalBuiltinVoidType()) { - ThrowTypeError("Setter must have void return type", sig->Function()->Start()); - } - - func_type->AddTypeFlag(TypeFlag::SETTER); - } + if (!prop_type->HasTypeFlag(TypeFlag::SETTER)) { + ThrowTypeError("Cannot assign to this property because it is readonly.", source_pos); } - - return prop; + ValidateSignatureAccessibility(member_expr->ObjType(), prop_type->FindSetter(), source_pos); } } @@ -1263,7 +1169,7 @@ binder::LocalVariable *ETSChecker::ResolveMemberReference(const ir::MemberExpres GetTypeOfVariable(prop); - if (prop->TsType()->IsETSFunctionType()) { + if (prop->TsType()->IsETSFunctionType() && !IsVariableGetterSetter(prop)) { if (type_annotation == nullptr) { ThrowTypeError({"Cannot infer type for ", target_ident->Name(), " because method reference needs an explicit target type"}, @@ -1332,43 +1238,39 @@ void ETSChecker::CheckValidInheritance(ETSObjectType *class_type, ir::ClassDefin } } -void ETSChecker::CheckGetterSetterModifiers(const ir::ClassDefinition *class_def) +void ETSChecker::CheckGetterSetterProperties(ETSObjectType *class_type) { - const auto accessor_modifiers = ir::ModifierFlags::ACCESSOR_MODIFIERS; + auto const check_getter_setter = [this](binder::LocalVariable *var, util::StringView name) { + auto const *type = var->TsType()->AsETSFunctionType(); + auto const *sig_getter = type->FindGetter(); + auto const *sig_setter = type->FindSetter(); + + for (auto const *sig : type->CallSignatures()) { + if (!sig->Function()->IsGetter() && !sig->Function()->IsSetter()) { + ThrowTypeError({"Method cannot use the same name as ", name, " accessor property"}, + sig->Function()->Start()); + } + if (sig != sig_getter && sig != sig_setter) { + ThrowTypeError("Duplicate accessor definition", sig->Function()->Start()); + } + } - const auto check_modifiers = [this](const ir::ModifierFlags base_modifiers, const ir::ModifierFlags other_modifiers, - const lexer::SourcePosition &pos) { - if (static_cast(accessor_modifiers & base_modifiers) != - static_cast(accessor_modifiers & other_modifiers)) { - ThrowTypeError("Getter and setter methods must have the same accessor modifiers", pos); + if (((sig_getter->Function()->Modifiers() ^ sig_setter->Function()->Modifiers()) & + ir::ModifierFlags::ACCESSOR_MODIFIERS) != 0) { + ThrowTypeError("Getter and setter methods must have the same accessor modifiers", + sig_getter->Function()->Start()); } }; - for (auto *it : class_def->Body()) { - if (it->IsMethodDefinition() && - (it->AsMethodDefinition()->Function()->IsGetter() || it->AsMethodDefinition()->Function()->IsSetter())) { - // Base case - if (!it->AsMethodDefinition()->Overloads().empty()) { - check_modifiers(it->AsMethodDefinition()->Modifiers(), - it->AsMethodDefinition()->Overloads()[0]->Modifiers(), - it->AsMethodDefinition()->Start()); - return; - } - // Static case - if (it->AsMethodDefinition()->IsStatic()) { - for (auto class_body : class_def->Body()) { - if (class_body->IsMethodDefinition() && - (class_body->AsMethodDefinition()->Function()->IsGetter() || - class_body->AsMethodDefinition()->Function()->IsSetter())) { - const auto *base = class_body->AsMethodDefinition(); - const auto *other = it->AsMethodDefinition(); - if (base != other && - base->Function()->Id()->Name().Is(other->Function()->Id()->Name().Mutf8())) { - check_modifiers(base->Modifiers(), other->Modifiers(), base->Start()); - } - } - } - } + for (const auto &[name, var] : class_type->InstanceMethods()) { + if (IsVariableGetterSetter(var)) { + check_getter_setter(var, name); + } + } + + for (const auto &[name, var] : class_type->StaticMethods()) { + if (IsVariableGetterSetter(var)) { + check_getter_setter(var, name); } } } diff --git a/checker/types/ets/etsFunctionType.h b/checker/types/ets/etsFunctionType.h index 5e588ff61c1fcddfdd16e354c6472f32f17ae8a9..d09f77fcfee4b38f316d8deb0d956681b823be17 100644 --- a/checker/types/ets/etsFunctionType.h +++ b/checker/types/ets/etsFunctionType.h @@ -18,6 +18,7 @@ #include "checker/types/type.h" #include "checker/types/signature.h" +#include "ir/base/scriptFunction.h" namespace panda::es2panda::checker { @@ -51,6 +52,11 @@ public: void AddCallSignature(Signature *signature) { + if (signature->Function()->IsGetter()) { + AddTypeFlag(TypeFlag::GETTER); + } else if (signature->Function()->IsSetter()) { + AddTypeFlag(TypeFlag::SETTER); + } call_signatures_.push_back(signature); } @@ -75,6 +81,26 @@ public: return nullptr; } + Signature *FindGetter() const + { + for (auto *sig : call_signatures_) { + if (sig->Function()->IsGetter()) { + return sig; + } + } + return nullptr; + } + + Signature *FindSetter() const + { + for (auto *sig : call_signatures_) { + if (sig->Function()->IsSetter()) { + return sig; + } + } + return nullptr; + } + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override { ss << "ets.lang.Object"; diff --git a/checker/types/ets/etsObjectType.cpp b/checker/types/ets/etsObjectType.cpp index af7582cadd2d1d5cc48da4684a645f656af38c5b..0a3eaa30574b2804282e265491d72fd63df08d2f 100644 --- a/checker/types/ets/etsObjectType.cpp +++ b/checker/types/ets/etsObjectType.cpp @@ -113,6 +113,7 @@ binder::LocalVariable *ETSObjectType::CreateSyntheticVarFromEverySignature(const func_type->AddTypeFlag(TypeFlag::SYNTHETIC); binder::LocalVariable *functional_interface = CollectSignaturesForSyntheticType(func_type, name, flags); + if (functional_interface != nullptr) { return functional_interface; } @@ -148,15 +149,6 @@ binder::LocalVariable *ETSObjectType::CollectSignaturesForSyntheticType(ETSFunct return found; } - if (found->Declaration()->Node()->IsMethodDefinition()) { - const auto *method = found->Declaration()->Node()->AsMethodDefinition(); - if (method->Function()->IsGetter()) { - func_type->AddTypeFlag(TypeFlag::GETTER); - } else if (method->Function()->IsSetter()) { - func_type->AddTypeFlag(TypeFlag::SETTER); - } - } - ASSERT(found->TsType()->IsETSFunctionType()); for (auto *it : found->TsType()->AsETSFunctionType()->CallSignatures()) { if (((flags & PropertySearchFlags::IGNORE_ABSTRACT) != 0) && @@ -177,15 +169,6 @@ binder::LocalVariable *ETSObjectType::CollectSignaturesForSyntheticType(ETSFunct return found; } - if (found->Declaration()->Node()->IsMethodDefinition()) { - const auto *method = found->Declaration()->Node()->AsMethodDefinition(); - if (method->Function()->IsGetter()) { - func_type->AddTypeFlag(TypeFlag::GETTER); - } else if (method->Function()->IsSetter()) { - func_type->AddTypeFlag(TypeFlag::SETTER); - } - } - ASSERT(found->TsType()->IsETSFunctionType()); for (auto *it : found->TsType()->AsETSFunctionType()->CallSignatures()) { if (((flags & PropertySearchFlags::IGNORE_ABSTRACT) != 0) && diff --git a/checker/types/ets/etsObjectType.h b/checker/types/ets/etsObjectType.h index d23996a8617dc23c6d675f537cfb23b36975ccdf..3f5ffdcc326c7331cd1351a3f9ba9ff5c45ad8c5 100644 --- a/checker/types/ets/etsObjectType.h +++ b/checker/types/ets/etsObjectType.h @@ -85,8 +85,9 @@ enum class PropertySearchFlags : uint32_t { IGNORE_ABSTRACT = 1U << 8U, ALLOW_FUNCTIONAL_INTERFACE = 1U << 9U, DISALLOW_SYNTHETIC_METHOD_CREATION = 1U << 10U, - IS_SETTER = 1U << 11U, - IS_GETTER = 1U << 12U, + IS_FUNCTIONAL = 1U << 11U, + IS_SETTER = 1U << 12U, + IS_GETTER = 1U << 13U, SEARCH_INSTANCE = SEARCH_INSTANCE_FIELD | SEARCH_INSTANCE_METHOD | SEARCH_INSTANCE_DECL, SEARCH_STATIC = SEARCH_STATIC_FIELD | SEARCH_STATIC_METHOD | SEARCH_STATIC_DECL, diff --git a/checker/types/typeFlag.h b/checker/types/typeFlag.h index 720304a12a56f26d05ddbf665696034f9056f445..3021616292f58c52f4d9b5e8942416d20844f67c 100644 --- a/checker/types/typeFlag.h +++ b/checker/types/typeFlag.h @@ -125,6 +125,7 @@ enum class TypeFlag : uint64_t { POSSIBLY_FALSY = DEFINITELY_FALSY | STRING | NUMBER | BOOLEAN | BIGINT, VALID_ARITHMETIC_TYPE = ANY | NUMBER_LIKE | BIGINT_LIKE | ENUM, UNIT = LITERAL | UNIQUE_SYMBOL | NULLABLE, + GETTER_SETTER = GETTER | SETTER, }; DEFINE_BITOPS(TypeFlag) diff --git a/compiler/base/lreference.cpp b/compiler/base/lreference.cpp index 0f09dcd1dfaa5e3ce7ff169ec3cb0b78257243d9..1202ef83796f520c4fd6a7d0ae55edaabec352bd 100644 --- a/compiler/base/lreference.cpp +++ b/compiler/base/lreference.cpp @@ -25,6 +25,7 @@ #include "ir/base/spreadElement.h" #include "ir/base/classProperty.h" #include "ir/base/classDefinition.h" +#include "ir/base/scriptFunction.h" #include "ir/expressions/assignmentExpression.h" #include "ir/expressions/identifier.h" #include "ir/expressions/memberExpression.h" @@ -183,8 +184,8 @@ ETSLReference::ETSLReference(CodeGen *cg, const ir::AstNode *node, ReferenceKind const auto *member_expr = Node()->AsMemberExpression(); static_obj_ref_ = member_expr->Object()->TsType(); - if (!member_expr->IsComputed() && - (member_expr->PropVar()->HasFlag(binder::VariableFlags::STATIC) && !static_obj_ref_->IsETSDynamicType())) { + if (!member_expr->IsComputed() && etsg_->Checker()->IsVariableStatic(member_expr->PropVar()) && + !static_obj_ref_->IsETSDynamicType()) { return; } @@ -288,6 +289,20 @@ void ETSLReference::SetValue() const break; } + if (member_expr->PropVar()->TsType()->HasTypeFlag(checker::TypeFlag::GETTER_SETTER)) { + const auto *sig = member_expr->PropVar()->TsType()->AsETSFunctionType()->FindSetter(); + + auto arg_reg = etsg_->AllocReg(); + etsg_->StoreAccumulator(Node(), arg_reg); + + if (sig->Function()->IsStatic()) { + etsg_->CallThisStatic0(Node(), arg_reg, sig->InternalName()); + } else { + etsg_->CallThisVirtual1(Node(), base_reg_, sig->InternalName(), arg_reg); + } + break; + } + auto &prop_name = member_expr->Property()->AsIdentifier()->Name(); if (member_expr->PropVar()->HasFlag(binder::VariableFlags::STATIC)) { util::StringView full_name = diff --git a/compiler/core/ETSGen.cpp b/compiler/core/ETSGen.cpp index 21e7ba4606059dcf6cb4ec54e857473fc3c6f72d..6e7d2e7b2403dc4c911d7960ef34a225d21edcb4 100644 --- a/compiler/core/ETSGen.cpp +++ b/compiler/core/ETSGen.cpp @@ -331,13 +331,6 @@ void ETSGen::StoreVar(const ir::AstNode *node, const binder::ConstScopeFindResul } } -void ETSGen::EmitGetter(const ir::AstNode *node, const VReg vreg, ir::ScriptFunction *script_func) -{ - auto *signature = script_func->Signature(); - CallThisVirtual(node, vreg, signature, script_func->Params()); - SetAccumulatorType(signature->ReturnType()); -} - util::StringView ETSGen::FormClassPropReference(const checker::ETSObjectType *class_type, const util::StringView &name) { std::stringstream ss; @@ -710,31 +703,6 @@ void ETSGen::EmitIsInstance(const ir::AstNode *const node, const VReg lhs) SetAccumulatorType(Checker()->GlobalETSBooleanType()); } -void ETSGen::EmitSetter(const ir::MemberExpression *member, ir::Expression *right) -{ - compiler::VReg callee_reg = AllocReg(); - auto ottctx = compiler::TargetTypeContext(this, member->Object()->TsType()); - ArenaVector args(Allocator()->Adapter()); - args.push_back(right); - - const auto &func_type = member->TsType()->AsETSFunctionType(); - for (const auto &sig : func_type->CallSignatures()) { - if (!sig->Function()->IsSetter()) { - continue; - } - - if (!sig->Function()->IsStatic()) { - member->Object()->Compile(this); - StoreAccumulator(member, callee_reg); - CallThisVirtual(member, callee_reg, sig, args); - } else { - CallStatic(member, sig, args); - } - - SetAccumulatorType(sig->ReturnType()); - } -} - bool ETSGen::TryLoadConstantExpression(const ir::Expression *node) { const auto *type = node->TsType(); diff --git a/compiler/core/ETSGen.h b/compiler/core/ETSGen.h index d7fb58f3c991ee94d9c81c7a64c5ffb8e85e846c..9d75aacefcd401a0eba1707dfbfd52619ddbfa5c 100644 --- a/compiler/core/ETSGen.h +++ b/compiler/core/ETSGen.h @@ -65,8 +65,6 @@ public: [[nodiscard]] util::StringView FormClassPropReference(const checker::ETSObjectType *class_type, const util::StringView &name); - void EmitGetter(const ir::AstNode *node, VReg vreg, ir::ScriptFunction *script_func); - void StoreProperty(const ir::AstNode *node, const checker::Type *prop_type, VReg obj_reg, const util::StringView &name); void LoadProperty(const ir::AstNode *node, const checker::Type *prop_type, VReg obj_reg, @@ -88,7 +86,6 @@ public: void EmitReturnVoid(const ir::AstNode *node); void LoadBuiltinVoid(const ir::AstNode *node); void ReturnAcc(const ir::AstNode *node); - void EmitSetter(const ir::MemberExpression *member, ir::Expression *right); void EmitIsInstance(const ir::AstNode *node, VReg lhs); @@ -365,6 +362,11 @@ public: Ra().Emit(node, name, ctor, arg0); } + void CallStatic0(const ir::AstNode *const node, const util::StringView name) + { + Ra().Emit(node, name, dummy_reg_, dummy_reg_); + } + void CallThisStatic0(const ir::AstNode *const node, const VReg ctor, const util::StringView name) { Ra().Emit(node, name, ctor, dummy_reg_); diff --git a/compiler/scripts/signatures.yaml b/compiler/scripts/signatures.yaml index d53c272c8ea33b8540c47562a119d8a5a805a069..30c12e9377d30e55b7b0681417bce7b755f3b337 100644 --- a/compiler/scripts/signatures.yaml +++ b/compiler/scripts/signatures.yaml @@ -90,6 +90,10 @@ defines: ref: GENERIC_END - name: ctor ref: CONSTRUCTOR + - name: + ref: GETTER_BEGIN + - name: + ref: SETTER_BEGIN - name: param0 ref: CTOR_PARAM0 - name: param1 diff --git a/ir/astNode.h b/ir/astNode.h index 496f9f8543f3d5754195f91a97ed97e0b4519406..9e7df719fb510fa16dcd6544aaf5f6a9485bff4d 100644 --- a/ir/astNode.h +++ b/ir/astNode.h @@ -96,7 +96,7 @@ enum class ModifierFlags : uint32_t { ALL = STATIC | ASYNC | ACCESS | DECLARE | READONLY | ABSTRACT, ALLOWED_IN_CTOR_PARAMETER = ACCESS | READONLY, INTERNAL_PROTECTED = INTERNAL | PROTECTED, - ACCESSOR_MODIFIERS = ABSTRACT | STATIC | FINAL | OVERRIDE + ACCESSOR_MODIFIERS = ABSTRACT | FINAL | OVERRIDE }; DEFINE_BITOPS(ModifierFlags) diff --git a/ir/base/methodDefinition.cpp b/ir/base/methodDefinition.cpp index 7e15b36ff3e231ac9a884c1446c1d46fd146d97a..4331a00b4716541f3dc08db2d8c4b26d709dd805 100644 --- a/ir/base/methodDefinition.cpp +++ b/ir/base/methodDefinition.cpp @@ -204,6 +204,14 @@ checker::Type *MethodDefinition::Check(checker::ETSChecker *checker) checker->Context().SetContainingSignature(nullptr); } + if (script_func->IsSetter() && (script_func->Signature()->ReturnType() != checker->GlobalBuiltinVoidType())) { + checker->ThrowTypeError("Setter must have void return type", script_func->Start()); + } + + if (script_func->IsGetter() && (script_func->Signature()->ReturnType() == checker->GlobalBuiltinVoidType())) { + checker->ThrowTypeError("Getter must return a value", script_func->Start()); + } + checker->CheckOverride(TsType()->AsETSFunctionType()->FindSignature(Function())); for (auto *it : overloads_) { diff --git a/ir/expressions/arrowFunctionExpression.cpp b/ir/expressions/arrowFunctionExpression.cpp index efe0e8f9d03fba43172eb344ce5079e14a248997..66f026199b7880a7ffbc2a4202a9cb4d72faf1dc 100644 --- a/ir/expressions/arrowFunctionExpression.cpp +++ b/ir/expressions/arrowFunctionExpression.cpp @@ -49,6 +49,7 @@ void ArrowFunctionExpression::Compile(compiler::PandaGen *pg) const void ArrowFunctionExpression::Compile(compiler::ETSGen *etsg) const { + ASSERT(resolved_lambda_ != nullptr); auto *ctor = resolved_lambda_->TsType()->AsETSObjectType()->ConstructSignatures()[0]; std::vector arguments; diff --git a/ir/expressions/assignmentExpression.cpp b/ir/expressions/assignmentExpression.cpp index 55dddea59c6617d026f441ae7064b10c8056a91f..ed4028129c90f193ae934f8ee1b651c497adc852 100644 --- a/ir/expressions/assignmentExpression.cpp +++ b/ir/expressions/assignmentExpression.cpp @@ -20,6 +20,7 @@ #include "compiler/core/ETSGen.h" #include "compiler/core/regScope.h" #include "ir/astDump.h" +#include "ir/base/scriptFunction.h" #include "ir/base/spreadElement.h" #include "ir/expressions/identifier.h" #include "ir/expressions/arrayExpression.h" @@ -149,13 +150,6 @@ void AssignmentExpression::Compile(compiler::ETSGen *etsg) const // All other operations are handled in OpAssignmentLowering ASSERT(operator_ == lexer::TokenType::PUNCTUATOR_SUBSTITUTION); compiler::RegScope rs(etsg); - - if (left_->IsMemberExpression() && left_->AsMemberExpression()->TsType()->IsETSFunctionType() && - left_->AsMemberExpression()->TsType()->AsETSFunctionType()->HasTypeFlag(checker::TypeFlag::SETTER)) { - etsg->EmitSetter(left_->AsMemberExpression(), right_); - return; - } - auto lref = compiler::ETSLReference::Create(etsg, left_, false); auto ttctx = compiler::TargetTypeContext(etsg, TsType()); @@ -251,20 +245,7 @@ checker::Type *AssignmentExpression::Check([[maybe_unused]] checker::ETSChecker if (left_->IsIdentifier()) { target_ = left_->AsIdentifier()->Variable(); - } else if (left_type->IsETSFunctionType() && - left_type->AsETSFunctionType()->HasTypeFlag(checker::TypeFlag::SETTER)) { - if (right_->IsBinaryExpression()) { - right_->Check(checker); - } - - ArenaVector arguments(checker->Allocator()->Adapter()); - arguments.push_back(right_); - auto *signature = checker->ResolveCallExpression(left_type->AsETSFunctionType()->CallSignatures(), nullptr, - arguments, Start()); - SetTsType(signature->ReturnType()); - return TsType(); } else { - ASSERT(left_->IsMemberExpression()); target_ = left_->AsMemberExpression()->PropVar(); } diff --git a/ir/expressions/memberExpression.cpp b/ir/expressions/memberExpression.cpp index 4fbd441462ca2898d5fb46130c52ecc8340d3818..ca4c6c0c77f860e5a02578312bfaf535e98668f5 100644 --- a/ir/expressions/memberExpression.cpp +++ b/ir/expressions/memberExpression.cpp @@ -186,55 +186,22 @@ void MemberExpression::Compile(compiler::ETSGen *etsg) const return; } - if (prop_var_->HasFlag(binder::VariableFlags::STATIC)) { + if (etsg->Checker()->IsVariableStatic(prop_var_)) { auto ttctx = compiler::TargetTypeContext(etsg, TsType()); + if (prop_var_->TsType()->HasTypeFlag(checker::TypeFlag::GETTER_SETTER)) { + checker::Signature *sig = prop_var_->TsType()->AsETSFunctionType()->FindGetter(); + etsg->CallStatic0(this, sig->InternalName()); + etsg->SetAccumulatorType(sig->ReturnType()); + return; + } + util::StringView full_name = etsg->FormClassPropReference(object_->TsType()->AsETSObjectType(), prop_name); etsg->LoadStaticProperty(this, TsType(), full_name); etsg->ApplyConversion(this); return; } - if (object_->TsType()->IsETSObjectType() && - HasMemberKind(MemberExpressionKind::GETTER | MemberExpressionKind::SETTER)) { - const auto &get_set = object_->TsType()->AsETSObjectType()->InstanceMethods(); - const auto res = get_set.find(prop_name); - if (res != get_set.end()) { - auto *decl = res->second->Declaration(); - ASSERT(decl != nullptr); - if (decl->Node()->IsMethodDefinition()) { - compiler::VReg callee_reg = etsg->AllocReg(); - auto ottctx = compiler::TargetTypeContext(etsg, object_->TsType()); - object_->Compile(etsg); - etsg->StoreAccumulator(this, callee_reg); - - if (decl->Node()->AsMethodDefinition()->Kind() == ir::MethodDefinitionKind::GET) { - etsg->EmitGetter(this, callee_reg, decl->Node()->AsMethodDefinition()->Function()); - } else { - etsg->EmitGetter(this, callee_reg, decl->Node()->AsMethodDefinition()->Overloads()[0]->Function()); - } - return; - } - } else { - const auto &static_get_set = object_->TsType()->AsETSObjectType()->StaticMethods(); - const auto static_res = static_get_set.find(prop_name); - if (static_res != static_get_set.end()) { - auto *decl = static_res->second->Declaration(); - ASSERT(decl != nullptr); - if (decl->Node()->IsMethodDefinition()) { - auto *script = decl->Node()->AsMethodDefinition()->Function(); - if (decl->Node()->AsMethodDefinition()->Kind() == ir::MethodDefinitionKind::SET) { - script = decl->Node()->AsMethodDefinition()->Overloads()[0]->AsMethodDefinition()->Function(); - } - - etsg->CallStatic(this, script->Signature(), script->Params()); - etsg->SetAccumulatorType(script->Signature()->ReturnType()); - return; - } - } - } - } - auto ottctx = compiler::TargetTypeContext(etsg, object_->TsType()); object_->Compile(etsg); @@ -258,7 +225,11 @@ void MemberExpression::Compile(compiler::ETSGen *etsg) const auto ttctx = compiler::TargetTypeContext(etsg, TsType()); auto load_property = [this, etsg, obj_reg, prop_name]() { - if (object_->TsType()->IsETSDynamicType()) { + if (prop_var_->TsType()->HasTypeFlag(checker::TypeFlag::GETTER_SETTER)) { + checker::Signature *sig = prop_var_->TsType()->AsETSFunctionType()->FindGetter(); + etsg->CallThisVirtual0(this, obj_reg, sig->InternalName()); + etsg->SetAccumulatorType(sig->ReturnType()); + } else if (object_->TsType()->IsETSDynamicType()) { auto lang = object_->TsType()->AsETSDynamicType()->Language(); etsg->LoadPropertyDynamic(this, TsType(), obj_reg, prop_name, lang); } else { @@ -398,27 +369,6 @@ checker::Type *MemberExpression::Check(checker::ETSChecker *checker) } obj_type_ = base_type->AsETSObjectType(); - - if (Property()->IsIdentifier()) { - const auto *prop = ObjType()->GetProperty(Property()->AsIdentifier()->Name(), - checker::PropertySearchFlags::SEARCH_INSTANCE_METHOD | - checker::PropertySearchFlags::SEARCH_STATIC_METHOD); - - if (prop != nullptr && prop->TsType() != nullptr && prop->TsType()->IsETSFunctionType()) { - const auto &func_type = prop->TsType()->AsETSFunctionType(); - - for (auto *sig : func_type->CallSignatures()) { - if (sig->Function()->IsSetter()) { - AddMemberKind(ir::MemberExpressionKind::SETTER); - checker->ValidateSignatureAccessibility(obj_type_, sig, Start()); - } else if (sig->Function()->IsGetter()) { - AddMemberKind(ir::MemberExpressionKind::GETTER); - checker->ValidateSignatureAccessibility(obj_type_, sig, Start()); - } - } - } - } - prop_var_ = checker->ResolveMemberReference(this, obj_type_); checker->ValidatePropertyAccess(prop_var_, obj_type_, property_->Start()); SetTsType(checker->GetTypeOfVariable(prop_var_)); diff --git a/parser/ETSparser.cpp b/parser/ETSparser.cpp index 26ec1e48dedd6a830ddec10492c23f92564e6a5d..0377ef1732214df53ce10332660219839e05cd3d 100644 --- a/parser/ETSparser.cpp +++ b/parser/ETSparser.cpp @@ -2106,10 +2106,6 @@ void ETSParser::CreateClassFunctionDeclaration(ir::MethodDefinition *method) ThrowSyntaxError("Main overload is not enabled", method_name->Start()); } - if (method_name->IsMutator()) { - method_name->SetMutator(); - } - auto *current_node = found->Declaration()->Node(); if (current_node->AsMethodDefinition()->Function()->IsDefaultParamProxy()) { diff --git a/test/compiler/ets/identifierReference13-expected.txt b/test/compiler/ets/identifierReference13-expected.txt index c0045aae3754eb2df6d45b4add3689ebe59616db..36b01d450f17aedcedfae6ec0faaf5773a277a1f 100644 --- a/test/compiler/ets/identifierReference13-expected.txt +++ b/test/compiler/ets/identifierReference13-expected.txt @@ -973,4 +973,4 @@ } } } -TypeError: Property 'foo' does not exist on type 'B' [identifierReference13.ets:9:20] +TypeError: Method used in wrong context [identifierReference13.ets:9:20] diff --git a/test/compiler/ets/identifierReference8-expected.txt b/test/compiler/ets/identifierReference8-expected.txt index 629a07ece8ea34e572715d1bfcca6393b5ceb9c1..9e5b562f0913ed077d8bb1d2c7ffa3f63fb278bb 100644 --- a/test/compiler/ets/identifierReference8-expected.txt +++ b/test/compiler/ets/identifierReference8-expected.txt @@ -643,4 +643,4 @@ } } } -TypeError: Property 'foo' does not exist on type 'A' [identifierReference8.ets:9:10] +TypeError: Method used in wrong context [identifierReference8.ets:9:10] diff --git a/test/compiler/ets/identifierReference9-expected.txt b/test/compiler/ets/identifierReference9-expected.txt index b3f1e5124025f85b2198df53bce10accdfef61b8..f05d891791ad4fe4d7d24155ea14d103028d62cb 100644 --- a/test/compiler/ets/identifierReference9-expected.txt +++ b/test/compiler/ets/identifierReference9-expected.txt @@ -643,4 +643,4 @@ } } } -TypeError: Property 'foo' does not exist on type 'A' [identifierReference9.ets:9:10] +TypeError: Method used in wrong context [identifierReference9.ets:9:10] diff --git a/test/parser/ets/accessor_call-expected.txt b/test/parser/ets/accessor_call-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..2225d1a1c787691b6c180799734785f906db1629 --- /dev/null +++ b/test/parser/ets/accessor_call-expected.txt @@ -0,0 +1,675 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "A", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 8 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "x", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "get", + "accessibility": "public", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "x", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "returnType": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 2, + "column": 14 + }, + "end": { + "line": 2, + "column": 17 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "ReturnStatement", + "argument": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 2, + "column": 27 + }, + "end": { + "line": 2, + "column": 28 + } + } + }, + "loc": { + "start": { + "line": 2, + "column": 20 + }, + "end": { + "line": 2, + "column": 28 + } + } + } + ], + "loc": { + "start": { + "line": 2, + "column": 18 + }, + "end": { + "line": 2, + "column": 30 + } + } + }, + "loc": { + "start": { + "line": 2, + "column": 10 + }, + "end": { + "line": 2, + "column": 30 + } + } + }, + "loc": { + "start": { + "line": 2, + "column": 10 + }, + "end": { + "line": 2, + "column": 30 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 2, + "column": 10 + }, + "end": { + "line": 2, + "column": 30 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "constructor", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "constructor", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "constructor", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 3, + "column": 2 + }, + "end": { + "line": 3, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 9 + }, + "end": { + "line": 3, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 3, + "column": 2 + } + } + }, + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "ETSGLOBAL", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "main", + "decorators": [], + "loc": { + "start": { + "line": 5, + "column": 10 + }, + "end": { + "line": 5, + "column": 14 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "main", + "decorators": [], + "loc": { + "start": { + "line": 5, + "column": 10 + }, + "end": { + "line": 5, + "column": 14 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "returnType": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "void", + "decorators": [], + "loc": { + "start": { + "line": 5, + "column": 18 + }, + "end": { + "line": 5, + "column": 22 + } + } + }, + "loc": { + "start": { + "line": 5, + "column": 18 + }, + "end": { + "line": 5, + "column": 24 + } + } + }, + "loc": { + "start": { + "line": 5, + "column": 18 + }, + "end": { + "line": 5, + "column": 24 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "ETSNewClassInstanceExpression", + "typeReference": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "A", + "decorators": [], + "loc": { + "start": { + "line": 6, + "column": 9 + }, + "end": { + "line": 6, + "column": 10 + } + } + }, + "loc": { + "start": { + "line": 6, + "column": 9 + }, + "end": { + "line": 6, + "column": 11 + } + } + }, + "loc": { + "start": { + "line": 6, + "column": 9 + }, + "end": { + "line": 6, + "column": 11 + } + } + }, + "arguments": [], + "loc": { + "start": { + "line": 6, + "column": 5 + }, + "end": { + "line": 6, + "column": 13 + } + } + }, + "property": { + "type": "Identifier", + "name": "x", + "decorators": [], + "loc": { + "start": { + "line": 6, + "column": 13 + }, + "end": { + "line": 6, + "column": 14 + } + } + }, + "computed": false, + "optional": false, + "loc": { + "start": { + "line": 6, + "column": 5 + }, + "end": { + "line": 6, + "column": 14 + } + } + }, + "arguments": [], + "optional": false, + "loc": { + "start": { + "line": 6, + "column": 5 + }, + "end": { + "line": 6, + "column": 16 + } + } + }, + "loc": { + "start": { + "line": 6, + "column": 5 + }, + "end": { + "line": 6, + "column": 17 + } + } + } + ], + "loc": { + "start": { + "line": 5, + "column": 23 + }, + "end": { + "line": 7, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 5, + "column": 14 + }, + "end": { + "line": 7, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 5, + "column": 14 + }, + "end": { + "line": 7, + "column": 2 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 5, + "column": 1 + }, + "end": { + "line": 7, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 8, + "column": 1 + } + } +} +TypeError: This expression is not callable. [accessor_call.ets:6:5] diff --git a/test/parser/ets/accessor_call.ets b/test/parser/ets/accessor_call.ets new file mode 100644 index 0000000000000000000000000000000000000000..f4244c1995737353ba338dba5a3ea0ea7b07ab78 --- /dev/null +++ b/test/parser/ets/accessor_call.ets @@ -0,0 +1,7 @@ +class A { + get x(): int { return 1 } +} + +function main(): void { + new A().x(); +} diff --git a/test/parser/ets/accessor_void-expected.txt b/test/parser/ets/accessor_void-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..352eda660979f4f0e8e77ca12a6be7f7fa363af5 --- /dev/null +++ b/test/parser/ets/accessor_void-expected.txt @@ -0,0 +1,426 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "A", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 8 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "x", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "get", + "accessibility": "public", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "x", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "returnType": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "void", + "decorators": [], + "loc": { + "start": { + "line": 2, + "column": 14 + }, + "end": { + "line": 2, + "column": 18 + } + } + }, + "loc": { + "start": { + "line": 2, + "column": 14 + }, + "end": { + "line": 2, + "column": 20 + } + } + }, + "loc": { + "start": { + "line": 2, + "column": 14 + }, + "end": { + "line": 2, + "column": 20 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 2, + "column": 19 + }, + "end": { + "line": 2, + "column": 22 + } + } + }, + "loc": { + "start": { + "line": 2, + "column": 10 + }, + "end": { + "line": 2, + "column": 22 + } + } + }, + "loc": { + "start": { + "line": 2, + "column": 10 + }, + "end": { + "line": 2, + "column": 22 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 2, + "column": 10 + }, + "end": { + "line": 2, + "column": 22 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "constructor", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "constructor", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "constructor", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 3, + "column": 2 + }, + "end": { + "line": 3, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 9 + }, + "end": { + "line": 3, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 3, + "column": 2 + } + } + }, + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "ETSGLOBAL", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 4, + "column": 1 + } + } +} +TypeError: Getter must return a value [accessor_void.ets:2:10] diff --git a/test/parser/ets/accessor_void.ets b/test/parser/ets/accessor_void.ets new file mode 100644 index 0000000000000000000000000000000000000000..df6401ffa2c1e89d011d23866674b141c6bb5b17 --- /dev/null +++ b/test/parser/ets/accessor_void.ets @@ -0,0 +1,3 @@ +class A { + get x(): void { } +} diff --git a/test/parser/ets/getter_setter_modifier_diff-expected.txt b/test/parser/ets/getter_setter_modifier_diff-expected.txt index ef3d201d799136f856a33fcb02f634583f4e8b7a..b8d55aae4671b464d792152b3fd3454902fd499e 100644 --- a/test/parser/ets/getter_setter_modifier_diff-expected.txt +++ b/test/parser/ets/getter_setter_modifier_diff-expected.txt @@ -6,7 +6,7 @@ "definition": { "id": { "type": "Identifier", - "name": "Book", + "name": "A", "decorators": [], "loc": { "start": { @@ -15,67 +15,18 @@ }, "end": { "line": 16, - "column": 11 + "column": 8 } } }, "superClass": null, "implements": [], "body": [ - { - "type": "ClassProperty", - "key": { - "type": "Identifier", - "name": "_pages", - "decorators": [], - "loc": { - "start": { - "line": 17, - "column": 13 - }, - "end": { - "line": 17, - "column": 19 - } - } - }, - "accessibility": "private", - "static": false, - "readonly": false, - "declare": false, - "optional": false, - "computed": false, - "typeAnnotation": { - "type": "ETSPrimitiveType", - "loc": { - "start": { - "line": 17, - "column": 21 - }, - "end": { - "line": 17, - "column": 24 - } - } - }, - "definite": false, - "decorators": [], - "loc": { - "start": { - "line": 1, - "column": 1 - }, - "end": { - "line": 1, - "column": 1 - } - } - }, { "type": "MethodDefinition", "key": { "type": "Identifier", - "name": "pages", + "name": "foo", "decorators": [], "loc": { "start": { @@ -99,7 +50,7 @@ "type": "ScriptFunction", "id": { "type": "Identifier", - "name": "pages", + "name": "foo", "decorators": [], "loc": { "start": { @@ -125,244 +76,81 @@ "type": "ETSPrimitiveType", "loc": { "start": { - "line": 19, - "column": 18 + "line": 17, + "column": 16 }, "end": { - "line": 19, - "column": 21 + "line": 17, + "column": 19 } } }, "decorators": [], "loc": { "start": { - "line": 19, - "column": 15 + "line": 17, + "column": 13 }, "end": { - "line": 19, - "column": 21 + "line": 17, + "column": 19 } } }, "loc": { "start": { - "line": 19, - "column": 15 + "line": 17, + "column": 13 }, "end": { - "line": 19, - "column": 21 + "line": 17, + "column": 19 } } } ], - "returnType": { - "type": "ETSTypeReference", - "part": { - "type": "ETSTypeReferencePart", - "name": { - "type": "Identifier", - "name": "void", - "decorators": [], - "loc": { - "start": { - "line": 19, - "column": 24 - }, - "end": { - "line": 19, - "column": 28 - } - } - }, - "loc": { - "start": { - "line": 19, - "column": 24 - }, - "end": { - "line": 19, - "column": 30 - } - } - }, - "loc": { - "start": { - "line": 19, - "column": 24 - }, - "end": { - "line": 19, - "column": 30 - } - } - }, "body": { "type": "BlockStatement", - "statements": [ - { - "type": "ExpressionStatement", - "expression": { - "type": "AssignmentExpression", - "operator": "=", - "left": { - "type": "MemberExpression", - "object": { - "type": "ThisExpression", - "loc": { - "start": { - "line": 20, - "column": 9 - }, - "end": { - "line": 20, - "column": 13 - } - } - }, - "property": { - "type": "Identifier", - "name": "_pages", - "decorators": [], - "loc": { - "start": { - "line": 20, - "column": 14 - }, - "end": { - "line": 20, - "column": 20 - } - } - }, - "computed": false, - "optional": false, - "loc": { - "start": { - "line": 20, - "column": 9 - }, - "end": { - "line": 20, - "column": 20 - } - } - }, - "right": { - "type": "Identifier", - "name": "p", - "decorators": [], - "loc": { - "start": { - "line": 20, - "column": 23 - }, - "end": { - "line": 20, - "column": 24 - } - } - }, - "loc": { - "start": { - "line": 20, - "column": 9 - }, - "end": { - "line": 20, - "column": 24 - } - } - }, - "loc": { - "start": { - "line": 20, - "column": 9 - }, - "end": { - "line": 20, - "column": 25 - } - } - } - ], + "statements": [], "loc": { "start": { - "line": 19, - "column": 29 + "line": 17, + "column": 21 }, "end": { - "line": 21, - "column": 6 + "line": 17, + "column": 23 } } }, "loc": { "start": { - "line": 19, - "column": 14 + "line": 17, + "column": 12 }, "end": { - "line": 21, - "column": 6 + "line": 17, + "column": 23 } } }, "loc": { "start": { - "line": 19, - "column": 14 - }, - "end": { - "line": 21, - "column": 6 - } - } - }, - "overloads": [], - "decorators": [], - "loc": { - "start": { - "line": 19, - "column": 14 - }, - "end": { - "line": 21, - "column": 6 - } - } - }, - { - "type": "MethodDefinition", - "key": { - "type": "Identifier", - "name": "pages", - "decorators": [], - "loc": { - "start": { - "line": 1, - "column": 1 + "line": 17, + "column": 12 }, "end": { - "line": 1, - "column": 1 + "line": 17, + "column": 23 } } }, - "kind": "get", - "accessibility": "public", - "static": true, - "optional": false, - "computed": false, - "value": { - "type": "FunctionExpression", - "function": { - "type": "ScriptFunction", - "id": { + "overloads": [ + { + "type": "MethodDefinition", + "key": { "type": "Identifier", - "name": "pages", + "name": "foo", "decorators": [], "loc": { "start": { @@ -375,97 +163,106 @@ } } }, - "generator": false, - "async": false, - "expression": false, - "params": [], - "returnType": { - "type": "ETSPrimitiveType", - "loc": { - "start": { - "line": 23, - "column": 25 + "kind": "get", + "accessibility": "public", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } }, - "end": { - "line": 23, - "column": 28 - } - } - }, - "body": { - "type": "BlockStatement", - "statements": [ - { - "type": "ReturnStatement", - "argument": { - "type": "NumberLiteral", - "value": 300, - "loc": { - "start": { - "line": 24, - "column": 16 - }, - "end": { - "line": 24, - "column": 19 - } + "generator": false, + "async": false, + "expression": false, + "params": [], + "returnType": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 18, + "column": 22 + }, + "end": { + "line": 18, + "column": 25 } - }, + } + }, + "body": { + "type": "BlockStatement", + "statements": [], "loc": { "start": { - "line": 24, - "column": 9 + "line": 18, + "column": 26 }, "end": { - "line": 24, - "column": 20 + "line": 18, + "column": 28 } } + }, + "loc": { + "start": { + "line": 18, + "column": 18 + }, + "end": { + "line": 18, + "column": 28 + } } - ], + }, "loc": { "start": { - "line": 23, - "column": 29 + "line": 18, + "column": 18 }, "end": { - "line": 25, - "column": 6 + "line": 18, + "column": 28 } } }, + "overloads": [], + "decorators": [], "loc": { "start": { - "line": 23, - "column": 21 + "line": 18, + "column": 18 }, "end": { - "line": 25, - "column": 6 + "line": 18, + "column": 28 } } - }, - "loc": { - "start": { - "line": 23, - "column": 21 - }, - "end": { - "line": 25, - "column": 6 - } } - }, - "overloads": [], + ], "decorators": [], "loc": { "start": { - "line": 23, - "column": 21 + "line": 17, + "column": 12 }, "end": { - "line": 25, - "column": 6 + "line": 17, + "column": 23 } } }, @@ -553,11 +350,11 @@ "decorators": [], "loc": { "start": { - "line": 26, + "line": 19, "column": 2 }, "end": { - "line": 26, + "line": 19, "column": 2 } } @@ -566,10 +363,10 @@ "loc": { "start": { "line": 16, - "column": 12 + "column": 9 }, "end": { - "line": 26, + "line": 19, "column": 2 } } @@ -580,7 +377,7 @@ "column": 1 }, "end": { - "line": 26, + "line": 19, "column": 2 } } @@ -730,9 +527,9 @@ "column": 1 }, "end": { - "line": 27, + "line": 20, "column": 1 } } } -TypeError: Getter and setter methods must have the same accessor modifiers [getter_setter_modifier_diff.ets:19:14] +TypeError: Getter and setter methods must have the same accessor modifiers [getter_setter_modifier_diff.ets:18:18] diff --git a/test/parser/ets/getter_setter_modifier_diff.ets b/test/parser/ets/getter_setter_modifier_diff.ets index ff9e0b034ad84f7e1016eec2de1cf69ad210e139..3e14c4a17e9aba4f4b9522d9246027e673a843a9 100644 --- a/test/parser/ets/getter_setter_modifier_diff.ets +++ b/test/parser/ets/getter_setter_modifier_diff.ets @@ -13,14 +13,7 @@ * limitations under the License. */ -class Book { - private _pages: int; - - set pages(p: int): void { - this._pages = p; - } - - static get pages(): int { - return 300; - } +class A { + set foo(p: int) {} + final get foo(): int {} } diff --git a/test/runtime/ets/accessor_chained.ets b/test/runtime/ets/accessor_chained.ets new file mode 100644 index 0000000000000000000000000000000000000000..35b863df1ad8b7762884735577100fabc312d564 --- /dev/null +++ b/test/runtime/ets/accessor_chained.ets @@ -0,0 +1,17 @@ +class A { + static xstate: int = 0; + + get x(): int { return A.xstate } // bug: can't remove return annotation + set x(v: int) { A.xstate = v } +} + +class B { + get y() : A { return new A() } +} + +function main(): void { + let b = new B(); + b.y.x = 123; + assert A.xstate == 123; + assert b.y.x == 123; +} diff --git a/test/runtime/ets/accessor_functional.ets b/test/runtime/ets/accessor_functional.ets new file mode 100644 index 0000000000000000000000000000000000000000..a2ece63e9ba3b0b0d4df5f528f4ef00fddc589dd --- /dev/null +++ b/test/runtime/ets/accessor_functional.ets @@ -0,0 +1,13 @@ +class A { + xstate: () => int; + + get x(): () => int { return this.xstate; } + set x(v: () => int) { this.xstate = v } +} + +function main() { + let a = new A(); + a.x = () => { return 123 }; // bug: no short form for return + assert a.xstate() == 123; + assert a.x() == 123; +} diff --git a/test/runtime/ets/accessor_inherited.ets b/test/runtime/ets/accessor_inherited.ets new file mode 100644 index 0000000000000000000000000000000000000000..27e6a6ebe71074e40fad756e3bfe2338018e015a --- /dev/null +++ b/test/runtime/ets/accessor_inherited.ets @@ -0,0 +1,15 @@ +class A { + xstate: int = 0; + + get x(): int { return this.xstate } + set x(v: int) { this.xstate = v } +} + +class B extends A { } + +function main() { + let b = new B(); + b.x = 123; + assert b.xstate == 123; + assert b.x == 123; +} diff --git a/util/enumbitops.h b/util/enumbitops.h index 0bbb861f5f1ad6fa2f2dc8f8904bf852b7ce9ca8..d64b5fe2d13b231b4777ce717d5918037b3117cb 100644 --- a/util/enumbitops.h +++ b/util/enumbitops.h @@ -20,55 +20,55 @@ // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define DEFINE_BITOPS(T) \ - inline T operator~(T a) \ + inline constexpr T operator~(T a) \ { \ using utype = std::underlying_type_t; \ /* NOLINTNEXTLINE(hicpp-signed-bitwise) */ \ return static_cast(~static_cast(a)); \ } \ \ - inline bool operator!(T a) \ + inline constexpr bool operator!(T a) \ { \ using utype = std::underlying_type_t; \ /* NOLINTNEXTLINE(hicpp-signed-bitwise) */ \ return (!static_cast(a)); \ } \ \ - inline T operator|(T a, T b) \ + inline constexpr T operator|(T a, T b) \ { \ using utype = std::underlying_type_t; \ /* NOLINTNEXTLINE(hicpp-signed-bitwise) */ \ return static_cast(static_cast(a) | static_cast(b)); \ } \ \ - inline std::underlying_type_t operator&(T a, T b) \ + inline constexpr std::underlying_type_t operator&(T a, T b) \ { \ using utype = std::underlying_type_t; \ /* NOLINTNEXTLINE(hicpp-signed-bitwise) */ \ return static_cast(static_cast(a) & static_cast(b)); \ } \ \ - inline T operator^(T a, T b) \ + inline constexpr T operator^(T a, T b) \ { \ using utype = std::underlying_type_t; \ /* NOLINTNEXTLINE(hicpp-signed-bitwise) */ \ return static_cast(static_cast(a) ^ static_cast(b)); \ } \ \ - inline T &operator|=(T &a, T b) \ + inline constexpr T &operator|=(T &a, T b) \ { \ /* NOLINTNEXTLINE(hicpp-signed-bitwise) */ \ return a = a | b; \ } \ \ - inline T &operator&=(T &a, T b) \ + inline constexpr T &operator&=(T &a, T b) \ { \ using utype = std::underlying_type_t; \ /* NOLINTNEXTLINE(hicpp-signed-bitwise) */ \ return a = static_cast(static_cast(a) & static_cast(b)); \ } \ \ - inline T &operator^=(T &a, T b) \ + inline constexpr T &operator^=(T &a, T b) \ { \ /* NOLINTNEXTLINE(hicpp-signed-bitwise) */ \ return a = a ^ b; \