diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 951f2217220594c4f069a014cf96b7d906716a2c..438beebcbf4243226146452730f7e08616ad8db6 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -2346,6 +2346,12 @@ void ETSAnalyzer::CheckObjectExprProps(const ir::ObjectExpression *expr, ETSChecker *checker = GetETSChecker(); checker::ETSObjectType *objType = objectTypeForProperties; + std::string requiredName = ""; + if (!CheckRequiredAttributeInit(expr, objectTypeForProperties, requiredName)) { + checker->LogError(diagnostic::MANDATORY_ATTRIBUTE_MISS, {requiredName}, expr->Start()); + return; + } + for (ir::Expression *propExpr : expr->Properties()) { if (!propExpr->IsProperty()) { checker->LogError(diagnostic::OBJECT_LITERAL_NOT_KV, {}, expr->Start()); @@ -2393,6 +2399,47 @@ void ETSAnalyzer::CheckObjectExprProps(const ir::ObjectExpression *expr, } } +bool ETSAnalyzer::CheckRequiredAttributeInit(const ir::ObjectExpression *expr, + checker::ETSObjectType *objectTypeForProperties, + std::string &requiredName) const +{ + if (expr->Properties().empty()) { + return true; + } + + ETSChecker *checker = GetETSChecker(); + checker::ETSObjectType *objType = objectTypeForProperties; + + auto allProperties = objType->GetAllProperties(); + std::unordered_set literalProperties; + + for (ir::Expression *propExpr : expr->Properties()) { + if (propExpr->IsProperty()) { + ir::Expression *key = propExpr->AsProperty()->Key(); + if (auto optPname = GetPropertyNameFromKey(key); optPname.has_value()) { + literalProperties.insert(std::string(optPname.value().Utf8())); + } + } + } + + for (auto *property : allProperties) { + if (!checker->GetTypeOfVariable(property)->IsETSMethodType()) { + std::string propName(property->Name().Utf8()); + auto *propertyType = checker->GetTypeOfVariable(property); + bool isInLiteral = literalProperties.find(propName) != literalProperties.end(); + if (!isInLiteral) { + bool isOptional = IsPropertyOptional(property, propertyType); + bool hasDefaultValue = HasPropertyDefaultValue(property); + if (!isOptional && !hasDefaultValue) { + requiredName = propName; + return false; // 必需属性未提供且无默认值 + } + } + } + } + return true; +} + checker::Type *ETSAnalyzer::Check(ir::OpaqueTypeNode *expr) const { return expr->TsType(); diff --git a/ets2panda/checker/ETSAnalyzer.h b/ets2panda/checker/ETSAnalyzer.h index c4a0d46ba6757eddae4f3d5212c7247c3a787942..88d90ec898a0a5b584caf8fd7f89ec516e8b28d6 100644 --- a/ets2panda/checker/ETSAnalyzer.h +++ b/ets2panda/checker/ETSAnalyzer.h @@ -83,6 +83,10 @@ private: checker->LogError(diagnostic::VOID_VALUE, {}, expr->Start()); } } + + bool CheckRequiredAttributeInit(const ir::ObjectExpression *expr, + checker::ETSObjectType *objectTypeForProperties, std::string &requiredName) const; + mutable std::vector catchParamStack_ {}; }; diff --git a/ets2panda/test/ast/compiler/ets/required_attribute_init/required_attribute_init.ets b/ets2panda/test/ast/compiler/ets/required_attribute_init/required_attribute_init.ets new file mode 100644 index 0000000000000000000000000000000000000000..bdddf2579cd1e0f79427b2e9056d9a50658a0f1c --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/required_attribute_init/required_attribute_init.ets @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +interface Person { + age :number; + sex?:string; +} + +let a:Person = {sex:"男"} as Person + +function main () +{ + console.log(a.sex); +} diff --git a/ets2panda/test/runtime/ets/objectLiteral-2.ets b/ets2panda/test/runtime/ets/objectLiteral-2.ets index f11bc578c6cd6657f86368884a757cebf87df46b..4ecb173c69a24a9b79b6c9a21f048471aeec358f 100644 --- a/ets2panda/test/runtime/ets/objectLiteral-2.ets +++ b/ets2panda/test/runtime/ets/objectLiteral-2.ets @@ -54,7 +54,7 @@ function main(): int { test(c, 5, 6) test({ // function argument - x: 3, + x: 3, iv: {v: 0} }, 3, 0) test(returnC(), 99, 77) diff --git a/ets2panda/util/diagnostic/semantic.yaml b/ets2panda/util/diagnostic/semantic.yaml index 4c4ae2e28ecd4f21ea96d41b0697c01a66857615..35164d73c850da1e285773763f7be1915119a895 100644 --- a/ets2panda/util/diagnostic/semantic.yaml +++ b/ets2panda/util/diagnostic/semantic.yaml @@ -1514,3 +1514,7 @@ semantic: - name: DYMANIC_INIT_WITH_OBJEXPR id: 382 message: "Dymanic Type {} cannot be initialize with an object expression" + +- name: MANDATORY_ATTRIBUTE_MISS + id: 383 + message: "The name '{}' attribute is mandatory, lacks explicit initialization, and has no default value."