diff --git a/ets2panda/compiler/lowering/ets/lambdaLowering.cpp b/ets2panda/compiler/lowering/ets/lambdaLowering.cpp index 6eb673295e6eed1d41d329a7cb53d40bc6763d9b..a4c293ae852039172b4747be2c2dfe3b2b2cdde5 100644 --- a/ets2panda/compiler/lowering/ets/lambdaLowering.cpp +++ b/ets2panda/compiler/lowering/ets/lambdaLowering.cpp @@ -700,7 +700,8 @@ static checker::Signature *GuessSignature(checker::ETSChecker *checker, ir::Expr } if (!ast->Parent()->IsCallExpression()) { - checker->ThrowTypeError({"Cannot deduce call signature"}, ast->Start()); + checker->ThrowTypeError( + std::initializer_list {"Cannot deduce call signature"}, ast->Start()); } auto &args = ast->Parent()->AsCallExpression()->Arguments(); @@ -721,7 +722,9 @@ static checker::Signature *GuessSignature(checker::ETSChecker *checker, ir::Expr } if (sigFound != nullptr) { // ambiguiuty - checker->ThrowTypeError({"Cannot deduce call signature"}, ast->Start()); + checker->ThrowTypeError( + std::initializer_list {"Cannot deduce call signature"}, + ast->Start()); } sigFound = sig; } diff --git a/ets2panda/compiler/lowering/ets/objectIndexAccess.cpp b/ets2panda/compiler/lowering/ets/objectIndexAccess.cpp index efd5350a965419003a18c51e6fc51ea7ed60a08e..3299612930a221e2329b9cb526d9158c70956b0a 100644 --- a/ets2panda/compiler/lowering/ets/objectIndexAccess.cpp +++ b/ets2panda/compiler/lowering/ets/objectIndexAccess.cpp @@ -112,14 +112,21 @@ bool ObjectIndexLowering::Perform(public_lib::Context *ctx, parser::Program *pro bool ObjectIndexLowering::Postcondition(public_lib::Context *ctx, const parser::Program *program) { + auto checkExternalPrograms = [this, ctx](const ArenaVector &programs) { + for (auto *p : programs) { + if (!Postcondition(ctx, p)) { + return false; + } + } + return true; + }; + if (ctx->config->options->CompilerOptions().compilationMode == CompilationMode::GEN_STD_LIB) { for (auto &[_, extPrograms] : program->ExternalSources()) { (void)_; - for (auto *extProg : extPrograms) { - if (!Postcondition(ctx, extProg)) { - return false; - } - } + if (!checkExternalPrograms(extPrograms)) { + return false; + }; } } diff --git a/ets2panda/compiler/lowering/ets/opAssignment.cpp b/ets2panda/compiler/lowering/ets/opAssignment.cpp index b00c314f8ed454cf507019d96e556edbcc95ba64..1e45a1cd3d9b502e046d06be8b05aa9ddd27c854 100644 --- a/ets2panda/compiler/lowering/ets/opAssignment.cpp +++ b/ets2panda/compiler/lowering/ets/opAssignment.cpp @@ -342,14 +342,21 @@ bool OpAssignmentLowering::Perform(public_lib::Context *ctx, parser::Program *pr bool OpAssignmentLowering::Postcondition(public_lib::Context *ctx, const parser::Program *program) { + auto checkExternalPrograms = [this, ctx](const ArenaVector &programs) { + for (auto *p : programs) { + if (!Postcondition(ctx, p)) { + return false; + } + } + return true; + }; + if (ctx->config->options->CompilerOptions().compilationMode == CompilationMode::GEN_STD_LIB) { - for (auto &[_, ext_programs] : program->ExternalSources()) { + for (auto &[_, extPrograms] : program->ExternalSources()) { (void)_; - for (auto *extProg : ext_programs) { - if (!Postcondition(ctx, extProg)) { - return false; - } - } + if (!checkExternalPrograms(extPrograms)) { + return false; + }; } } diff --git a/ets2panda/compiler/lowering/ets/tupleLowering.cpp b/ets2panda/compiler/lowering/ets/tupleLowering.cpp index ad0cf4cd1234ab643d05651af936cb4a9202a81e..984f66b1d5529b9bcf79d76b65016be27a6f1282 100644 --- a/ets2panda/compiler/lowering/ets/tupleLowering.cpp +++ b/ets2panda/compiler/lowering/ets/tupleLowering.cpp @@ -29,6 +29,135 @@ #include "ir/ts/tsAsExpression.h" namespace ark::es2panda::compiler { +class TupleUpdateConverter { +public: + TupleUpdateConverter(checker::ETSChecker *const checker, ir::UpdateExpression *const update) + : checker_(checker), update_(update) + { + } + + std::optional CheckUpdateArgument() + { + auto *const argument = update_->Argument(); + const bool isArgumentMemberExpression = argument->IsMemberExpression(); + auto *const argumentType = + isArgumentMemberExpression ? argument->AsMemberExpression()->Object()->TsType() : nullptr; + + if ((argumentType == nullptr) || (!argumentType->IsETSTupleType())) { + return std::nullopt; + } + return {argumentType}; + } + + checker::Type *SetArgumentType(checker::Type *const argumentType) + { + auto *const savedType = argument_->TsType(); + argument_->SetTsType(argumentType->AsETSTupleType()->ElementType()); + return savedType; + } + + void ComputeTypes(checker::Type *const argumentType) + { + tupleTypeAtIdx_ = argumentType->AsETSTupleType()->GetTypeAtIndex( + checker_->GetTupleElementAccessValue(argument_->AsMemberExpression()->Property()->TsType(), + argument_->AsMemberExpression()->Property()->Start())); + + tupleElementTypeNode_ = checker_->AllocNode(argumentType->AsETSTupleType()->ElementType()); + tupleTypeAtIdxNode_ = checker_->AllocNode(tupleTypeAtIdx_); + } + + ArenaVector GenerateExpressions() + { + // Clone argument of update expression (conversion flag might be added to it, so we need to duplicate it to not + // make + // conversions on 'line 3', that belongs to 'line 1' ) + auto [memberExpr, argumentClone] = CloneArgument(argument_); + // -------------- + + // Generate temporary symbols + auto [gensym, tmpVar] = GenerateSymbol(tupleTypeAtIdx_); + auto [gensym2, tmpVar2] = GenerateSymbol(tupleTypeAtIdx_); + // -------------- + // make node: let gensym = tuple[n] as ; + auto *const gensymTsAs = checker_->AllocNode(argumentClone, tupleTypeAtIdxNode_, false); + auto *const tupleAsType = checker_->AllocNode( + gensym, gensymTsAs, lexer::TokenType::PUNCTUATOR_SUBSTITUTION); + // -------------- + + // make node: let gensym2 = (gensym)++; + auto *identClone = gensym->Clone(checker_->Allocator(), nullptr); + identClone->SetTsType(tmpVar->TsType()); + auto *gensymUpdate = + checker_->AllocNode(identClone, update_->OperatorType(), update_->IsPrefix()); + auto *const gensym2Assignment = checker_->AllocNode( + gensym2, gensymUpdate, lexer::TokenType::PUNCTUATOR_SUBSTITUTION); + // -------------- + + // make node: tuple[n] = (gensym as ) as ; + identClone = gensym->Clone(checker_->Allocator(), nullptr); + identClone->SetTsType(tmpVar->TsType()); + auto *gensymAs = checker_->AllocNode( + identClone, tupleTypeAtIdxNode_->Clone(checker_->Allocator(), nullptr), false); + auto *gensymAsTupleTypeAtIdx = checker_->AllocNode(gensymAs, tupleElementTypeNode_, false); + auto *const tupleAssignment = checker_->AllocNode( + argument_, gensymAsTupleTypeAtIdx, lexer::TokenType::PUNCTUATOR_SUBSTITUTION); + // -------------- + + // make node: gensym2 as ; + identClone = gensym2->Clone(checker_->Allocator(), nullptr); + identClone->SetTsType(tmpVar2->TsType()); + auto *const finalTupleNode = checker_->AllocNode( + identClone, tupleTypeAtIdxNode_->Clone(checker_->Allocator(), nullptr), false); + // -------------- + + // Construct sequence expression order + ArenaVector expressionList(checker_->Allocator()->Adapter()); + expressionList.push_back(tupleAsType); + expressionList.push_back(gensym2Assignment); + expressionList.push_back(tupleAssignment); + expressionList.push_back(finalTupleNode); + // -------------- + + return expressionList; + } + +private: + std::tuple GenerateSymbol(checker::Type *const type) const + { + auto *gensym = Gensym(checker_->Allocator()); + auto *const tmpVar = NearestScope(update_)->AddDecl( + checker_->Allocator(), gensym->Name(), varbinder::VariableFlags::LOCAL); + tmpVar->SetTsType(type); + gensym->SetVariable(tmpVar); + gensym->SetTsType(tmpVar->TsType()); + return std::make_tuple(gensym, tmpVar); + } + + std::tuple CloneArgument( + ir::Expression *const argument) const + { + auto *const memberExpr = argument->AsMemberExpression(); + auto *const argumentClone = memberExpr->Clone(checker_->Allocator(), memberExpr->Parent()); + argumentClone->Object()->SetTsType(memberExpr->Object()->TsType()); + if (argumentClone->Object()->IsIdentifier()) { + argumentClone->Object()->AsIdentifier()->SetVariable(memberExpr->Object()->AsIdentifier()->Variable()); + } + argumentClone->Property()->SetTsType(memberExpr->Property()->TsType()); + if (argumentClone->Property()->IsIdentifier()) { + argumentClone->Property()->AsIdentifier()->SetVariable(memberExpr->Property()->AsIdentifier()->Variable()); + } + argumentClone->SetTsType(memberExpr->TsType()); + return std::make_tuple(memberExpr, argumentClone); + }; + + checker::ETSChecker *const checker_; + ir::UpdateExpression *const update_; + ir::Expression *const argument_ {nullptr}; + checker::Type *tupleTypeAtIdx_ {nullptr}; + ir::OpaqueTypeNode *tupleElementTypeNode_ {nullptr}; + ir::OpaqueTypeNode *tupleTypeAtIdxNode_ {nullptr}; +}; + static ir::Expression *ConvertTupleUpdate(checker::ETSChecker *const checker, ir::UpdateExpression *const update) { // Converts `tuple[n]++` to @@ -49,111 +178,34 @@ static ir::Expression *ConvertTupleUpdate(checker::ETSChecker *const checker, ir // is already ), the boxing flag will be on the as expression, instead of the identifier, so // the identifier node won't be unboxed at 'line 2'. - // Check if argument of update expression is tuple - auto *const argument = update->Argument(); - const bool isArgumentMemberExpression = argument->IsMemberExpression(); - auto *const argumentType = - isArgumentMemberExpression ? argument->AsMemberExpression()->Object()->TsType() : nullptr; + auto converter = TupleUpdateConverter {checker, update}; - if ((argumentType == nullptr) || (!argumentType->IsETSTupleType())) { + // Check if argument of update expression is tuple + auto const argumentType = converter.CheckUpdateArgument(); + if (!argumentType) { return update; } // -------------- // Set tuple type to Object (because we'll need implicit boxing) - auto *const savedType = argument->TsType(); - argument->SetTsType(argumentType->AsETSTupleType()->ElementType()); + auto *const savedType = converter.SetArgumentType(*argumentType); // -------------- // Compute necessary types and OpaqueTypeNodes - auto *const tupleTypeAtIdx = argumentType->AsETSTupleType()->GetTypeAtIndex(checker->GetTupleElementAccessValue( - argument->AsMemberExpression()->Property()->TsType(), argument->AsMemberExpression()->Property()->Start())); - - auto *const tupleElementTypeNode = - checker->AllocNode(argumentType->AsETSTupleType()->ElementType()); - auto *const tupleTypeAtIdxNode = checker->AllocNode(tupleTypeAtIdx); - // -------------- - - // Clone argument of update expression (conversion flag might be added to it, so we need to duplicate it to not make - // conversions on 'line 3', that belongs to 'line 1' ) - auto *const memberExpr = argument->AsMemberExpression(); - auto *const argumentClone = memberExpr->Clone(checker->Allocator(), memberExpr->Parent()); - argumentClone->Object()->SetTsType(memberExpr->Object()->TsType()); - if (argumentClone->Object()->IsIdentifier()) { - argumentClone->Object()->AsIdentifier()->SetVariable(memberExpr->Object()->AsIdentifier()->Variable()); - } - argumentClone->Property()->SetTsType(memberExpr->Property()->TsType()); - if (argumentClone->Property()->IsIdentifier()) { - argumentClone->Property()->AsIdentifier()->SetVariable(memberExpr->Property()->AsIdentifier()->Variable()); - } - argumentClone->SetTsType(memberExpr->TsType()); - // -------------- - - // Generate temporary symbols - auto *gensym = Gensym(checker->Allocator()); - auto *const tmpVar = NearestScope(update)->AddDecl( - checker->Allocator(), gensym->Name(), varbinder::VariableFlags::LOCAL); - tmpVar->SetTsType(tupleTypeAtIdx); - gensym->SetVariable(tmpVar); - gensym->SetTsType(tmpVar->TsType()); - - auto *gensym2 = Gensym(checker->Allocator()); - auto *const tmpVar2 = NearestScope(update)->AddDecl( - checker->Allocator(), gensym2->Name(), varbinder::VariableFlags::LOCAL); - tmpVar2->SetTsType(tupleTypeAtIdx); - gensym2->SetVariable(tmpVar2); - gensym2->SetTsType(tmpVar2->TsType()); + converter.ComputeTypes(*argumentType); // -------------- - // make node: let gensym = tuple[n] as ; - auto *const gensymTsAs = checker->AllocNode(argumentClone, tupleTypeAtIdxNode, false); - auto *const tupleAsType = - checker->AllocNode(gensym, gensymTsAs, lexer::TokenType::PUNCTUATOR_SUBSTITUTION); - // -------------- - - // make node: let gensym2 = (gensym)++; - auto *identClone = gensym->Clone(checker->Allocator(), nullptr); - identClone->SetTsType(tmpVar->TsType()); - auto *gensymUpdate = - checker->AllocNode(identClone, update->OperatorType(), update->IsPrefix()); - auto *const gensym2Assignment = - checker->AllocNode(gensym2, gensymUpdate, lexer::TokenType::PUNCTUATOR_SUBSTITUTION); - // -------------- - - // make node: tuple[n] = (gensym as ) as ; - identClone = gensym->Clone(checker->Allocator(), nullptr); - identClone->SetTsType(tmpVar->TsType()); - auto *gensymAs = checker->AllocNode( - identClone, tupleTypeAtIdxNode->Clone(checker->Allocator(), nullptr), false); - auto *gensymAsTupleTypeAtIdx = checker->AllocNode(gensymAs, tupleElementTypeNode, false); - auto *const tupleAssignment = checker->AllocNode( - argument, gensymAsTupleTypeAtIdx, lexer::TokenType::PUNCTUATOR_SUBSTITUTION); - // -------------- - - // make node: gensym2 as ; - identClone = gensym2->Clone(checker->Allocator(), nullptr); - identClone->SetTsType(tmpVar2->TsType()); - auto *const finalTupleNode = checker->AllocNode( - identClone, tupleTypeAtIdxNode->Clone(checker->Allocator(), nullptr), false); - // -------------- - - // Construct sequence expression order - ArenaVector expressionList(checker->Allocator()->Adapter()); - expressionList.push_back(tupleAsType); - expressionList.push_back(gensym2Assignment); - expressionList.push_back(tupleAssignment); - expressionList.push_back(finalTupleNode); - // -------------- + auto expressions = converter.GenerateExpressions(); // Check the new sequence expression - auto *const sequenceExpr = checker->AllocNode(std::move(expressionList)); + auto *const sequenceExpr = checker->AllocNode(std::move(expressions)); sequenceExpr->SetParent(update->Parent()); sequenceExpr->Check(checker); // -------------- // Set back TsType of argument (not necessarily needed now, but there can be a phase later, that need to get the // right type of it) - argument->SetTsType(savedType); + [[maybe_unused]] auto _ = converter.SetArgumentType(savedType); // -------------- return sequenceExpr;